diff --git a/index.html b/index.html
index 3699cc4..24f2f0e 100644
--- a/index.html
+++ b/index.html
@@ -7,10 +7,7 @@
在线学习平台
-
-
-
-
+
diff --git a/src/api/modules/course.ts b/src/api/modules/course.ts
index df09693..6b8ed79 100644
--- a/src/api/modules/course.ts
+++ b/src/api/modules/course.ts
@@ -93,9 +93,55 @@ export class CourseApi {
// 调用后端API
const response = await ApiRequest.get('/lesson/list', queryParams)
console.log('课程列表API响应:', response)
+ console.log('响应数据结构:', response.data)
+ console.log('响应数据类型:', typeof response.data)
+
+ // 检查是否是axios响应格式还是我们的ApiResponse格式
+ let actualData: any
+ let actualCode: number
+ let actualMessage: string
+
+ // 使用类型断言来处理不同的响应格式
+ const responseAny = response as any
+
+ if (responseAny.data && typeof responseAny.data === 'object' && 'data' in responseAny.data) {
+ // 这是我们期望的ApiResponse格式: { code, message, data: { list, total } }
+ actualData = responseAny.data.data
+ actualCode = responseAny.data.code
+ actualMessage = responseAny.data.message
+ console.log('检测到ApiResponse格式')
+ } else {
+ // 这可能是直接的axios响应格式: { list, total }
+ actualData = responseAny.data
+ actualCode = responseAny.status || 200
+ actualMessage = responseAny.statusText || 'OK'
+ console.log('检测到直接响应格式')
+ }
+
+ console.log('实际数据:', actualData)
+ console.log('实际数据的list字段:', actualData?.list)
+ console.log('list是否为数组:', Array.isArray(actualData?.list))
+
+ // 检查响应数据的有效性
+ if (!actualData || !Array.isArray(actualData.list)) {
+ console.warn('API响应数据格式异常')
+ console.warn('期望的格式: { list: [], total: number }')
+ console.warn('实际收到的格式:', actualData)
+ return {
+ code: actualCode || 0,
+ message: actualMessage || '数据格式异常',
+ data: {
+ list: [],
+ total: 0,
+ page: params?.page || 1,
+ pageSize: params?.pageSize || 10,
+ totalPages: 0
+ }
+ }
+ }
// 适配后端响应格式为前端期望的格式
- const adaptedCourses: Course[] = response.data.list.map((backendCourse: BackendCourse) => ({
+ const adaptedCourses: Course[] = actualData.list.map((backendCourse: BackendCourse) => ({
id: backendCourse.id,
title: backendCourse.name,
description: backendCourse.description,
@@ -140,20 +186,33 @@ export class CourseApi {
}))
const adaptedResponse: ApiResponse> = {
- code: response.code,
- message: response.message,
+ code: actualCode,
+ message: actualMessage,
data: {
list: adaptedCourses,
- total: response.data.total,
+ total: actualData.total || 0,
page: params?.page || 1,
pageSize: params?.pageSize || 10,
- totalPages: Math.ceil(response.data.total / (params?.pageSize || 10))
+ totalPages: Math.ceil((actualData.total || 0) / (params?.pageSize || 10))
}
}
return adaptedResponse
} catch (error) {
- throw error
+ console.error('课程API调用失败:', error)
+
+ // 返回空数据而不是抛出错误,确保应用不会崩溃
+ return {
+ code: 500,
+ message: '获取课程列表失败',
+ data: {
+ list: [],
+ total: 0,
+ page: params?.page || 1,
+ pageSize: params?.pageSize || 10,
+ totalPages: 0
+ }
+ }
}
}
@@ -183,55 +242,77 @@ export class CourseApi {
// 调用后端课程详情接口
const response = await ApiRequest.get('/lesson/detail', { id })
+ // 检查是否是axios响应格式还是我们的ApiResponse格式
+ let actualData: any
+ let actualCode: number
+ let actualMessage: string
+
+ // 使用类型断言来处理不同的响应格式
+ const responseAny = response as any
+
+ if (responseAny.data && typeof responseAny.data === 'object' && 'data' in responseAny.data) {
+ // 这是我们期望的ApiResponse格式: { code, message, data: BackendCourse }
+ actualData = responseAny.data.data
+ actualCode = responseAny.data.code
+ actualMessage = responseAny.data.message
+ console.log('检测到ApiResponse格式')
+ } else {
+ // 这可能是直接的axios响应格式: BackendCourse
+ actualData = responseAny.data
+ actualCode = responseAny.status || 200
+ actualMessage = responseAny.statusText || 'OK'
+ console.log('检测到直接响应格式')
+ }
+
// 适配数据格式
const adaptedCourse: Course = {
- id: response.data.id,
- title: response.data.name,
- description: response.data.description,
- content: response.data.outline, // 使用 outline 作为课程内容
- thumbnail: response.data.cover,
- coverImage: response.data.cover,
- price: parseFloat(response.data.price || '0'),
- originalPrice: parseFloat(response.data.price || '0'),
+ id: actualData.id,
+ title: actualData.name,
+ description: actualData.description,
+ content: actualData.outline, // 使用 outline 作为课程内容
+ thumbnail: actualData.cover,
+ coverImage: actualData.cover,
+ price: parseFloat(actualData.price || '0'),
+ originalPrice: parseFloat(actualData.price || '0'),
currency: 'CNY',
rating: 4.5,
ratingCount: 0,
studentsCount: 0,
- duration: this.calculateDuration(response.data.startTime, response.data.endTime),
+ duration: this.calculateDuration(actualData.startTime, actualData.endTime),
totalLessons: 0,
level: 'beginner' as const,
language: 'zh-CN',
category: {
- id: response.data.categoryId,
+ id: actualData.categoryId,
name: '未分类',
slug: 'uncategorized'
},
tags: [],
skills: [],
- requirements: response.data.prerequisite ? [response.data.prerequisite] : [],
- objectives: response.data.target ? [response.data.target] : [],
+ requirements: actualData.prerequisite ? [actualData.prerequisite] : [],
+ objectives: actualData.target ? [actualData.target] : [],
instructor: {
- id: response.data.teacherId || 0,
- name: response.data.school || '未知讲师',
+ id: actualData.teacherId || 0,
+ name: actualData.school || '未知讲师',
title: '讲师',
- bio: response.data.position || '',
+ bio: actualData.position || '',
avatar: '',
rating: 4.5,
studentsCount: 0,
coursesCount: 0,
- experience: response.data.arrangement || '',
+ experience: actualData.arrangement || '',
education: [],
certifications: []
},
status: 'published' as const,
- createdAt: this.formatTimestamp(response.data.createdTime),
- updatedAt: this.formatTimestamp(response.data.updatedTime),
- publishedAt: response.data.startTime
+ createdAt: this.formatTimestamp(actualData.createdTime),
+ updatedAt: this.formatTimestamp(actualData.updatedTime),
+ publishedAt: actualData.startTime
}
return {
- code: response.code,
- message: response.message,
+ code: actualCode,
+ message: actualMessage,
data: adaptedCourse
}
} catch (error) {
@@ -300,28 +381,54 @@ export class CourseApi {
const backendResponse = await ApiRequest.get('/lesson/section/list', { lesson_id: lessonId.toString() })
console.log('章节API响应:', backendResponse)
- console.log('响应状态码:', backendResponse.code)
- console.log('响应消息:', backendResponse.message)
- console.log('原始章节数据:', backendResponse.data?.list)
- console.log('章节数据数量:', backendResponse.data?.list?.length || 0)
+
+ // 检查是否是axios响应格式还是我们的ApiResponse格式
+ let actualData: any
+ let actualCode: number
+ let actualMessage: string
+ let actualTimestamp: string | undefined
+
+ // 使用类型断言来处理不同的响应格式
+ const responseAny = backendResponse as any
+
+ 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('响应状态码:', actualCode)
+ console.log('响应消息:', actualMessage)
+ console.log('原始章节数据:', actualData?.list)
+ console.log('章节数据数量:', actualData?.list?.length || 0)
// 检查数据是否存在
- if (!backendResponse.data || !backendResponse.data.list) {
- console.warn('API返回的数据结构不正确:', backendResponse.data)
+ if (!actualData || !Array.isArray(actualData.list)) {
+ console.warn('API返回的数据结构不正确:', actualData)
return {
- code: backendResponse.code,
- message: backendResponse.message,
+ code: actualCode,
+ message: actualMessage,
data: {
list: [],
timestamp: Date.now(),
- traceId: backendResponse.timestamp?.toString() || ''
+ traceId: actualTimestamp || ''
},
- timestamp: backendResponse.timestamp?.toString()
+ timestamp: actualTimestamp
}
}
// 适配数据格式
- const adaptedSections: CourseSection[] = backendResponse.data.list.map((section: BackendCourseSection) => ({
+ const adaptedSections: CourseSection[] = actualData.list.map((section: BackendCourseSection) => ({
id: section.id,
lessonId: section.lessonId,
outline: section.videoUrl, // 将videoUrl映射到outline
@@ -340,14 +447,14 @@ export class CourseApi {
console.log('适配后的章节数据:', adaptedSections)
const adaptedResponse: ApiResponse = {
- code: backendResponse.code,
- message: backendResponse.message,
+ code: actualCode,
+ message: actualMessage,
data: {
list: adaptedSections,
timestamp: Date.now(),
- traceId: backendResponse.timestamp?.toString() || ''
+ traceId: actualTimestamp || ''
},
- timestamp: backendResponse.timestamp?.toString()
+ timestamp: actualTimestamp
}
return adaptedResponse
diff --git a/src/views/Courses.vue b/src/views/Courses.vue
index d2f0048..715c50b 100644
--- a/src/views/Courses.vue
+++ b/src/views/Courses.vue
@@ -355,16 +355,30 @@ const loadCourses = async () => {
keyword: selectedMajor.value !== '全部' ? selectedMajor.value : undefined
}
+ console.log('加载课程参数:', params)
const response = await CourseApi.getCourses(params)
+ console.log('课程API响应:', response)
- if (response.code === 0 || response.code === 200) {
- courses.value = response.data.list
- total.value = response.data.total
+ if (response && response.data) {
+ if (response.code === 0 || response.code === 200) {
+ courses.value = response.data.list || []
+ total.value = response.data.total || 0
+ console.log('课程加载成功:', courses.value.length, '条课程')
+ } else {
+ console.error('获取课程列表失败:', response.message)
+ courses.value = []
+ total.value = 0
+ }
} else {
- console.error('获取课程列表失败:', response.message)
+ console.error('API响应格式异常:', response)
+ courses.value = []
+ total.value = 0
}
} catch (error) {
console.error('加载课程失败:', error)
+ courses.value = []
+ total.value = 0
+ // 可以在这里添加用户友好的错误提示
} finally {
loading.value = false
}
diff --git a/src/views/Faculty.vue b/src/views/Faculty.vue
index 147be40..901c9f0 100644
--- a/src/views/Faculty.vue
+++ b/src/views/Faculty.vue
@@ -106,14 +106,14 @@ const hasBannerImage = computed(() => bannerImageSrc.value.trim() !== '')
// 筛选标签数据
const filterTabs = ref([
- { id: 'all', name: '全部讲师' },
- { id: 'main', name: '主讲' },
- { id: 'international', name: '注册国际讲师' },
- { id: 'consultant', name: '咨询师' },
- { id: 'expert', name: '专家顾问' },
- { id: 'senior', name: '资深讲师' },
- { id: 'featured', name: '金牌讲师' },
- { id: 'enterprise', name: '企业导师' }
+ { id: 'field', name: '课长领域' },
+ { id: 'all', name: '全部' },
+ { id: 'chinese-promotion', name: '汉语国际推广' },
+ { id: 'chinese-language', name: '汉语言' },
+ { id: 'chinese-education', name: '华文教育' },
+ { id: 'e-commerce', name: '电子商务' },
+ { id: 'new-energy', name: '新能源' },
+ { id: 'smart-education', name: '智慧教育' }
])
const activeTab = ref('all')
@@ -328,32 +328,35 @@ const goToPage = (page: number) => {
display: flex;
gap: 0;
margin-bottom: 40px;
- background: white;
- border-radius: 8px;
- padding: 8px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ background: transparent;
+ border-bottom: 1px solid #e5e5e5;
+ padding: 0;
+ box-shadow: none;
}
.filter-tab {
- padding: 12px 24px;
+ padding: 12px 20px;
border: none;
background: transparent;
color: #666;
font-size: 14px;
cursor: pointer;
- border-radius: 6px;
+ border-radius: 0;
transition: all 0.3s;
white-space: nowrap;
+ position: relative;
+ border-bottom: 2px solid transparent;
}
.filter-tab:hover {
- background: #f8f9fa;
- color: #333;
+ color: #4A90E2;
}
.filter-tab.active {
- background: #4A90E2;
- color: white;
+ background: transparent;
+ color: #4A90E2;
+ border-bottom-color: #4A90E2;
+ font-weight: 500;
}
/* 师资卡片网格 */
@@ -546,12 +549,15 @@ const goToPage = (page: number) => {
.filter-tabs {
flex-wrap: wrap;
- gap: 8px;
+ gap: 0;
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
}
.filter-tab {
- padding: 8px 16px;
+ padding: 10px 16px;
font-size: 13px;
+ flex-shrink: 0;
}
.placeholder-icon {