feat: 更新 FileUploader 组件和生成的 API 类型

- 更新 FileUploader.vue 组件
- 更新组件类型定义
- 更新 API 生成的类型定义

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
En 2026-03-16 18:15:34 +08:00
parent a1dcd529ef
commit e7348656ff
12 changed files with 151 additions and 38 deletions

View File

@ -1,3 +1,3 @@
VITE_API_BASE_URL=http://localhost:3000/api/v1 VITE_API_BASE_URL=
VITE_APP_TITLE=幼儿阅读教学服务平台 VITE_APP_TITLE=幼儿阅读教学服务平台
VITE_SERVER_BASE_URL=http://localhost:3000 VITE_SERVER_BASE_URL=

View File

@ -5,6 +5,7 @@
* Reading Platform Backend Service API Documentation * Reading Platform Backend Service API Documentation
* OpenAPI spec version: 1.0.0 * OpenAPI spec version: 1.0.0
*/ */
import type { CourseLessonResponse } from './courseLessonResponse';
/** /**
* *
@ -126,4 +127,6 @@ export interface CourseResponse {
createdAt?: string; createdAt?: string;
/** 更新时间 */ /** 更新时间 */
updatedAt?: string; updatedAt?: string;
/** 关联的课程环节 */
courseLessons?: CourseLessonResponse[];
} }

View File

@ -29,8 +29,11 @@ export * from './courseControllerGetReviewListParams';
export * from './courseCreateRequest'; export * from './courseCreateRequest';
export * from './courseLesson'; export * from './courseLesson';
export * from './courseLessonCreateRequest'; export * from './courseLessonCreateRequest';
export * from './courseLessonResponse';
export * from './coursePackage'; export * from './coursePackage';
export * from './coursePackageControllerFindAllParams'; export * from './coursePackageControllerFindAllParams';
export * from './coursePackageCourseItem';
export * from './coursePackageResponse';
export * from './courseResponse'; export * from './courseResponse';
export * from './courseUpdateRequest'; export * from './courseUpdateRequest';
export * from './createClassDto'; export * from './createClassDto';
@ -144,6 +147,7 @@ export * from './pageResourceLibrary';
export * from './pageResultClassResponse'; export * from './pageResultClassResponse';
export * from './pageResultClazz'; export * from './pageResultClazz';
export * from './pageResultCourse'; export * from './pageResultCourse';
export * from './pageResultCoursePackageResponse';
export * from './pageResultCourseResponse'; export * from './pageResultCourseResponse';
export * from './pageResultGrowthRecord'; export * from './pageResultGrowthRecord';
export * from './pageResultGrowthRecordResponse'; export * from './pageResultGrowthRecordResponse';
@ -153,6 +157,8 @@ export * from './pageResultNotification';
export * from './pageResultNotificationResponse'; export * from './pageResultNotificationResponse';
export * from './pageResultParent'; export * from './pageResultParent';
export * from './pageResultParentResponse'; export * from './pageResultParentResponse';
export * from './pageResultResourceItem';
export * from './pageResultResourceLibrary';
export * from './pageResultStudent'; export * from './pageResultStudent';
export * from './pageResultStudentResponse'; export * from './pageResultStudentResponse';
export * from './pageResultTask'; export * from './pageResultTask';
@ -178,6 +184,7 @@ export * from './resultClazz';
export * from './resultCourse'; export * from './resultCourse';
export * from './resultCourseLesson'; export * from './resultCourseLesson';
export * from './resultCoursePackage'; export * from './resultCoursePackage';
export * from './resultCoursePackageResponse';
export * from './resultCourseResponse'; export * from './resultCourseResponse';
export * from './resultDto'; export * from './resultDto';
export * from './resultDtoData'; export * from './resultDtoData';
@ -191,6 +198,7 @@ export * from './resultListClassTeacherResponse';
export * from './resultListClazz'; export * from './resultListClazz';
export * from './resultListCourse'; export * from './resultListCourse';
export * from './resultListCourseLesson'; export * from './resultListCourseLesson';
export * from './resultListCoursePackageResponse';
export * from './resultListCourseResponse'; export * from './resultListCourseResponse';
export * from './resultListGrowthRecord'; export * from './resultListGrowthRecord';
export * from './resultListGrowthRecordResponse'; export * from './resultListGrowthRecordResponse';
@ -219,6 +227,7 @@ export * from './resultPageResourceLibrary';
export * from './resultPageResultClassResponse'; export * from './resultPageResultClassResponse';
export * from './resultPageResultClazz'; export * from './resultPageResultClazz';
export * from './resultPageResultCourse'; export * from './resultPageResultCourse';
export * from './resultPageResultCoursePackageResponse';
export * from './resultPageResultCourseResponse'; export * from './resultPageResultCourseResponse';
export * from './resultPageResultGrowthRecord'; export * from './resultPageResultGrowthRecord';
export * from './resultPageResultGrowthRecordResponse'; export * from './resultPageResultGrowthRecordResponse';
@ -228,6 +237,8 @@ export * from './resultPageResultNotification';
export * from './resultPageResultNotificationResponse'; export * from './resultPageResultNotificationResponse';
export * from './resultPageResultParent'; export * from './resultPageResultParent';
export * from './resultPageResultParentResponse'; export * from './resultPageResultParentResponse';
export * from './resultPageResultResourceItem';
export * from './resultPageResultResourceLibrary';
export * from './resultPageResultStudent'; export * from './resultPageResultStudent';
export * from './resultPageResultStudentResponse'; export * from './resultPageResultStudentResponse';
export * from './resultPageResultTask'; export * from './resultPageResultTask';

