diff --git a/reading-platform-frontend/.env.development b/reading-platform-frontend/.env.development index 41071c4..dbca012 100644 --- a/reading-platform-frontend/.env.development +++ b/reading-platform-frontend/.env.development @@ -1,3 +1,3 @@ -VITE_API_BASE_URL=http://localhost:3000/api/v1 +VITE_API_BASE_URL= VITE_APP_TITLE=幼儿阅读教学服务平台 -VITE_SERVER_BASE_URL=http://localhost:3000 +VITE_SERVER_BASE_URL= diff --git a/reading-platform-frontend/src/api/generated/model/courseResponse.ts b/reading-platform-frontend/src/api/generated/model/courseResponse.ts index 58f98c8..592a81d 100644 --- a/reading-platform-frontend/src/api/generated/model/courseResponse.ts +++ b/reading-platform-frontend/src/api/generated/model/courseResponse.ts @@ -5,6 +5,7 @@ * Reading Platform Backend Service API Documentation * OpenAPI spec version: 1.0.0 */ +import type { CourseLessonResponse } from './courseLessonResponse'; /** * 课程响应 @@ -126,4 +127,6 @@ export interface CourseResponse { createdAt?: string; /** 更新时间 */ updatedAt?: string; + /** 关联的课程环节 */ + courseLessons?: CourseLessonResponse[]; } diff --git a/reading-platform-frontend/src/api/generated/model/index.ts b/reading-platform-frontend/src/api/generated/model/index.ts index b9cd3aa..1c444c9 100644 --- a/reading-platform-frontend/src/api/generated/model/index.ts +++ b/reading-platform-frontend/src/api/generated/model/index.ts @@ -29,8 +29,11 @@ export * from './courseControllerGetReviewListParams'; export * from './courseCreateRequest'; export * from './courseLesson'; export * from './courseLessonCreateRequest'; +export * from './courseLessonResponse'; export * from './coursePackage'; export * from './coursePackageControllerFindAllParams'; +export * from './coursePackageCourseItem'; +export * from './coursePackageResponse'; export * from './courseResponse'; export * from './courseUpdateRequest'; export * from './createClassDto'; @@ -144,6 +147,7 @@ export * from './pageResourceLibrary'; export * from './pageResultClassResponse'; export * from './pageResultClazz'; export * from './pageResultCourse'; +export * from './pageResultCoursePackageResponse'; export * from './pageResultCourseResponse'; export * from './pageResultGrowthRecord'; export * from './pageResultGrowthRecordResponse'; @@ -153,6 +157,8 @@ export * from './pageResultNotification'; export * from './pageResultNotificationResponse'; export * from './pageResultParent'; export * from './pageResultParentResponse'; +export * from './pageResultResourceItem'; +export * from './pageResultResourceLibrary'; export * from './pageResultStudent'; export * from './pageResultStudentResponse'; export * from './pageResultTask'; @@ -178,6 +184,7 @@ export * from './resultClazz'; export * from './resultCourse'; export * from './resultCourseLesson'; export * from './resultCoursePackage'; +export * from './resultCoursePackageResponse'; export * from './resultCourseResponse'; export * from './resultDto'; export * from './resultDtoData'; @@ -191,6 +198,7 @@ export * from './resultListClassTeacherResponse'; export * from './resultListClazz'; export * from './resultListCourse'; export * from './resultListCourseLesson'; +export * from './resultListCoursePackageResponse'; export * from './resultListCourseResponse'; export * from './resultListGrowthRecord'; export * from './resultListGrowthRecordResponse'; @@ -219,6 +227,7 @@ export * from './resultPageResourceLibrary'; export * from './resultPageResultClassResponse'; export * from './resultPageResultClazz'; export * from './resultPageResultCourse'; +export * from './resultPageResultCoursePackageResponse'; export * from './resultPageResultCourseResponse'; export * from './resultPageResultGrowthRecord'; export * from './resultPageResultGrowthRecordResponse'; @@ -228,6 +237,8 @@ export * from './resultPageResultNotification'; export * from './resultPageResultNotificationResponse'; export * from './resultPageResultParent'; export * from './resultPageResultParentResponse'; +export * from './resultPageResultResourceItem'; +export * from './resultPageResultResourceLibrary'; export * from './resultPageResultStudent'; export * from './resultPageResultStudentResponse'; export * from './resultPageResultTask'; diff --git a/reading-platform-frontend/src/api/generated/model/itemCreateRequest.ts b/reading-platform-frontend/src/api/generated/model/itemCreateRequest.ts index f82243e..05e57c4 100644 --- a/reading-platform-frontend/src/api/generated/model/itemCreateRequest.ts +++ b/reading-platform-frontend/src/api/generated/model/itemCreateRequest.ts @@ -8,11 +8,11 @@ export interface ItemCreateRequest { libraryId?: string; - name?: string; - code?: string; - type?: string; + title?: string; + fileType?: string; + filePath?: string; + fileSize?: number; description?: string; - quantity?: number; - location?: string; + tags?: string; tenantId?: string; } diff --git a/reading-platform-frontend/src/api/generated/model/itemUpdateRequest.ts b/reading-platform-frontend/src/api/generated/model/itemUpdateRequest.ts index d38d81d..b769ff4 100644 --- a/reading-platform-frontend/src/api/generated/model/itemUpdateRequest.ts +++ b/reading-platform-frontend/src/api/generated/model/itemUpdateRequest.ts @@ -7,7 +7,7 @@ */ export interface ItemUpdateRequest { - name?: string; + title?: string; description?: string; - quantity?: number; + tags?: string; } diff --git a/reading-platform-frontend/src/api/generated/model/resourceItem.ts b/reading-platform-frontend/src/api/generated/model/resourceItem.ts index 2712870..a8b878d 100644 --- a/reading-platform-frontend/src/api/generated/model/resourceItem.ts +++ b/reading-platform-frontend/src/api/generated/model/resourceItem.ts @@ -24,19 +24,31 @@ export interface ResourceItem { libraryId?: string; /** 租户 ID */ tenantId?: string; - /** 资源类型 */ - type?: string; - /** 资源名称 */ - name?: string; - /** 资源编码 */ - code?: string; + /** 资源标题 */ + title?: 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; - /** 可用数量 */ + /** 可用数量(保留字段,兼容旧数据) */ availableQuantity?: number; - /** 存放位置 */ + /** 存放位置(保留字段,兼容旧数据) */ location?: string; /** 状态 */ status?: string; diff --git a/reading-platform-frontend/src/api/generated/model/resourceLibrary.ts b/reading-platform-frontend/src/api/generated/model/resourceLibrary.ts index 7ae8d03..492b5d3 100644 --- a/reading-platform-frontend/src/api/generated/model/resourceLibrary.ts +++ b/reading-platform-frontend/src/api/generated/model/resourceLibrary.ts @@ -26,6 +26,14 @@ export interface ResourceLibrary { name?: string; /** 资源库描述 */ description?: string; - /** 资源库类型 */ - type?: string; + /** 资源库类型 (PICTURE_BOOK/MATERIAL/TEMPLATE) */ + libraryType?: string; + /** 封面图片 URL */ + coverImage?: string; + /** 创建人 ID */ + createdBy?: number; + /** 状态 */ + status?: string; + /** 排序号 */ + sortOrder?: number; } diff --git a/reading-platform-frontend/src/api/generated/model/tenantCreateRequest.ts b/reading-platform-frontend/src/api/generated/model/tenantCreateRequest.ts index 8028f3d..ca8bdcb 100644 --- a/reading-platform-frontend/src/api/generated/model/tenantCreateRequest.ts +++ b/reading-platform-frontend/src/api/generated/model/tenantCreateRequest.ts @@ -12,7 +12,7 @@ export interface TenantCreateRequest { /** 租户名称 */ name: string; - /** 租户编码 */ + /** 租户编码/登录账号 */ code: string; /** 联系人 */ contactName?: string; @@ -24,10 +24,29 @@ export interface TenantCreateRequest { address?: string; /** Logo URL */ logoUrl?: string; - /** 过期时间 */ + /** 套餐类型 */ + packageType?: string; + /** 教师配额 */ + teacherQuota?: number; + /** 学生配额 */ + studentQuota?: number; + /** 开始日期 */ + startDate?: string; + /** 结束日期 */ + expireDate?: string; + /** + * 过期时间(兼容旧字段) + * @deprecated + */ expireAt?: string; - /** 最大学生数 */ + /** + * 最大学生数(兼容旧字段) + * @deprecated + */ maxStudents?: number; - /** 最大教师数 */ + /** + * 最大教师数(兼容旧字段) + * @deprecated + */ maxTeachers?: number; } diff --git a/reading-platform-frontend/src/api/generated/model/tenantResponse.ts b/reading-platform-frontend/src/api/generated/model/tenantResponse.ts index 8f5b065..b9179f9 100644 --- a/reading-platform-frontend/src/api/generated/model/tenantResponse.ts +++ b/reading-platform-frontend/src/api/generated/model/tenantResponse.ts @@ -14,7 +14,7 @@ export interface TenantResponse { id?: number; /** 租户名称 */ name?: string; - /** 租户编码 */ + /** 租户编码/登录账号 */ code?: string; /** 用户名 */ username?: string; @@ -36,6 +36,24 @@ export interface TenantResponse { maxStudents?: number; /** 最大教师数 */ maxTeachers?: number; + /** 套餐类型 */ + packageType?: string; + /** 教师配额 */ + teacherQuota?: number; + /** 学生配额 */ + studentQuota?: number; + /** 存储配额 */ + storageQuota?: number; + /** 已用存储 */ + storageUsed?: number; + /** 教师数量(已使用) */ + teacherCount?: number; + /** 学生数量(已使用) */ + studentCount?: number; + /** 开始日期 */ + startDate?: string; + /** 结束日期 */ + expireDate?: string; /** 创建时间 */ createdAt?: string; /** 更新时间 */ diff --git a/reading-platform-frontend/src/api/generated/model/tenantUpdateRequest.ts b/reading-platform-frontend/src/api/generated/model/tenantUpdateRequest.ts index 727466a..ca303f3 100644 --- a/reading-platform-frontend/src/api/generated/model/tenantUpdateRequest.ts +++ b/reading-platform-frontend/src/api/generated/model/tenantUpdateRequest.ts @@ -24,10 +24,29 @@ export interface TenantUpdateRequest { logoUrl?: string; /** 状态 */ status?: string; - /** 过期时间 */ + /** 套餐类型 */ + packageType?: string; + /** 教师配额 */ + teacherQuota?: number; + /** 学生配额 */ + studentQuota?: number; + /** 开始日期 */ + startDate?: string; + /** 结束日期 */ + expireDate?: string; + /** + * 过期时间(兼容旧字段) + * @deprecated + */ expireAt?: string; - /** 最大学生数 */ + /** + * 最大学生数(兼容旧字段) + * @deprecated + */ maxStudents?: number; - /** 最大教师数 */ + /** + * 最大教师数(兼容旧字段) + * @deprecated + */ maxTeachers?: number; } diff --git a/reading-platform-frontend/src/components.d.ts b/reading-platform-frontend/src/components.d.ts index 2ae7cd0..89333d6 100644 --- a/reading-platform-frontend/src/components.d.ts +++ b/reading-platform-frontend/src/components.d.ts @@ -13,12 +13,15 @@ declare module 'vue' { AButton: typeof import('ant-design-vue/es')['Button'] ACard: typeof import('ant-design-vue/es')['Card'] ACheckbox: typeof import('ant-design-vue/es')['Checkbox'] + ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup'] ACol: typeof import('ant-design-vue/es')['Col'] + ADivider: typeof import('ant-design-vue/es')['Divider'] ADropdown: typeof import('ant-design-vue/es')['Dropdown'] AEmpty: typeof import('ant-design-vue/es')['Empty'] AForm: typeof import('ant-design-vue/es')['Form'] AFormItem: typeof import('ant-design-vue/es')['FormItem'] AInput: typeof import('ant-design-vue/es')['Input'] + AInputNumber: typeof import('ant-design-vue/es')['InputNumber'] AInputPassword: typeof import('ant-design-vue/es')['InputPassword'] AInputSearch: typeof import('ant-design-vue/es')['InputSearch'] ALayout: typeof import('ant-design-vue/es')['Layout'] @@ -29,14 +32,25 @@ declare module 'vue' { AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider'] AMenuItem: typeof import('ant-design-vue/es')['MenuItem'] AModal: typeof import('ant-design-vue/es')['Modal'] + APageHeader: typeof import('ant-design-vue/es')['PageHeader'] APopconfirm: typeof import('ant-design-vue/es')['Popconfirm'] + AProgress: typeof import('ant-design-vue/es')['Progress'] ARow: typeof import('ant-design-vue/es')['Row'] ASelect: typeof import('ant-design-vue/es')['Select'] + ASelectOptGroup: typeof import('ant-design-vue/es')['SelectOptGroup'] ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] 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'] + ATabPane: typeof import('ant-design-vue/es')['TabPane'] + ATabs: typeof import('ant-design-vue/es')['Tabs'] ATag: typeof import('ant-design-vue/es')['Tag'] + ATextarea: typeof import('ant-design-vue/es')['Textarea'] ATooltip: typeof import('ant-design-vue/es')['Tooltip'] + AUpload: typeof import('ant-design-vue/es')['Upload'] FilePreviewModal: typeof import('./components/FilePreviewModal.vue')['default'] FileUploader: typeof import('./components/course/FileUploader.vue')['default'] LessonConfigPanel: typeof import('./components/course/LessonConfigPanel.vue')['default'] diff --git a/reading-platform-frontend/src/components/course/FileUploader.vue b/reading-platform-frontend/src/components/course/FileUploader.vue index 1fa2028..b2301e9 100644 --- a/reading-platform-frontend/src/components/course/FileUploader.vue +++ b/reading-platform-frontend/src/components/course/FileUploader.vue @@ -77,7 +77,7 @@ import { SwapOutlined, DeleteOutlined, } from '@ant-design/icons-vue'; -import { uploadFile } from '@/api/file'; +import { getOssToken, uploadToOss } from '@/api/file'; interface Props { filePath?: string; @@ -107,7 +107,7 @@ const buttonText = computed(() => { const typeMap: Record = { video: '上传视频', ppt: '上传课件', - pdf: '上传PDF', + pdf: '上传 PDF', image: '上传图片', audio: '上传音频', document: '上传文档', @@ -144,18 +144,18 @@ const acceptTypes = computed(() => { const previewUrl = computed(() => { if (!props.filePath) return ''; - // 如果已经是完整URL或以/uploads开头,直接返回 + // 如果已经是完整 URL 或以 /uploads 开头,直接返回 if (props.filePath.startsWith('http') || props.filePath.startsWith('/uploads')) { return props.filePath; } - // 如果路径已经包含uploads目录,不再添加前缀 + // 如果路径已经包含 uploads 目录,不再添加前缀 if (props.filePath.includes('/uploads/')) { return props.filePath; } return `/uploads/${props.filePath}`; }); -// 检查是否为PDF文件(用于ppt类型也支持PDF预览) +// 检查是否为 PDF 文件(用于 ppt 类型也支持 PDF 预览) const isPdfFile = computed(() => { if (props.fileType === 'ppt' && props.filePath) { return props.filePath.toLowerCase().endsWith('.pdf'); @@ -196,7 +196,7 @@ const beforeUpload = async (file: File) => { message.error('请上传 Word 文档'); return false; } - // PPT类型允许PPT和PDF + // PPT 类型允许 PPT 和 PDF if (props.fileType === 'ppt' && !file.type.includes('presentation') && !file.type.includes('powerpoint') && @@ -210,14 +210,23 @@ const beforeUpload = async (file: File) => { uploading.value = true; try { + // 1. 获取 OSS 直传 Token const uploadType = props.fileType === 'ppt' ? 'ppt' : props.fileType || 'other'; - const result = await uploadFile(file, uploadType); - emit('update:filePath', result.filePath); + const token = await getOssToken(file.name, uploadType); + + // 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('change', { filePath: result.filePath, fileName: file.name }); + emit('change', { filePath: fileUrl, fileName: file.name }); message.success('上传成功'); } catch (error: any) { - message.error('上传失败: ' + (error.response?.data?.message || error.message)); + message.error('上传失败:' + (error.response?.data?.message || error.message)); } finally { uploading.value = false; }