11 KiB
11 KiB
前端代码实现 - 我的课程与学习记录关联
📱 1. API接口定义
在 peidu/uniapp/src/api/parentAcademy.js 中添加:
// 课程学习相关接口
export default {
// ... 现有接口 ...
// 开始学习课程
startLearning(data) {
return request({
url: '/api/parent-academy/start-learning',
method: 'POST',
data
})
},
// 更新学习进度
updateProgress(data) {
return request({
url: '/api/parent-academy/update-progress',
method: 'POST',
data
})
},
// 完成课程学习
completeLearning(data) {
return request({
url: '/api/parent-academy/complete-learning',
method: 'POST',
data
})
},
// 获取学习历史
getLearningHistory(courseId) {
return request({
url: '/api/parent-academy/learning-history',
method: 'GET',
params: { courseId }
})
},
// 提交课程评价
submitReview(data) {
return request({
url: '/api/parent-academy/submit-review',
method: 'POST',
data
})
}
}
📄 2. 改造 my-courses.vue 页面
2.1 增强课程卡片显示
在课程卡片中添加学习进度条:
<template>
<view class="course-card" @tap="viewCourse(course)">
<!-- 现有内容 -->
<!-- 新增: 学习进度条 -->
<view class="progress-section" v-if="course.learningRecord">
<view class="progress-bar">
<view
class="progress-fill"
:style="{ width: course.learningRecord.learningProgress + '%' }"
></view>
</view>
<view class="progress-info">
<text class="progress-text">
学习进度: {{ course.learningRecord.learningProgress }}%
</text>
<text class="points-text" v-if="course.learningRecord.pointsAwarded > 0">
已获得 {{ course.learningRecord.pointsAwarded }} 积分
</text>
</view>
</view>
<!-- 新增: 完成标记 -->
<view class="completed-badge" v-if="course.learningRecord && course.learningRecord.isCompleted">
<text class="badge-icon">✓</text>
<text class="badge-text">已完成</text>
</view>
</view>
</template>
<script>
export default {
methods: {
async loadMyCourses() {
// ... 现有代码 ...
// 转换数据格式时添加学习记录
this.courseList = list.map(item => {
const purchase = item.purchase || item
const course = item.course || item
const learningRecord = item.learningRecord || null
return {
// ... 现有字段 ...
learningRecord: learningRecord ? {
id: learningRecord.id,
learningProgress: learningRecord.learningProgress || 0,
lastPosition: learningRecord.lastPosition || 0,
isCompleted: learningRecord.isCompleted || 0,
pointsAwarded: learningRecord.pointsAwarded || 0,
notes: learningRecord.notes || ''
} : null
}
})
}
}
}
</script>
<style scoped>
/* 学习进度条样式 */
.progress-section {
margin-top: 20rpx;
padding-top: 20rpx;
border-top: 1rpx solid #f0f0f0;
}
.progress-bar {
width: 100%;
height: 8rpx;
background: #f0f0f0;
border-radius: 4rpx;
overflow: hidden;
margin-bottom: 15rpx;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
border-radius: 4rpx;
transition: width 0.3s;
}
.progress-info {
display: flex;
justify-content: space-between;
align-items: center;
}
.progress-text {
font-size: 24rpx;
color: #666666;
}
.points-text {
font-size: 24rpx;
color: #ff6b6b;
font-weight: 500;
}
/* 完成标记样式 */
.completed-badge {
position: absolute;
top: 20rpx;
right: 20rpx;
display: flex;
align-items: center;
gap: 8rpx;
padding: 8rpx 16rpx;
background: linear-gradient(135deg, #66bb6a 0%, #43a047 100%);
border-radius: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(67, 160, 71, 0.3);
}
.badge-icon {
font-size: 24rpx;
color: #ffffff;
font-weight: bold;
}
.badge-text {
font-size: 22rpx;
color: #ffffff;
font-weight: 500;
}
</style>
📺 3. 创建课程学习页面
创建 peidu/uniapp/src/user-package/pages/course/player.vue:
<template>
<view class="course-player-page">
<!-- 视频播放器 -->
<video
v-if="course.videoUrl"
:src="course.videoUrl"
:initial-time="lastPosition"
class="video-player"
controls
@timeupdate="onTimeUpdate"
@ended="onVideoEnded"
></video>
<!-- 课程信息 -->
<view class="course-info">
<text class="course-title">{{ course.title }}</text>
<view class="course-meta">
<text class="meta-item">时长: {{ course.duration }}分钟</text>
<text class="meta-item">进度: {{ learningProgress }}%</text>
</view>
</view>
<!-- 学习笔记 -->
<view class="notes-section">
<text class="section-title">学习笔记</text>
<textarea
v-model="notes"
class="notes-input"
placeholder="记录你的学习心得..."
maxlength="500"
></textarea>
<text class="notes-count">{{ notes.length }}/500</text>
</view>
<!-- 完成按钮 -->
<view class="action-section">
<button
class="btn-complete"
:disabled="learningProgress < 90"
@tap="completeLearning"
>
{{ learningProgress >= 90 ? '完成学习' : '请观看至少90%的内容' }}
</button>
</view>
</view>
</template>
<script>
import api from '@/api/index.js'
export default {
data() {
return {
courseId: null,
purchaseId: null,
learningRecordId: null,
course: {},
lastPosition: 0,
learningProgress: 0,
notes: '',
currentPosition: 0,
duration: 0,
updateTimer: null
}
},
onLoad(options) {
this.courseId = options.id
this.purchaseId = options.purchaseId
this.loadCourseData()
},
onUnload() {
// 页面卸载时保存进度
this.saveProgress()
if (this.updateTimer) {
clearInterval(this.updateTimer)
}
},
methods: {
async loadCourseData() {
try {
// 获取课程信息
const courseData = await api.parentAcademyApi.getCourseDetail(this.courseId)
this.course = courseData
// 开始学习,获取学习记录
const learningData = await api.parentAcademyApi.startLearning({
courseId: this.courseId,
purchaseId: this.purchaseId
})
this.learningRecordId = learningData.learningRecordId
this.lastPosition = learningData.lastPosition || 0
this.learningProgress = learningData.learningProgress || 0
// 启动定时保存进度(每30秒)
this.updateTimer = setInterval(() => {
this.saveProgress()
}, 30000)
} catch (error) {
console.error('加载课程数据失败:', error)
uni.showToast({
title: '加载失败',
icon: 'none'
})
}
},
onTimeUpdate(e) {
this.currentPosition = Math.floor(e.detail.currentTime)
this.duration = Math.floor(e.detail.duration)
// 计算进度
if (this.duration > 0) {
this.learningProgress = Math.floor((this.currentPosition / this.duration) * 100)
}
},
async saveProgress() {
if (!this.learningRecordId || this.currentPosition === 0) {
return
}
try {
await api.parentAcademyApi.updateProgress({
learningRecordId: this.learningRecordId,
position: this.currentPosition,
duration: this.duration
})
console.log('学习进度已保存:', this.currentPosition)
} catch (error) {
console.error('保存进度失败:', error)
}
},
onVideoEnded() {
// 视频播放完成
this.learningProgress = 100
this.saveProgress()
},
async completeLearning() {
if (this.learningProgress < 90) {
uni.showToast({
title: '请观看至少90%的内容',
icon: 'none'
})
return
}
try {
uni.showLoading({ title: '提交中...' })
const result = await api.parentAcademyApi.completeLearning({
learningRecordId: this.learningRecordId,
notes: this.notes
})
uni.hideLoading()
// 显示积分奖励
if (result.pointsAwarded > 0) {
uni.showModal({
title: '恭喜完成学习!',
content: `获得 ${result.pointsAwarded} 积分奖励`,
showCancel: false,
success: () => {
// 返回我的课程页面
uni.navigateBack()
}
})
} else {
uni.showToast({
title: '学习完成',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
} catch (error) {
uni.hideLoading()
console.error('完成学习失败:', error)
uni.showToast({
title: '提交失败',
icon: 'none'
})
}
}
}
}
</script>
<style scoped>
.course-player-page {
min-height: 100vh;
background: #f5f7fa;
}
.video-player {
width: 100%;
height: 420rpx;
}
.course-info {
background: #ffffff;
padding: 30rpx;
margin-bottom: 20rpx;
}
.course-title {
display: block;
font-size: 32rpx;
font-weight: 500;
color: #333333;
margin-bottom: 20rpx;
}
.course-meta {
display: flex;
gap: 30rpx;
}
.meta-item {
font-size: 26rpx;
color: #666666;
}
.notes-section {
background: #ffffff;
padding: 30rpx;
margin-bottom: 20rpx;
}
.section-title {
display: block;
font-size: 28rpx;
font-weight: 500;
color: #333333;
margin-bottom: 20rpx;
}
.notes-input {
width: 100%;
min-height: 200rpx;
padding: 20rpx;
background: #f5f7fa;
border-radius: 8rpx;
font-size: 26rpx;
line-height: 1.6;
}
.notes-count {
display: block;
text-align: right;
font-size: 24rpx;
color: #999999;
margin-top: 10rpx;
}
.action-section {
padding: 30rpx;
}
.btn-complete {
width: 100%;
height: 88rpx;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #ffffff;
font-size: 30rpx;
border-radius: 44rpx;
border: none;
}
.btn-complete[disabled] {
background: #cccccc;
color: #999999;
}
</style>
🔄 4. 修改课程跳转逻辑
在 my-courses.vue 中修改 viewCourse 方法:
viewCourse(course) {
console.log('查看课程:', course)
// 跳转到课程学习页面
uni.navigateTo({
url: `/user-package/pages/course/player?id=${course.id}&purchaseId=${course.purchaseId}`
})
}
✅ 完成后的功能
- 断点续播 - 自动从上次学习位置继续
- 进度保存 - 每30秒自动保存学习进度
- 学习笔记 - 支持记录学习心得
- 积分奖励 - 完成学习后自动发放积分
- 进度可视化 - 实时显示学习进度百分比