View File

@ -8,11 +8,11 @@
export interface ItemCreateRequest { export interface ItemCreateRequest {
libraryId?: string; libraryId?: string;
name?: string; title?: string;
code?: string; fileType?: string;
type?: string; filePath?: string;
fileSize?: number;
description?: string; description?: string;
quantity?: number; tags?: string;
location?: string;
tenantId?: string; tenantId?: string;
} }

View File

@ -7,7 +7,7 @@
*/ */
export interface ItemUpdateRequest { export interface ItemUpdateRequest {
name?: string; title?: string;
description?: string; description?: string;
quantity?: number; tags?: string;
} }

View File

@ -24,19 +24,31 @@ export interface ResourceItem {
libraryId?: string; libraryId?: string;
/** 租户 ID */ /** 租户 ID */
tenantId?: string; tenantId?: string;
/** 资源类型 */ /** 资源标题 */
type?: string; title?: string;
/** 资源名称 */
name?: string;
/** 资源编码 */
code?: string;
/** 资源描述 */ /** 资源描述 */
description?: string; description?: string;
/** 数量 */ /** 文件类型 (IMAGE/PDF/VIDEO/AUDIO/PPT/OTHER) */
fileType?: string;
/** 文件路径 */
filePath?: string;
/** 文件大小 (字节) */
fileSize?: number;
/** 资源标签 (JSON 数组) */
tags?: string;
/** 排序号 */
sortOrder?: number;
/** 资源类型(保留字段,兼容旧数据) */
type?: string;
/** 资源名称(保留字段,兼容旧数据) */
name?: string;
/** 资源编码(保留字段,兼容旧数据) */
code?: string;
/** 数量(保留字段,兼容旧数据) */
quantity?: number; quantity?: number;
/** 可用数量 */ /** 可用数量(保留字段,兼容旧数据) */
availableQuantity?: number; availableQuantity?: number;
/** 存放位置 */ /** 存放位置(保留字段,兼容旧数据) */
location?: string; location?: string;
/** 状态 */ /** 状态 */
status?: string; status?: string;

View File

@ -26,6 +26,14 @@ export interface ResourceLibrary {
name?: string; name?: string;
/** 资源库描述 */ /** 资源库描述 */
description?: string; description?: string;
/** 资源库类型 */ /** 资源库类型 (PICTURE_BOOK/MATERIAL/TEMPLATE) */
type?: string; libraryType?: string;
/** 封面图片 URL */
coverImage?: string;
/** 创建人 ID */
createdBy?: number;
/** 状态 */
status?: string;
/** 排序号 */
sortOrder?: number;
} }

View File

