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_SERVER_BASE_URL=http://localhost:3000
VITE_SERVER_BASE_URL=

View File

@ -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[];
}

View File

@ -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';

View File

@ -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;
}

View File

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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
/** 更新时间 */

View File

@ -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;
}

View File

@ -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']

View File

@ -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<string, string> = {
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}`;
});
// PDFpptPDF
// 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;
}
// PPTPPTPDF
// 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;
}