// 课程相关API接口 import { ApiRequest } from '../request' import type { ApiResponse, PaginationResponse, Course, CourseCategory, CourseSubject, CourseDifficulty, CourseListQueryParams, BackendCourseItem, Chapter, Lesson, LessonResource, CourseSection, CourseSectionListResponse, BackendCourseSection, BackendInstructor, BackendSectionVideo, BackendComment, SectionVideo, VideoQuality, CourseComment, Quiz, LearningProgress, SearchRequest, Instructor, } from '../types' /** * 课程API模块 */ export class CourseApi { /** * 格式化时间戳为ISO字符串 */ private static formatTimestamp(timestamp: number | string | null | undefined): string { if (!timestamp) { return new Date().toISOString() } try { // 如果是字符串,尝试解析 if (typeof timestamp === 'string') { const date = new Date(timestamp) return isNaN(date.getTime()) ? new Date().toISOString() : date.toISOString() } // 如果是数字时间戳 if (timestamp <= 0) { return new Date().toISOString() } // 如果时间戳是秒级的,转换为毫秒级 const ms = timestamp < 10000000000 ? timestamp * 1000 : timestamp const date = new Date(ms) // 检查日期是否有效 if (isNaN(date.getTime())) { return new Date().toISOString() } return date.toISOString() } catch (error) { console.error('时间戳格式化失败:', error) return new Date().toISOString() } } /** * 映射后端难度值到前端级别 */ private static mapDifficultyToLevel(difficulty: number): string { switch (difficulty) { case 0: return '零基础' case 1: return '初级' case 2: return '进阶' case 3: return '高阶' default: return '未知' } } /** * 映射后端难度值到标准级别 */ private static mapDifficultyToStandardLevel(difficulty: number): 'beginner' | 'intermediate' | 'advanced' { switch (difficulty) { case 0: return 'beginner' case 1: return 'beginner' case 2: return 'intermediate' case 3: return 'advanced' default: return 'beginner' } } // 获取课程列表 - 适配后端接口 static async getCourses(params?: CourseListQueryParams): Promise> { try { console.log('🚀 调用课程列表API,参数:', params) // 构建查询参数,根据API文档的参数名称 const queryParams: any = {} if (params?.categoryId) queryParams.categoryId = params.categoryId if (params?.difficulty) queryParams.difficulty = params.difficulty if (params?.subject) queryParams.subject = params.subject console.log('🔍 查询参数:', queryParams) // 调用后端API const response = await ApiRequest.get('/aiol/aiolCourse/query_list', queryParams) console.log('🔍 课程列表API响应:', response) // 处理后端响应格式 if (response.data && response.data.success && response.data.result) { // 转换后端数据格式为前端格式 const courses: Course[] = response.data.result.map((item: BackendCourseItem) => ({ id: item.id, // 保持字符串格式,不转换为数字 title: item.name || '', description: item.description || '', instructor: item.school || '未知讲师', teacherList: item.teacherList || [], // 新增:传递讲师列表 duration: item.arrangement || '待定', level: this.mapDifficultyToLevel(item.difficulty), category: item.subject || '其他', thumbnail: item.cover || '', price: 0, // 后端没有价格字段,设为0 rating: 0, // 后端没有评分字段,设为0 studentsCount: item.enrollCount || 0, lessonsCount: 0, // 后端没有课程数量字段,设为0 tags: [], isEnrolled: false, progress: 0, createdAt: this.formatTimestamp(item.createTime), updatedAt: this.formatTimestamp(item.updateTime), status: item.status === 1 ? 'published' : 'draft', enrollmentCount: item.enrollCount || 0, maxEnrollment: item.maxEnroll || 0, startDate: item.startTime || '', endDate: item.endTime || '', outline: item.outline || '', prerequisite: item.prerequisite || '', reference: item.reference || '', target: item.target || '', question: item.question || '', video: item.video || '' })) return { code: 200, message: '获取成功', data: courses } } else { console.warn('⚠️ 课程列表API返回格式异常:', response) return { code: 500, message: response.data?.message || '获取课程列表失败', data: [] } } } catch (error: any) { console.error('课程API调用失败:', error) let errorMessage = '获取课程列表失败' if (error.code === 'ECONNABORTED') { errorMessage = '请求超时,请检查网络连接' } else if (error.message === 'Network Error') { errorMessage = '网络连接失败,请检查网络设置' } else if (error.message?.includes('网络')) { errorMessage = error.message } // 返回空数据而不是抛出错误,确保应用不会崩溃 return { code: 500, message: errorMessage, data: [] } } } // 获取课程详情 - 适配后端接口 static async getCourseDetail(id: string): Promise> { try { console.log('🚀 调用课程详情API,课程ID:', id) // 调用后端API const response = await ApiRequest.get('/aiol/aiolCourse/detail', { id }) console.log('🔍 课程详情API响应:', response) // 处理后端响应格式 if (response.data && response.data.success) { // 检查result是否为null或空 if (!response.data.result) { console.warn('⚠️ 课程详情为空,可能课程不存在或已删除') return { code: 404, message: '课程不存在或已删除', data: {} as Course } } // 转换后端数据格式为前端格式 const item: BackendCourseItem = response.data.result const course: Course = { id: item.id, // 保持字符串格式,不转换为数字 title: item.name || '', description: item.description || '', thumbnail: item.cover || '', price: 0, // 后端没有价格字段,设为0 currency: 'CNY', rating: 0, // 后端没有评分字段,设为0 ratingCount: 0, studentsCount: item.enrollCount || 0, duration: item.arrangement || '待定', totalLessons: 0, level: this.mapDifficultyToStandardLevel(item.difficulty), language: 'zh-CN', category: { id: 1, name: item.subject || '其他', slug: 'other' }, tags: [], skills: [], requirements: item.prerequisite ? [item.prerequisite] : [], objectives: item.target ? [item.target] : [], instructor: { id: 1, name: item.school || '未知讲师', title: '讲师', bio: '', avatar: '', rating: 4.5, studentsCount: 0, coursesCount: 0, experience: '', education: [], certifications: [] }, status: item.status === 1 ? 'published' : 'draft', isEnrolled: false, progress: 0, createdAt: this.formatTimestamp(item.createTime), updatedAt: this.formatTimestamp(item.updateTime) } return { code: 200, message: '获取成功', data: course } } else { console.warn('⚠️ 课程详情API返回格式异常:', response) return { code: 500, message: response.data?.message || '获取课程详情失败', data: {} as Course } } } catch (error: any) { console.error('❌ 获取课程详情失败:', error) return { code: 500, message: error.message || '获取课程详情失败', data: {} as Course } } } // 搜索课程 static searchCourses(params: SearchRequest): Promise>> { return ApiRequest.get('/courses/search', params) } // 获取热门课程 static getPopularCourses(limit?: number): Promise> { return ApiRequest.get('/courses/popular', { limit }) } // 获取最新课程 static getLatestCourses(limit?: number): Promise> { return ApiRequest.get('/courses/latest', { limit }) } // 获取推荐课程 static getRecommendedCourses(userId?: number, limit?: number): Promise> { return ApiRequest.get('/courses/recommended', { userId, limit }) } // 获取课程详情 - 适配后端接口 static async getCourseById(id: string): Promise> { try { // 调用后端课程详情接口 const response = await ApiRequest.get('/aiol/aiolCourse/detail', { id }) console.log('🔍 课程详情API响应:', response) // 处理后端响应格式 if (response.data && response.data.success) { // 检查result是否为null或空 if (!response.data.result) { console.warn('⚠️ 课程详情为空,可能课程不存在或已删除') return { code: 404, message: '课程不存在或已删除', data: {} as Course } } // 转换后端数据格式为前端格式 const item: BackendCourseItem = response.data.result const course: Course = { id: item.id, // 保持字符串格式,不转换为数字 title: item.name || '', description: item.description || '', thumbnail: item.cover || '', price: 0, // 后端没有价格字段,设为0 currency: 'CNY', rating: 0, // 后端没有评分字段,设为0 ratingCount: 0, studentsCount: item.enrollCount || 0, duration: item.arrangement || '待定', totalLessons: 0, level: this.mapDifficultyToStandardLevel(item.difficulty), language: 'zh-CN', category: { id: 1, name: item.subject || '其他', slug: 'other' }, tags: [], skills: [], requirements: item.prerequisite ? [item.prerequisite] : [], objectives: item.target ? [item.target] : [], instructor: { id: 1, name: item.school || '未知讲师', title: '讲师', bio: '', avatar: '', rating: 4.5, studentsCount: 0, coursesCount: 0, experience: '', education: [], certifications: [] }, status: item.status === 1 ? 'published' : 'draft', isEnrolled: false, progress: 0, createdAt: this.formatTimestamp(item.createTime), updatedAt: this.formatTimestamp(item.updateTime) } return { code: 200, message: '获取成功', data: course } } else { console.warn('⚠️ 课程详情API返回格式异常:', response) return { code: 500, message: response.data?.message || '获取课程详情失败', data: {} as Course } } } catch (error: any) { console.error('❌ 获取课程详情失败:', error) return { code: 500, message: error.message || '获取课程详情失败', data: {} as Course } } } // 获取课程章节 static getCourseChapters(courseId: number): Promise> { return ApiRequest.get(`/courses/${courseId}/chapters`) } // 获取课程所有课时 static getCourseLessons(courseId: number): Promise> { return ApiRequest.get(`/courses/${courseId}/lessons`) } // 获取章节详情 static getChapterById(id: number): Promise> { return ApiRequest.get(`/chapters/${id}`) } // 获取课时详情 static getLessonById(id: number): Promise> { return ApiRequest.get(`/lessons/${id}`) } // 获取课时资源 static getLessonResources(lessonId: number): Promise> { return ApiRequest.get(`/lessons/${lessonId}/resources`) } // 获取课程分类 static async getCategories(): Promise> { try { console.log('🚀 获取课程分类列表') // 调用后端API(不需要token) const response = await ApiRequest.get('/aiol/aiolCourse/category/list') console.log('🔍 分类API响应:', response) // 处理后端响应格式 if (response.data && response.data.success && response.data.result) { // 转换后端数据格式为前端格式 const categories: CourseCategory[] = response.data.result.map((item: any) => ({ id: parseInt(item.id) || 0, name: item.name || '', slug: item.name?.toLowerCase().replace(/\s+/g, '-') || '', description: '', sortOrder: item.sortOrder || 0 })) return { code: 200, message: '获取成功', data: categories } } else { console.warn('⚠️ 分类API返回格式异常:', response) return { code: 500, message: response.data?.message || '获取分类失败', data: [] } } } catch (error: any) { console.error('❌ 获取课程分类失败:', error) return { code: 500, message: error.message || '获取分类失败', data: [] } } } // 获取课程专题列表 static async getSubjects(): Promise> { try { console.log('🚀 获取课程专题列表') // 调用后端API(不需要token) const response = await ApiRequest.get('/aiol/aiolCourse/subject/list') console.log('🔍 专题API响应:', response) // 处理后端响应格式 if (response.data && response.data.success && response.data.result) { // 转换后端数据格式为前端格式(专题接口返回的是value和label字段) const subjects: CourseSubject[] = response.data.result.map((item: any, index: number) => ({ id: item.value || '0', // 保持原始的value值(字符串格式) name: item.label || '', slug: item.label?.toLowerCase().replace(/\s+/g, '-') || '', description: '', sortOrder: index })) return { code: 200, message: '获取成功', data: subjects } } else { console.warn('⚠️ 专题API返回格式异常:', response) return { code: 500, message: response.data?.message || '获取专题失败', data: [] } } } catch (error: any) { console.error('❌ 获取课程专题失败:', error) return { code: 500, message: error.message || '获取专题失败', data: [] } } } // 获取课程难度列表 static async getDifficulties(): Promise> { try { console.log('🚀 获取课程难度列表') // 调用后端API(不需要token) const response = await ApiRequest.get('/aiol/aiolCourse/difficulty/list') console.log('🔍 难度API响应:', response) // 处理后端响应格式 if (response.data && response.data.success && response.data.result) { // 转换后端数据格式为前端格式(难度接口返回的是value和label字段) const difficulties: CourseDifficulty[] = response.data.result.map((item: any, index: number) => ({ id: item.value || '0', // 保持原始的value值(字符串格式) name: item.label || '', slug: item.label?.toLowerCase().replace(/\s+/g, '-') || '', description: '', sortOrder: index })) return { code: 200, message: '获取成功', data: difficulties } } else { console.warn('⚠️ 难度API返回格式异常:', response) return { code: 500, message: response.data?.message || '获取难度失败', data: [] } } } catch (error: any) { console.error('❌ 获取课程难度失败:', error) return { code: 500, message: error.message || '获取难度失败', data: [] } } } // 获取分类下的课程 static getCoursesByCategory(categoryId: number, params?: { page?: number pageSize?: number sortBy?: string }): Promise>> { return ApiRequest.get(`/categories/${categoryId}/courses`, params) } // 报名课程 static async enrollCourse(courseId: string): Promise> { try { console.log('🔍 报名课程,课程ID:', courseId) console.log('🔍 API请求URL: /aiol/aiolCourse/' + courseId + '/enroll') const response = await ApiRequest.post(`/aiol/aiolCourse/${courseId}/enroll`) console.log('🔍 报名API响应:', response) // 处理后端响应格式 if (response.data && typeof response.data === 'object') { // 如果响应包含success字段,使用标准格式 if ('success' in response.data) { return { code: response.data.code || 0, message: response.data.message || '报名成功', data: { success: response.data.success || false, message: response.data.message || '', result: response.data } } } } // 默认返回成功状态 return { code: 0, message: '报名成功', data: { success: true, message: '报名成功', result: null } } } catch (error: any) { console.error('❌ 课程报名失败:', error) // 如果是401错误,说明未登录 if (error.response?.status === 401) { return { code: 401, message: '请先登录', data: { success: false, message: '请先登录', result: null } } } // 其他错误 return { code: error.response?.status || 500, message: error.message || '报名失败', data: { success: false, message: error.message || '报名失败', result: null } } } } // 取消报名 static unenrollCourse(courseId: number): Promise> { return ApiRequest.delete(`/courses/${courseId}/enroll`) } // 检查课程报名状态 static async checkEnrollmentStatus(courseId: string): Promise> { try { console.log('🔍 检查课程报名状态,课程ID:', courseId) console.log('🔍 API请求URL: /aiol/aiolCourse/' + courseId + '/is_enrolled') const response = await ApiRequest.get(`/aiol/aiolCourse/${courseId}/is_enrolled`) console.log('🔍 报名状态API响应:', response) // 处理后端响应格式 if (response.data && typeof response.data === 'object') { // 如果响应包含success字段,使用标准格式 if ('success' in response.data) { return { code: response.data.code || 0, message: response.data.message || '', data: { result: response.data.result || false, message: response.data.message } } } // 如果直接返回result字段 if ('result' in response.data) { return { code: 0, message: '查询成功', data: { result: response.data.result || false, message: response.data.message } } } } // 默认返回未报名状态 return { code: 0, message: '查询成功', data: { result: false, message: '未报名' } } } catch (error: any) { console.error('❌ 检查课程报名状态失败:', error) // 如果是401错误,说明未登录 if (error.response?.status === 401) { return { code: 401, message: '请先登录', data: { result: false, message: '请先登录' } } } // 其他错误,默认返回未报名状态 return { code: error.response?.status || 500, message: error.message || '查询失败', data: { result: false, message: error.message || '查询失败' } } } } // 获取课程章节列表 static async getCourseSections(courseId: string): Promise> { try { console.log('🔍 获取课程章节数据,课程ID:', courseId) console.log('🔍 API请求URL: /aiol/aiolCourse/' + courseId + '/section') const response = await ApiRequest.get(`/aiol/aiolCourse/${courseId}/section`) 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 adaptedSections: CourseSection[] = response.data.result.map((section: BackendCourseSection) => ({ id: section.id, lessonId: section.courseId, // 使用courseId作为lessonId outline: '', // 暂时为空,根据type可以设置不同的内容 name: section.name, type: section.type, // 保持原值,可能为null parentId: section.parentId || '', // 如果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 })) console.log('✅ 适配后的章节数据:', adaptedSections) return { 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: '' } } } } 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 } } // 获取我的课程 static getMyCourses(params?: { page?: number pageSize?: number status?: 'all' | 'in_progress' | 'completed' }): Promise>> { return ApiRequest.get('/my-courses', params) } // 获取学习进度 static getLearningProgress(courseId: number): Promise> { return ApiRequest.get(`/courses/${courseId}/progress`) } // 更新学习进度 static updateLearningProgress(data: { courseId: number lessonId: number progress: number timeSpent?: number }): Promise> { return ApiRequest.post('/learning-progress', data) } // 标记课时完成 static markLessonCompleted(lessonId: number): Promise> { return ApiRequest.post(`/lessons/${lessonId}/complete`) } // 获取课程测验 static getCourseQuizzes(courseId: number): Promise> { return ApiRequest.get(`/courses/${courseId}/quizzes`) } // 获取测验详情 static getQuizById(id: number): Promise> { return ApiRequest.get(`/quizzes/${id}`) } // 提交测验答案 static submitQuizAnswers(quizId: number, answers: Array<{ questionId: number answer: string | string[] }>): Promise }>> { return ApiRequest.post(`/quizzes/${quizId}/submit`, { answers }) } // 获取测验结果 static getQuizResults(quizId: number): Promise bestScore: number averageScore: number totalAttempts: number }>> { return ApiRequest.get(`/quizzes/${quizId}/results`) } // 下载课程资源 static downloadResource(resourceId: number): Promise { return ApiRequest.download(`/resources/${resourceId}/download`) } // 获取讲师信息 static getInstructorById(id: number): Promise> { return ApiRequest.get(`/instructors/${id}`) } // 获取讲师的课程 static getInstructorCourses(instructorId: number, params?: { page?: number pageSize?: number }): Promise>> { return ApiRequest.get(`/instructors/${instructorId}/courses`, params) } // 关注讲师 static followInstructor(instructorId: number): Promise> { return ApiRequest.post(`/instructors/${instructorId}/follow`) } // 取消关注讲师 static unfollowInstructor(instructorId: number): Promise> { return ApiRequest.delete(`/instructors/${instructorId}/follow`) } // 获取课程统计信息 static getCourseStats(courseId: number): Promise }>> { return ApiRequest.get(`/courses/${courseId}/stats`) } // 预览课程(免费课时) static previewCourse(courseId: number): Promise> { return ApiRequest.get(`/courses/${courseId}/preview`) } // 获取相关课程推荐 static getRelatedCourses(courseId: number, limit?: number): Promise> { return ApiRequest.get(`/courses/${courseId}/related`, { limit }) } // 检查课程访问权限 static checkCourseAccess(courseId: number): Promise> { return ApiRequest.get(`/courses/${courseId}/access`) } // 获取课程讲师列表 static async getCourseInstructors(courseId: string): Promise> { try { console.log('🔍 获取课程讲师数据,课程ID:', courseId) console.log('🔍 API请求URL: /aiol/aiolCourse/' + courseId + '/teachers') const response = await ApiRequest.get(`/aiol/aiolCourse/${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 } } // 获取章节视频列表 static async getSectionVideos(courseId: string, sectionId: string): Promise> { try { console.log('🔍 获取章节视频数据,课程ID:', courseId, '章节ID:', sectionId) console.log('🔍 API请求URL: /aiol/aiolCourse/' + courseId + '/section_video/' + sectionId) const response = await ApiRequest.get(`/aiol/aiolCourse/${courseId}/section_video/${sectionId}`) 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 adaptedVideos: SectionVideo[] = response.data.result.map((video: BackendSectionVideo) => { // 解析fileUrl中的多个清晰度URL const qualities = this.parseVideoQualities(video.fileUrl) return { id: video.id, name: video.name, description: video.description, type: video.type, thumbnailUrl: video.thumbnailUrl, duration: video.duration, fileSize: video.fileSize, qualities: qualities, defaultQuality: '360', // 默认360p currentQuality: '360' // 当前选中360p } }) console.log('✅ 适配后的视频数据:', adaptedVideos) return { code: response.data.code, message: response.data.message, data: adaptedVideos } } 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 } } // 解析视频URL(逗号分隔的多个清晰度URL) private static parseVideoQualities(fileUrl: string): VideoQuality[] { const qualities: VideoQuality[] = [] try { if (!fileUrl || fileUrl.trim() === '') { console.warn('视频URL为空') return qualities } // 按逗号分割URL const urls = fileUrl.split(',').map(url => url.trim()).filter(url => url.length > 0) console.log('🔍 分割后的视频URL:', urls) // 支持的清晰度列表(按优先级排序) const supportedQualities = [ { value: '1080', label: '1080p' }, { value: '720', label: '720p' }, { value: '480', label: '480p' }, { value: '360', label: '360p' } ] // 根据URL数量分配清晰度 // 假设URL按清晰度从高到低排列:1080p, 720p, 480p, 360p urls.forEach((url, index) => { if (index < supportedQualities.length) { qualities.push({ label: supportedQualities[index].label, value: supportedQualities[index].value, url: url }) } }) // 如果没有解析到任何清晰度,使用第一个URL作为360p if (qualities.length === 0 && urls.length > 0) { qualities.push({ label: '360p', value: '360', url: urls[0] }) } console.log('✅ 解析后的视频清晰度:', qualities) } catch (error) { console.warn('解析视频清晰度失败,使用原始URL:', error) // 如果解析失败,将整个fileUrl作为360p使用 qualities.push({ label: '360p', value: '360', url: fileUrl }) } return qualities } // 获取课程评论列表 static async getCourseComments(courseId: string): Promise> { try { console.log('🔍 获取课程评论数据,课程ID:', courseId) console.log('🔍 API请求URL: /aiol/aiolComment/course/' + courseId + '/list') const response = await ApiRequest.get(`/aiol/aiolComment/course/${courseId}/list`) 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 adaptedComments: CourseComment[] = response.data.result.map((comment: BackendComment) => ({ id: comment.id, userId: comment.userId, userName: comment.userName || '匿名用户', userAvatar: comment.userAvatar || '', userTag: comment.userTag || '', content: comment.content || '', images: comment.imgs ? comment.imgs.split(',').filter(img => img.trim()) : [], // 图片URL逗号分隔 isTop: comment.izTop === 1, // 1=置顶,0=普通 likeCount: comment.likeCount || 0, createTime: comment.createTime || '', timeAgo: this.formatTimeAgo(comment.createTime) // 计算相对时间 })) console.log('✅ 适配后的评论数据:', adaptedComments) return { code: response.data.code, message: response.data.message, data: adaptedComments } } else { console.warn('⚠️ API返回的数据结构不正确:', response.data) return { code: 500, message: '数据格式错误', data: [] } } } catch (error) { console.error('❌ 评论API调用失败:', error) throw error } } // 格式化时间为相对时间显示 private static formatTimeAgo(createTime: string): string { if (!createTime) return '未知时间' try { const now = new Date() const commentTime = new Date(createTime) const diffMs = now.getTime() - commentTime.getTime() const diffMinutes = Math.floor(diffMs / (1000 * 60)) const diffHours = Math.floor(diffMs / (1000 * 60 * 60)) const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)) const diffWeeks = Math.floor(diffDays / 7) const diffMonths = Math.floor(diffDays / 30) if (diffMinutes < 1) return '刚刚' if (diffMinutes < 60) return `${diffMinutes}分钟前` if (diffHours < 24) return `${diffHours}小时前` if (diffDays < 7) return `${diffDays}天前` if (diffWeeks < 4) return `${diffWeeks}周前` if (diffMonths < 12) return `${diffMonths}个月前` return commentTime.toLocaleDateString() } catch (error) { console.warn('时间格式化失败:', error) return createTime } } } export default CourseApi