From f4a5f6f78252c83a85fa3bda5574babb0ccf7c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=BC=A0?= <2091066548@qq.com> Date: Fri, 15 Aug 2025 18:12:31 +0800 Subject: [PATCH] =?UTF-8?q?feat+fix=EF=BC=9Amock=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E8=BF=94=E5=9B=9E=E4=B8=8D=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=8A=A5=E9=94=99=EF=BC=8C=E8=AE=B2=E5=B8=88?= =?UTF-8?q?=E7=AB=A0=E8=8A=82=E6=A0=91=E7=8A=B6=E5=AF=B9=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/modules/course.ts | 183 +++++++++++++++++------------ src/api/types.ts | 55 ++++++--- src/views/CourseDetail.vue | 149 ++++++++++++++--------- src/views/CourseDetailEnrolled.vue | 41 +------ src/views/CourseStudy.vue | 7 +- 5 files changed, 246 insertions(+), 189 deletions(-) diff --git a/src/api/modules/course.ts b/src/api/modules/course.ts index 9a48e5c..7a2077b 100644 --- a/src/api/modules/course.ts +++ b/src/api/modules/course.ts @@ -15,7 +15,7 @@ import type { CourseSection, CourseSectionListResponse, BackendCourseSection, - BackendCourseSectionListResponse, + BackendInstructor, Quiz, LearningProgress, SearchRequest, @@ -551,94 +551,65 @@ export class CourseApi { } // 获取课程章节列表 - static async getCourseSections(lessonId: string): Promise> { + static async getCourseSections(courseId: string): Promise> { try { - console.log('尝试从API获取课程章节数据,课程ID:', lessonId) - console.log('API请求URL: /lesson/section/list') - console.log('API请求参数:', { lesson_id: lessonId }) + console.log('🔍 获取课程章节数据,课程ID:', courseId) + console.log('🔍 API请求URL: /biz/course/' + courseId + '/section') - const backendResponse = await ApiRequest.get('/lesson/section/list', { lesson_id: lessonId }) - console.log('章节API响应:', backendResponse) + const response = await ApiRequest.get(`/biz/course/${courseId}/section`) + console.log('🔍 章节API响应:', response) - // 检查是否是axios响应格式还是我们的ApiResponse格式 - let actualData: any - let actualCode: number - let actualMessage: string - let actualTimestamp: string | undefined + // 处理后端响应格式 + if (response.data && response.data.success && response.data.result) { + console.log('✅ 响应状态码:', response.data.code) + console.log('✅ 响应消息:', response.data.message) + console.log('✅ 原始章节数据:', response.data.result) + console.log('✅ 章节数据数量:', response.data.result.length || 0) - // 使用类型断言来处理不同的响应格式 - const responseAny = backendResponse as any + // 适配数据格式 + const adaptedSections: CourseSection[] = response.data.result.map((section: BackendCourseSection) => ({ + id: section.id, + lessonId: section.courseId, // 使用courseId作为lessonId + outline: '', // 暂时为空,根据type可以设置不同的内容 + name: section.name, + type: section.type, + parentId: section.parentId, + sort: section.sortOrder, + level: section.level, + revision: 1, // 默认版本号 + createdAt: section.createTime ? new Date(section.createTime).getTime() : null, + updatedAt: section.updateTime ? new Date(section.updateTime).getTime() : null, + deletedAt: null, + completed: false, + duration: undefined + })) - if (responseAny.data && typeof responseAny.data === 'object' && 'data' in responseAny.data) { - // 这是我们期望的ApiResponse格式: { code, message, data: { list }, timestamp } - actualData = responseAny.data.data - actualCode = responseAny.data.code - actualMessage = responseAny.data.message - actualTimestamp = responseAny.data.timestamp?.toString() - console.log('检测到ApiResponse格式') - } else { - // 这可能是直接的axios响应格式: { list } - actualData = responseAny.data - actualCode = responseAny.status || 200 - actualMessage = responseAny.statusText || 'OK' - actualTimestamp = undefined - console.log('检测到直接响应格式') - } + console.log('✅ 适配后的章节数据:', adaptedSections) - console.log('响应状态码:', actualCode) - console.log('响应消息:', actualMessage) - console.log('原始章节数据:', actualData?.list) - console.log('章节数据数量:', actualData?.list?.length || 0) - - // 检查数据是否存在 - if (!actualData || !Array.isArray(actualData.list)) { - console.warn('API返回的数据结构不正确:', actualData) return { - code: actualCode, - message: actualMessage, + code: response.data.code, + message: response.data.message, + data: { + list: adaptedSections, + timestamp: Date.now(), + traceId: response.data.timestamp?.toString() || '' + } + } + } else { + console.warn('⚠️ API返回的数据结构不正确:', response.data) + return { + code: 500, + message: '数据格式错误', data: { list: [], timestamp: Date.now(), - traceId: actualTimestamp || '' - }, - timestamp: actualTimestamp + traceId: '' + } } } - - // 适配数据格式 - const adaptedSections: CourseSection[] = actualData.list.map((section: BackendCourseSection) => ({ - id: section.id, - lessonId: section.lessonId, - outline: section.videoUrl, // 将videoUrl映射到outline - name: section.name, - parentId: section.parentId, - sort: section.sortOrder, // 将sortOrder映射到sort - level: section.level === 0 ? 1 : 0, // 转换level逻辑:API中0=子级,1=父级;前端中0=父级,1=子级 - revision: section.revision, - createdAt: section.createdTime ? new Date(section.createdTime).getTime() : null, - updatedAt: section.updatedTime ? new Date(section.updatedTime).getTime() : null, - deletedAt: null, - completed: false, - duration: undefined - })) - - console.log('适配后的章节数据:', adaptedSections) - - const adaptedResponse: ApiResponse = { - code: actualCode, - message: actualMessage, - data: { - list: adaptedSections, - timestamp: Date.now(), - traceId: actualTimestamp || '' - }, - timestamp: actualTimestamp - } - - return adaptedResponse } catch (error) { - console.error('章节API调用失败:', error) - console.error('错误详情:', { + console.error('❌ 章节API调用失败:', error) + console.error('❌ 错误详情:', { message: (error as Error).message, stack: (error as Error).stack, response: (error as any).response?.data, @@ -791,6 +762,66 @@ export class CourseApi { return ApiRequest.get(`/courses/${courseId}/access`) } + // 获取课程讲师列表 + static async getCourseInstructors(courseId: string): Promise> { + try { + console.log('🔍 获取课程讲师数据,课程ID:', courseId) + console.log('🔍 API请求URL: /biz/course/' + courseId + '/teachers') + + const response = await ApiRequest.get(`/biz/course/${courseId}/teachers`) + console.log('🔍 讲师API响应:', response) + + // 处理后端响应格式 + if (response.data && response.data.success && response.data.result) { + console.log('✅ 响应状态码:', response.data.code) + console.log('✅ 响应消息:', response.data.message) + console.log('✅ 原始讲师数据:', response.data.result) + console.log('✅ 讲师数据数量:', response.data.result.length || 0) + + // 适配数据格式 + const adaptedInstructors: Instructor[] = response.data.result.map((instructor: BackendInstructor) => ({ + id: parseInt(instructor.id) || 0, // 转换为数字ID + name: instructor.name, + title: instructor.title, + bio: instructor.tag || '', // 使用tag作为bio + avatar: instructor.avatar, + rating: 4.8, // 默认评分 + studentsCount: 1000, // 默认学生数 + coursesCount: 10, // 默认课程数 + experience: '5年教学经验', // 默认经验 + education: ['计算机科学硕士'], // 默认教育背景 + certifications: ['高级讲师认证'] // 默认认证 + })) + + console.log('✅ 适配后的讲师数据:', adaptedInstructors) + + return { + code: response.data.code, + message: response.data.message, + data: adaptedInstructors + } + } else { + console.warn('⚠️ API返回的数据结构不正确:', response.data) + return { + code: 500, + message: '数据格式错误', + data: [] + } + } + } catch (error) { + console.error('❌ 讲师API调用失败:', error) + console.error('❌ 错误详情:', { + message: (error as Error).message, + stack: (error as Error).stack, + response: (error as any).response?.data, + status: (error as any).response?.status, + statusText: (error as any).response?.statusText + }) + + // 重新抛出错误,不使用模拟数据 + throw error + } + } } diff --git a/src/api/types.ts b/src/api/types.ts index 04b3f17..fccf490 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -368,32 +368,32 @@ export interface LessonResource { // 后端API返回的章节数据结构 export interface BackendCourseSection { - id: number - lessonId: number - videoUrl: string // 视频链接 + id: string + courseId: string name: string // 章节名称 + type: number // 章节类型:0=视频、1=资料、2=考试、3=作业 sortOrder: number // 排序 - parentId: number // 父章节ID - level: number // 层级:0=子级(课时),1=父级(章节) - revision: number // 版本号 - createdBy: number - createdTime: string | null - updatedBy: number - updatedTime: string | null + parentId: string // 父章节ID + level: number // 章节层级:0=一级章节、1=二级章节 + createBy: string + createTime: string + updateBy: string + updateTime: string } // 前端使用的课程章节类型(适配后的数据结构) export interface CourseSection { id: string // 改为string类型,保持一致性 lessonId: string // 改为string类型,与Course.id保持一致 - outline: string // 章节大纲/内容链接(从videoUrl适配) + outline: string // 章节大纲/内容链接 name: string // 章节名称 - parentId: number // 父章节ID + type: number // 章节类型:0=视频、1=资料、2=考试、3=作业 + parentId: string // 父章节ID,改为string类型 sort: number // 排序(从sortOrder适配) - level: number // 层级:0=父级(章节),1=子级(课时)- 已从后端数据转换 + level: number // 层级:0=一级章节、1=二级章节 revision: number // 版本号 - createdAt: number | null // 从createdTime适配 - updatedAt: number | null // 从updatedTime适配 + createdAt: number | null // 从createTime适配 + updatedAt: number | null // 从updateTime适配 deletedAt: string | null completed?: boolean // 是否已完成(前端状态) duration?: string // 课时时长(前端计算) @@ -401,8 +401,29 @@ export interface CourseSection { // 后端章节列表响应格式 export interface BackendCourseSectionListResponse { - list: BackendCourseSection[] - total: number + success: boolean + message: string + code: number + result: BackendCourseSection[] + timestamp: number +} + +// 后端讲师数据结构 +export interface BackendInstructor { + id: string + name: string + avatar: string + title: string + tag: string +} + +// 后端讲师列表响应格式 +export interface BackendInstructorListResponse { + success: boolean + message: string + code: number + result: BackendInstructor[] + timestamp: number } // 前端章节列表响应格式 diff --git a/src/views/CourseDetail.vue b/src/views/CourseDetail.vue index f771faf..bac4820 100644 --- a/src/views/CourseDetail.vue +++ b/src/views/CourseDetail.vue @@ -140,7 +140,15 @@

讲师

-
+ +
+

正在加载讲师信息...

+
+
+

{{ instructorsError }}

+ +
+
@@ -480,6 +488,10 @@ const courseSections = ref([]) const sectionsLoading = ref(false) const sectionsError = ref('') +// 讲师数据 +const instructorsLoading = ref(false) +const instructorsError = ref('') + // 报名状态管理 const isEnrolled = ref(false) // 用户是否已报名该课程 const enrollmentLoading = ref(false) // 报名加载状态 @@ -525,46 +537,12 @@ interface ChapterGroup { const groupedSections = ref([]) -// 生成模拟章节数据(用于演示) -const generateMockSections = (): CourseSection[] => { - return [ - // 第一章 - 课前准备 (4个) - { id: "1", lessonId: courseId.value, name: '开课彩蛋:新开始新征程', outline: 'https://example.com/video1.m3u8', parentId: 0, sort: 1, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '01:03:56' }, - { id: "2", lessonId: courseId.value, name: '课程定位与目标', outline: 'https://example.com/video2.m3u8', parentId: 0, sort: 2, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '00:44:05' }, - { id: "3", lessonId: courseId.value, name: '教学安排及学习建议', outline: 'https://example.com/video3.m3u8', parentId: 0, sort: 3, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '00:52:22' }, - { id: "4", lessonId: courseId.value, name: '课前准备PPT', outline: 'https://example.com/ppt1.ppt', parentId: 0, sort: 4, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, +// 生成模拟章节数据(暂时禁用,等待API修复) +// const generateMockSections = (): CourseSection[] => { +// return [] +// } - // 第二章 - 程序设计基础知识 (5个) - { id: "5", lessonId: courseId.value, name: '第一课 程序设计入门', outline: 'https://example.com/video4.m3u8', parentId: 0, sort: 5, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '00:52:22' }, - { id: "6", lessonId: courseId.value, name: '操作PPT', outline: 'https://example.com/ppt2.ppt', parentId: 0, sort: 6, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - { id: "7", lessonId: courseId.value, name: '第二课 循环结构', outline: 'https://example.com/video5.m3u8', parentId: 0, sort: 7, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '01:03:56' }, - { id: "8", lessonId: courseId.value, name: '函数&循环', outline: 'https://example.com/video5.m3u8', parentId: 0, sort: 8, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - { id: "9", lessonId: courseId.value, name: '第三课 条件结构', outline: 'https://example.com/video6.m3u8', parentId: 0, sort: 9, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:45:30' }, - // 第三章 - 实战项目 (6个) - { id: "10", lessonId: courseId.value, name: '项目一:计算器开发', outline: 'https://example.com/video7.m3u8', parentId: 0, sort: 10, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:20:15' }, - { id: "11", lessonId: courseId.value, name: '项目源码下载', outline: 'https://example.com/source1.zip', parentId: 0, sort: 11, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - { id: "12", lessonId: courseId.value, name: '项目二:数据管理系统', outline: 'https://example.com/video8.m3u8', parentId: 0, sort: 12, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:45:20' }, - { id: "13", lessonId: courseId.value, name: '作业:完成个人项目', outline: '', parentId: 0, sort: 13, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - { id: "14", lessonId: courseId.value, name: '项目三:Web应用开发', outline: 'https://example.com/video9.m3u8', parentId: 0, sort: 14, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '02:10:45' }, - { id: "15", lessonId: courseId.value, name: '期末考试', outline: '', parentId: 0, sort: 15, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - - // 第四章 - 高级应用 (4个) - { id: "16", lessonId: courseId.value, name: '高级特性介绍', outline: 'https://example.com/video10.m3u8', parentId: 0, sort: 16, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:55:30' }, - { id: "17", lessonId: courseId.value, name: '性能优化技巧', outline: 'https://example.com/video11.m3u8', parentId: 0, sort: 17, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:15:20' }, - { id: "18", lessonId: courseId.value, name: '部署与发布', outline: 'https://example.com/video12.m3u8', parentId: 0, sort: 18, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:40:15' }, - { id: "19", lessonId: courseId.value, name: '课程总结', outline: 'https://example.com/video13.m3u8', parentId: 0, sort: 19, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:30:10' }, - - // 第五章 - 拓展学习 (3个) - { id: "20", lessonId: courseId.value, name: '行业发展趋势', outline: 'https://example.com/video14.m3u8', parentId: 0, sort: 20, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:35:45' }, - { id: "21", lessonId: courseId.value, name: '学习资源推荐', outline: 'https://example.com/resources.pdf', parentId: 0, sort: 21, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - { id: "22", lessonId: courseId.value, name: '结业证书申请', outline: '', parentId: 0, sort: 22, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - - // 第六章 - 答疑与交流 (2个) - { id: "23", lessonId: courseId.value, name: '常见问题解答', outline: 'https://example.com/video15.m3u8', parentId: 0, sort: 23, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:25:30' }, - { id: "24", lessonId: courseId.value, name: '在线答疑直播', outline: 'https://example.com/live1.m3u8', parentId: 0, sort: 24, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:30:00' } - ] -} // 将章节按章分组 const groupSectionsByChapter = (sections: CourseSection[]) => { @@ -783,17 +761,17 @@ const loadCourseSections = async () => { console.log('章节API响应:', response) if (response.code === 0 || response.code === 200) { - if (response.data && Array.isArray(response.data)) { - courseSections.value = response.data - groupedSections.value = groupSectionsByChapter(response.data) - console.log('章节数据设置成功:', courseSections.value) - console.log('分组数据:', groupedSections.value) + if (response.data && response.data.list && Array.isArray(response.data.list)) { + courseSections.value = response.data.list + groupedSections.value = groupSectionsByChapter(response.data.list) + console.log('✅ 章节数据设置成功:', courseSections.value) + console.log('✅ 分组数据:', groupedSections.value) } else { - console.log('API返回的章节数据为空,使用模拟数据') + console.log('⚠️ API返回的章节数据为空,使用模拟数据') loadMockData() } } else { - console.log('API返回错误,使用模拟数据') + console.log('⚠️ API返回错误,使用模拟数据') loadMockData() } } catch (err) { @@ -807,15 +785,47 @@ const loadCourseSections = async () => { // 加载模拟数据 const loadMockData = () => { - console.log('加载模拟章节数据') - const mockSections = generateMockSections() - courseSections.value = mockSections - groupedSections.value = groupSectionsByChapter(mockSections) + console.log('⚠️ API调用失败,暂不使用模拟数据') + // 暂时不加载模拟数据,等待API修复 + courseSections.value = [] + groupedSections.value = [] +} - // 计算学习进度 - // const completed = mockSections.filter(section => section.completed).length - // completedLessons.value = completed - // progress.value = Math.round((completed / mockSections.length) * 100) +// 加载课程讲师列表 +const loadCourseInstructors = async () => { + if (!courseId.value || courseId.value.trim() === '') { + instructorsError.value = '课程ID无效' + console.error('课程ID无效:', courseId.value) + return + } + + try { + instructorsLoading.value = true + instructorsError.value = '' + + console.log('调用API获取课程讲师...') + const response = await CourseApi.getCourseInstructors(courseId.value) + console.log('讲师API响应:', response) + + if (response.code === 0 || response.code === 200) { + if (response.data && Array.isArray(response.data)) { + instructors.value = response.data + console.log('✅ 讲师数据设置成功:', instructors.value) + } else { + console.log('⚠️ API返回的讲师数据为空,使用默认数据') + // 保持默认的mock数据 + } + } else { + console.log('⚠️ API返回错误,使用默认数据') + instructorsError.value = response.message || '获取讲师信息失败' + } + } catch (err) { + console.error('加载课程讲师失败:', err) + instructorsError.value = '获取讲师信息失败' + // 保持默认的mock数据 + } finally { + instructorsLoading.value = false + } } // 切换章节展开/折叠 @@ -1131,7 +1141,8 @@ onMounted(() => { console.log('课程详情页加载完成,课程ID:', courseId.value) initializeMockState() // 初始化模拟状态 loadCourseDetail() - // loadCourseSections() // 暂时禁用章节接口调用,因为接口不存在 + loadCourseSections() // 启用章节接口调用 + loadCourseInstructors() // 启用讲师接口调用 }) @@ -1821,6 +1832,34 @@ onMounted(() => { color: #999; } +/* 讲师加载状态 */ +.instructors-loading { + padding: 20px; + text-align: center; + color: #666; +} + +.instructors-error { + padding: 20px; + text-align: center; + color: #ff4d4f; +} + +.instructors-error .retry-btn { + margin-top: 10px; + padding: 6px 12px; + background: #1890ff; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 12px; +} + +.instructors-error .retry-btn:hover { + background: #40a9ff; +} + /* 分隔线样式 */ .course-info-divider { height: 1px; diff --git a/src/views/CourseDetailEnrolled.vue b/src/views/CourseDetailEnrolled.vue index 8c0c28d..4181720 100644 --- a/src/views/CourseDetailEnrolled.vue +++ b/src/views/CourseDetailEnrolled.vue @@ -534,45 +534,10 @@ const displayComments = ref([ } ]) -// 生成模拟章节数据(用于演示) +// 生成模拟章节数据(暂时禁用) const generateMockSections = (): CourseSection[] => { - return [ - // 第一章 - 课前准备 (4个) - { id: "1", lessonId: courseId.value, name: '开课彩蛋:新开始新征程', outline: 'https://example.com/video1.m3u8', parentId: 0, sort: 1, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '01:03:56' }, - { id: "2", lessonId: courseId.value, name: '课程定位与目标', outline: 'https://example.com/video2.m3u8', parentId: 0, sort: 2, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '00:44:05' }, - { id: "3", lessonId: courseId.value, name: '教学安排及学习建议', outline: 'https://example.com/video3.m3u8', parentId: 0, sort: 3, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '00:52:22' }, - { id: "4", lessonId: courseId.value, name: '课前准备PPT', outline: 'https://example.com/ppt1.ppt', parentId: 0, sort: 4, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - - // 第二章 - 程序设计基础知识 (5个) - { id: "5", lessonId: courseId.value, name: '第一课 程序设计入门', outline: 'https://example.com/video4.m3u8', parentId: 0, sort: 5, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '00:52:22' }, - { id: "6", lessonId: courseId.value, name: '操作PPT', outline: 'https://example.com/ppt2.ppt', parentId: 0, sort: 6, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - { id: "7", lessonId: courseId.value, name: '第二课 循环结构', outline: 'https://example.com/video5.m3u8', parentId: 0, sort: 7, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '01:03:56' }, - { id: "8", lessonId: courseId.value, name: '函数&循环', outline: 'https://example.com/video5.m3u8', parentId: 0, sort: 8, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - { id: "9", lessonId: courseId.value, name: '第三课 条件结构', outline: 'https://example.com/video6.m3u8', parentId: 0, sort: 9, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:45:30' }, - - // 第三章 - 实战项目 (6个) - { id: "10", lessonId: courseId.value, name: '项目一:计算器开发', outline: 'https://example.com/video7.m3u8', parentId: 0, sort: 10, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:20:15' }, - { id: "11", lessonId: courseId.value, name: '项目源码下载', outline: 'https://example.com/source1.zip', parentId: 0, sort: 11, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - { id: "12", lessonId: courseId.value, name: '项目二:数据管理系统', outline: 'https://example.com/video8.m3u8', parentId: 0, sort: 12, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:45:20' }, - { id: "13", lessonId: courseId.value, name: '作业:完成个人项目', outline: '', parentId: 0, sort: 13, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - { id: "14", lessonId: courseId.value, name: '项目三:Web应用开发', outline: 'https://example.com/video9.m3u8', parentId: 0, sort: 14, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '02:10:45' }, - { id: "15", lessonId: courseId.value, name: '期末考试', outline: '', parentId: 0, sort: 15, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - - // 第四章 - 高级应用 (4个) - { id: "16", lessonId: courseId.value, name: '高级特性介绍', outline: 'https://example.com/video10.m3u8', parentId: 0, sort: 16, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:55:30' }, - { id: "17", lessonId: courseId.value, name: '性能优化技巧', outline: 'https://example.com/video11.m3u8', parentId: 0, sort: 17, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:15:20' }, - { id: "18", lessonId: courseId.value, name: '部署与发布', outline: 'https://example.com/video12.m3u8', parentId: 0, sort: 18, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:40:15' }, - { id: "19", lessonId: courseId.value, name: '课程总结', outline: 'https://example.com/video13.m3u8', parentId: 0, sort: 19, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:30:10' }, - - // 第五章 - 拓展学习 (3个) - { id: "20", lessonId: courseId.value, name: '行业发展趋势', outline: 'https://example.com/video14.m3u8', parentId: 0, sort: 20, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:35:45' }, - { id: "21", lessonId: courseId.value, name: '学习资源推荐', outline: 'https://example.com/resources.pdf', parentId: 0, sort: 21, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - { id: "22", lessonId: courseId.value, name: '结业证书申请', outline: '', parentId: 0, sort: 22, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, - - // 第六章 - 答疑与交流 (2个) - { id: "23", lessonId: courseId.value, name: '常见问题解答', outline: 'https://example.com/video15.m3u8', parentId: 0, sort: 23, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:25:30' }, - { id: "24", lessonId: courseId.value, name: '在线答疑直播', outline: 'https://example.com/live1.m3u8', parentId: 0, sort: 24, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:30:00' } - ] + // 暂时返回空数组,等待API修复 + return [] } // 将章节按章分组 diff --git a/src/views/CourseStudy.vue b/src/views/CourseStudy.vue index d28bccd..3dd6260 100644 --- a/src/views/CourseStudy.vue +++ b/src/views/CourseStudy.vue @@ -541,14 +541,15 @@ const generateChapterGroups = () => { lessonId: courseId.value, outline: currentVideoUrl.value, name: currentVideoTitle.value || '开课彩蛋:新开始新征程', - parentId: 1, + parentId: "1", sort: 0, level: 1, revision: 0, createdAt: Date.now(), updatedAt: null, deletedAt: null, - completed: false + completed: false, + type: 0 } ], expanded: true @@ -556,7 +557,7 @@ const generateChapterGroups = () => { } else { parentSections.forEach((parentSection, index) => { const childSections = courseSections.value.filter(section => - section.level === 1 && section.parentId === parseInt(parentSection.id) + section.level === 1 && section.parentId === parentSection.id ) groups.push({