@ -12,7 +12,7 @@
export interface TenantCreateRequest { export interface TenantCreateRequest {
/** 租户名称 */ /** 租户名称 */
name: string; name: string;
/** 租户编码 */ /** 租户编码/登录账号 */
code: string; code: string;
/** 联系人 */ /** 联系人 */
contactName?: string; contactName?: string;
@ -24,10 +24,29 @@ export interface TenantCreateRequest {
address?: string; address?: string;
/** Logo URL */ /** Logo URL */
logoUrl?: string; logoUrl?: string;
/** 过期时间 */ /** 套餐类型 */
packageType?: string;
/** 教师配额 */
teacherQuota?: number;
/** 学生配额 */
studentQuota?: number;
/** 开始日期 */
startDate?: string;
/** 结束日期 */
expireDate?: string;
/**
*
* @deprecated
*/
expireAt?: string; expireAt?: string;
/** 最大学生数 */ /**
*
* @deprecated
*/
maxStudents?: number; maxStudents?: number;
/** 最大教师数 */ /**
*
* @deprecated
*/
maxTeachers?: number; maxTeachers?: number;
} }

View File

@ -14,7 +14,7 @@ export interface TenantResponse {
id?: number; id?: number;
/** 租户名称 */ /** 租户名称 */
name?: string; name?: string;
/** 租户编码 */ /** 租户编码/登录账号 */
code?: string; code?: string;
/** 用户名 */ /** 用户名 */
username?: string; username?: string;
@ -36,6 +36,24 @@ export interface TenantResponse {
maxStudents?: number; maxStudents?: number;
/** 最大教师数 */ /** 最大教师数 */
maxTeachers?: number; maxTeachers?: number;
/** 套餐类型 */
packageType?: string;
/** 教师配额 */
teacherQuota?: number;
/** 学生配额 */
studentQuota?: number;
/** 存储配额 */
storageQuota?: number;
/** 已用存储 */
storageUsed?: number;
/** 教师数量(已使用) */
teacherCount?: number;
/** 学生数量(已使用) */
studentCount?: number;
/** 开始日期 */
startDate?: string;
/** 结束日期 */
expireDate?: string;
/** 创建时间 */ /** 创建时间 */
createdAt?: string; createdAt?: string;
/** 更新时间 */ /** 更新时间 */

View File

@ -24,10 +24,29 @@ export interface TenantUpdateRequest {
logoUrl?: string; logoUrl?: string;
/** 状态 */ /** 状态 */
status?: string; status?: string;
/** 过期时间 */ /** 套餐类型 */
packageType?: string;
/** 教师配额 */
teacherQuota?: number;
/** 学生配额 */
studentQuota?: number;
/** 开始日期 */
startDate?: string;
/** 结束日期 */
expireDate?: string;
/**
*
* @deprecated
*/
expireAt?: string; expireAt?: string;
/** 最大学生数 */ /**
*
* @deprecated
*/
maxStudents?: number; maxStudents?: number;
/** 最大教师数 */ /**
*
* @deprecated
*/
maxTeachers?: number; maxTeachers?: number;
} }

View File

@ -13,12 +13,15 @@ declare module 'vue' {
AButton: typeof import('ant-design-vue/es')['Button'] AButton: typeof import('ant-design-vue/es')['Button']
ACard: typeof import('ant-design-vue/es')['Card'] ACard: typeof import('ant-design-vue/es')['Card']
ACheckbox: typeof import('ant-design-vue/es')['Checkbox'] ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
ACol: typeof import('ant-design-vue/es')['Col'] ACol: typeof import('ant-design-vue/es')['Col']
ADivider: typeof import('ant-design-vue/es')['Divider']
ADropdown: typeof import('ant-design-vue/es')['Dropdown'] ADropdown: typeof import('ant-design-vue/es')['Dropdown']
AEmpty: typeof import('ant-design-vue/es')['Empty'] AEmpty: typeof import('ant-design-vue/es')['Empty']
AForm: typeof import('ant-design-vue/es')['Form'] AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem'] AFormItem: typeof import('ant-design-vue/es')['FormItem']
AInput: typeof import('ant-design-vue/es')['Input'] AInput: typeof import('ant-design-vue/es')['Input']
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
AInputPassword: typeof import('ant-design-vue/es')['InputPassword'] AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
AInputSearch: typeof import('ant-design-vue/es')['InputSearch'] AInputSearch: typeof import('ant-design-vue/es')['InputSearch']
ALayout: typeof import('ant-design-vue/es')['Layout'] ALayout: typeof import('ant-design-vue/es')['Layout']
@ -29,14 +32,25 @@ declare module 'vue' {
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider'] AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
AMenuItem: typeof import('ant-design-vue/es')['MenuItem'] AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
AModal: typeof import('ant-design-vue/es')['Modal'] AModal: typeof import('ant-design-vue/es')['Modal']
APageHeader: typeof import('ant-design-vue/es')['PageHeader']
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm'] APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
AProgress: typeof import('ant-design-vue/es')['Progress']
ARow: typeof import('ant-design-vue/es')['Row'] ARow: typeof import('ant-design-vue/es')['Row']
ASelect: typeof import('ant-design-vue/es')['Select'] ASelect: typeof import('ant-design-vue/es')['Select']
ASelectOptGroup: typeof import('ant-design-vue/es')['SelectOptGroup']
ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
ASpace: typeof import('ant-design-vue/es')['Space'] ASpace: typeof import('ant-design-vue/es')['Space']
ASpin: typeof import('ant-design-vue/es')['Spin']
AStep: typeof import('ant-design-vue/es')['Step']
ASteps: typeof import('ant-design-vue/es')['Steps']
ASwitch: typeof import('ant-design-vue/es')['Switch']
ATable: typeof import('ant-design-vue/es')['Table'] ATable: typeof import('ant-design-vue/es')['Table']
ATabPane: typeof import('ant-design-vue/es')['TabPane']
ATabs: typeof import('ant-design-vue/es')['Tabs']
ATag: typeof import('ant-design-vue/es')['Tag'] ATag: typeof import('ant-design-vue/es')['Tag']
ATextarea: typeof import('ant-design-vue/es')['Textarea']
ATooltip: typeof import('ant-design-vue/es')['Tooltip'] ATooltip: typeof import('ant-design-vue/es')['Tooltip']
AUpload: typeof import('ant-design-vue/es')['Upload']
FilePreviewModal: typeof import('./components/FilePreviewModal.vue')['default'] FilePreviewModal: typeof import('./components/FilePreviewModal.vue')['default']
FileUploader: typeof import('./components/course/FileUploader.vue')['default'] FileUploader: typeof import('./components/course/FileUploader.vue')['default']
LessonConfigPanel: typeof import('./components/course/LessonConfigPanel.vue')['default'] LessonConfigPanel: typeof import('./components/course/LessonConfigPanel.vue')['default']

View File

@ -77,7 +77,7 @@ import {
SwapOutlined, SwapOutlined,
DeleteOutlined, DeleteOutlined,
} from '@ant-design/icons-vue'; } from '@ant-design/icons-vue';
import { uploadFile } from '@/api/file'; import { getOssToken, uploadToOss } from '@/api/file';
interface Props { interface Props {
filePath?: string; filePath?: string;
@ -210,14 +210,23 @@ const beforeUpload = async (file: File) => {
uploading.value = true; uploading.value = true;
try { try {
// 1. OSS Token
const uploadType = props.fileType === 'ppt' ? 'ppt' : props.fileType || 'other'; const uploadType = props.fileType === 'ppt' ? 'ppt' : props.fileType || 'other';
const result = await uploadFile(file, uploadType); const token = await getOssToken(file.name, uploadType);
emit('update:filePath', result.filePath);
// 2. OSS
await uploadToOss(file, token, (percent) => {
console.log(`Upload progress: ${percent}%`);
});
// 3. URL
const fileUrl = `${token.host}/${token.key}`;
emit('update:filePath', fileUrl);
emit('update:fileName', file.name); emit('update:fileName', file.name);
emit('change', { filePath: result.filePath, fileName: file.name }); emit('change', { filePath: fileUrl, fileName: file.name });
message.success('上传成功'); message.success('上传成功');
} catch (error: any) { } catch (error: any) {
message.error('上传失败: ' + (error.response?.data?.message || error.message)); message.error('上传失败' + (error.response?.data?.message || error.message));
} finally { } finally {
uploading.value = false; uploading.value = false;
} }