修改课程播放视频代码
This commit is contained in:
parent
c7453da854
commit
ab31374e1a
@ -7,10 +7,7 @@
|
||||
<title>在线学习平台</title>
|
||||
<meta name="description" content="专业的在线学习平台,提供优质的编程和技术课程">
|
||||
<meta name="keywords" content="在线学习,编程课程,技术培训,Vue.js,React,Node.js">
|
||||
<!-- CKPlayer CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ckplayer@8.3.5/dist/ckplayer.css">
|
||||
<!-- CKPlayer JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/ckplayer@8.3.5/dist/ckplayer.js"></script>
|
||||
<!-- CKPlayer 将通过本地包引入,移除CDN引用 -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
@ -93,9 +93,55 @@ export class CourseApi {
|
||||
// 调用后端API
|
||||
const response = await ApiRequest.get<BackendCourseListResponse>('/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<PaginationResponse<Course>> = {
|
||||
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<BackendCourse>('/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<BackendCourseSectionListResponse>('/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<CourseSectionListResponse> = {
|
||||
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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user