|
|
@@ -1,116 +1,96 @@
|
|
|
<template>
|
|
|
<view class="course-detail-page">
|
|
|
- <!-- 课程信息 -->
|
|
|
+ <!-- 课程介绍 -->
|
|
|
<view class="course-head">
|
|
|
<text class="course-level">{{ course.level || 'L' }}</text>
|
|
|
<text class="course-name">{{ course.name }}</text>
|
|
|
<text class="course-status" :class="'st-' + course.effectiveStatus">{{ statusLabel(course.effectiveStatus) }}</text>
|
|
|
<text class="course-desc" v-if="course.description">{{ course.description }}</text>
|
|
|
+ <text class="course-time" v-if="course.startTime || course.endTime">
|
|
|
+ 开课 {{ fmtDate(course.startTime) }} · 结课 {{ fmtDate(course.endTime) }}
|
|
|
+ </text>
|
|
|
<text class="course-class" v-if="className">我的班次:{{ className }}</text>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 报名/参加课程操作区 -->
|
|
|
- <view class="action-card" v-if="enrollmentStatus !== 'confirmed'">
|
|
|
- <!-- 未报名 -->
|
|
|
- <template v-if="enrollmentStatus === 'none'">
|
|
|
- <text class="action-title">报名参加本课程</text>
|
|
|
- <text class="action-desc">填写报名信息并支付后即可申请进班学习</text>
|
|
|
- <button class="action-btn" @click="goTo('/pages/enroll/list')">去报名</button>
|
|
|
- </template>
|
|
|
- <!-- 待支付 -->
|
|
|
- <template v-else-if="enrollmentStatus === 'pending'">
|
|
|
- <text class="action-title">报名待支付</text>
|
|
|
- <text class="action-desc">完成支付后即可申请进班</text>
|
|
|
- <button class="action-btn" @click="goTo('/pages/enroll/list')">去支付</button>
|
|
|
- </template>
|
|
|
- <!-- 已支付待进班 -->
|
|
|
- <template v-else-if="enrollmentStatus === 'paid'">
|
|
|
- <text class="action-title">已报名,待进班</text>
|
|
|
- <text class="action-desc">提交进班申请后由班主任审核,审核通过即可开始学习</text>
|
|
|
- <button class="action-btn" :disabled="enterLoading" @click="applyEnter">申请进班</button>
|
|
|
- </template>
|
|
|
- <!-- 审核中 -->
|
|
|
- <template v-else-if="enrollmentStatus === 'reviewing'">
|
|
|
- <text class="action-title">进班审核中</text>
|
|
|
- <text class="action-desc">班主任正在审核你的进班申请,请耐心等待</text>
|
|
|
- <button class="action-btn disabled" disabled>审核中</button>
|
|
|
- </template>
|
|
|
- <!-- 已驳回 -->
|
|
|
- <template v-else-if="enrollmentStatus === 'rejected'">
|
|
|
- <text class="action-title">进班申请被驳回</text>
|
|
|
- <text class="action-desc">可重新提交进班申请,或联系班主任了解原因</text>
|
|
|
- <button class="action-btn" :disabled="enterLoading" @click="applyEnter">重新申请进班</button>
|
|
|
- </template>
|
|
|
+ <!-- 未报名:先报名 -->
|
|
|
+ <view class="action-card" v-if="enrollmentStatus === 'none'">
|
|
|
+ <text class="action-title">报名参加本课程</text>
|
|
|
+ <text class="action-desc">填写报名信息并完成支付后,即可申请进班学习</text>
|
|
|
+ <button class="action-btn" @click="goTo('/pages/enroll/list')">去报名</button>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 学习进度 -->
|
|
|
- <view class="section-card" v-if="enrollmentStatus === 'confirmed'">
|
|
|
- <view class="section-head">
|
|
|
- <text class="section-title">学习进度</text>
|
|
|
- <text class="progress-count">{{ progress.done }}/{{ progress.total }} 项完成</text>
|
|
|
- </view>
|
|
|
- <view class="progress-bar">
|
|
|
- <view class="progress-fill" :style="{ width: progressPercent }"></view>
|
|
|
- </view>
|
|
|
- <view class="progress-list">
|
|
|
- <view class="progress-item" v-for="(it, idx) in progress.items" :key="idx">
|
|
|
- <text class="progress-icon" :class="{ done: it.ok }">{{ it.ok ? '✅' : '⬜' }}</text>
|
|
|
- <text class="progress-label">{{ it.label }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
+ <!-- 已报名未进班 -->
|
|
|
+ <view class="action-card" v-else-if="enrollmentStatus === 'pending'">
|
|
|
+ <text class="action-title">报名待支付</text>
|
|
|
+ <text class="action-desc">完成支付后即可申请进班</text>
|
|
|
+ <button class="action-btn" @click="goTo('/pages/enroll/list')">去支付</button>
|
|
|
+ </view>
|
|
|
+ <view class="action-card" v-else-if="enrollmentStatus === 'paid'">
|
|
|
+ <text class="action-title">已报名,待进班</text>
|
|
|
+ <text class="action-desc">提交进班申请后由班主任审核,审核通过即可开始学习</text>
|
|
|
+ <button class="action-btn" :disabled="enterLoading" @click="applyEnter">申请进班</button>
|
|
|
+ </view>
|
|
|
+ <view class="action-card" v-else-if="enrollmentStatus === 'reviewing'">
|
|
|
+ <text class="action-title">进班审核中</text>
|
|
|
+ <text class="action-desc">班主任正在审核你的进班申请,请耐心等待</text>
|
|
|
+ <button class="action-btn disabled" disabled>审核中</button>
|
|
|
+ </view>
|
|
|
+ <view class="action-card" v-else-if="enrollmentStatus === 'rejected'">
|
|
|
+ <text class="action-title">进班申请被驳回</text>
|
|
|
+ <text class="action-desc">可重新提交进班申请,或联系班主任了解原因</text>
|
|
|
+ <button class="action-btn" :disabled="enterLoading" @click="applyEnter">重新申请进班</button>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 课程内功能入口 -->
|
|
|
- <view v-if="enrollmentStatus === 'confirmed'">
|
|
|
- <view class="section-title">课程内容</view>
|
|
|
- <view class="nav-grid">
|
|
|
- <view class="nav-item" @click="goTo('/pages/material/index')">
|
|
|
- <text class="nav-icon">📄</text>
|
|
|
- <text class="nav-text">课前资料</text>
|
|
|
- </view>
|
|
|
- <view class="nav-item" @click="goTo('/pages/group/index')">
|
|
|
- <text class="nav-icon">👥</text>
|
|
|
- <text class="nav-text">我的小组</text>
|
|
|
- </view>
|
|
|
- <view class="nav-item" @click="switchToTab('/pages/checkin/index')">
|
|
|
- <text class="nav-icon">✅</text>
|
|
|
- <text class="nav-text">装机打卡</text>
|
|
|
- </view>
|
|
|
- <view class="nav-item" @click="goTo('/pages/upload/index')">
|
|
|
- <text class="nav-icon">📤</text>
|
|
|
- <text class="nav-text">成果上传</text>
|
|
|
- </view>
|
|
|
- <view class="nav-item" @click="goTo('/pages/teaching/index')">
|
|
|
- <text class="nav-icon">📝</text>
|
|
|
- <text class="nav-text">教学卡</text>
|
|
|
- </view>
|
|
|
- <view class="nav-item" @click="goTo('/pages/roadmap/index')">
|
|
|
- <text class="nav-icon">🎤</text>
|
|
|
- <text class="nav-text">路演材料</text>
|
|
|
- </view>
|
|
|
- <view class="nav-item" @click="goTo('/pages/vote/index')">
|
|
|
- <text class="nav-icon">🗳️</text>
|
|
|
- <text class="nav-text">路演投票</text>
|
|
|
+ <!-- 已进班:按课程前/中/后阶段显示要做的事 -->
|
|
|
+ <template v-if="enrollmentStatus === 'confirmed'">
|
|
|
+ <!-- 课程前:课前准备 -->
|
|
|
+ <view class="stage-card" v-if="stage === 'upcoming'">
|
|
|
+ <text class="stage-icon">📅</text>
|
|
|
+ <view class="stage-text">
|
|
|
+ <text class="stage-title">课程即将开课</text>
|
|
|
+ <text class="stage-sub">先完成课前准备,做好学习规划</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <view class="nav-item" @click="goTo('/pages/scoreboard/index')">
|
|
|
- <text class="nav-icon">🏆</text>
|
|
|
- <text class="nav-text">积分榜</text>
|
|
|
+ <!-- 课程中:学习进度 -->
|
|
|
+ <view class="section-card" v-if="stage === 'active'">
|
|
|
+ <view class="section-head">
|
|
|
+ <text class="section-title">学习进度</text>
|
|
|
+ <text class="progress-count">{{ progress.done }}/{{ progress.total }} 项完成</text>
|
|
|
+ </view>
|
|
|
+ <view class="progress-bar">
|
|
|
+ <view class="progress-fill" :style="{ width: progressPercent }"></view>
|
|
|
+ </view>
|
|
|
+ <view class="progress-list">
|
|
|
+ <view class="progress-item" v-for="(it, idx) in progress.items" :key="idx">
|
|
|
+ <text class="progress-icon" :class="{ done: it.ok }">{{ it.ok ? '✅' : '⬜' }}</text>
|
|
|
+ <text class="progress-label">{{ it.label }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <view class="nav-item" @click="goTo('/pages/plan/index')">
|
|
|
- <text class="nav-icon">📅</text>
|
|
|
- <text class="nav-text">行动计划</text>
|
|
|
+ <!-- 课程后:结业事项 -->
|
|
|
+ <view class="stage-card" v-if="stage === 'finished'">
|
|
|
+ <text class="stage-icon">🎉</text>
|
|
|
+ <view class="stage-text">
|
|
|
+ <text class="stage-title">课程已结束</text>
|
|
|
+ <text class="stage-sub">完成结业事项,收获学习成果</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <view class="nav-item" @click="goTo('/pages/assignment/index')">
|
|
|
- <text class="nav-icon">📋</text>
|
|
|
- <text class="nav-text">三本账</text>
|
|
|
+
|
|
|
+ <!-- 本阶段要做的事 -->
|
|
|
+ <view class="stage-title-block">本阶段要做的事</view>
|
|
|
+ <view class="nav-grid">
|
|
|
+ <view class="nav-item" v-for="(g, idx) in stageMenus" :key="idx" @click="onMenu(g)">
|
|
|
+ <text class="nav-icon">{{ g.icon }}</text>
|
|
|
+ <text class="nav-text">{{ g.text }}</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
+ </template>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import { getMyCourse, getCourseProgress, enterCourse } from '@/utils/api.js'
|
|
|
+import { formatDateTime } from '@/utils/format.js'
|
|
|
|
|
|
export default {
|
|
|
data() {
|
|
|
@@ -129,18 +109,56 @@ export default {
|
|
|
var pct = Math.round((this.progress.done || 0) * 100 / total)
|
|
|
return pct + '%'
|
|
|
},
|
|
|
+ // 课程所处阶段:upcoming(前) / active(中) / finished(后) / draft
|
|
|
+ stage() {
|
|
|
+ return this.course.effectiveStatus || 'active'
|
|
|
+ },
|
|
|
enrollmentStatus() {
|
|
|
if (!this.enrollment || !this.enrollment.status) return 'none'
|
|
|
return this.enrollment.status
|
|
|
+ },
|
|
|
+ stageMenus() {
|
|
|
+ if (this.stage === 'upcoming') {
|
|
|
+ // 课程前:课前准备
|
|
|
+ return [
|
|
|
+ { icon: '📄', text: '课前资料', url: '/pages/material/index' },
|
|
|
+ { icon: '📝', text: '兴趣调研', url: '/pages/survey/index' },
|
|
|
+ { icon: '📅', text: '行动计划', url: '/pages/plan/index' },
|
|
|
+ { icon: '👥', text: '我的小组', url: '/pages/group/index' }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ if (this.stage === 'finished') {
|
|
|
+ // 课程后:结业事项
|
|
|
+ return [
|
|
|
+ { icon: '📋', text: '三本账', url: '/pages/assignment/index' },
|
|
|
+ { icon: '📅', text: '行动计划', url: '/pages/plan/index' },
|
|
|
+ { icon: '🏆', text: '积分榜', url: '/pages/scoreboard/index' },
|
|
|
+ { icon: '🗳️', text: '路演投票', url: '/pages/vote/index' }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ // 课程中:学习内容
|
|
|
+ return [
|
|
|
+ { icon: '📄', text: '课前资料', url: '/pages/material/index' },
|
|
|
+ { icon: '👥', text: '我的小组', url: '/pages/group/index' },
|
|
|
+ { icon: '✅', text: '装机打卡', url: '/pages/checkin/index', tab: true },
|
|
|
+ { icon: '📤', text: '成果上传', url: '/pages/upload/index' },
|
|
|
+ { icon: '📝', text: '教学卡', url: '/pages/teaching/index' },
|
|
|
+ { icon: '🎤', text: '路演材料', url: '/pages/roadmap/index' },
|
|
|
+ { icon: '🗳️', text: '路演投票', url: '/pages/vote/index' },
|
|
|
+ { icon: '🏆', text: '积分榜', url: '/pages/scoreboard/index' },
|
|
|
+ { icon: '📅', text: '行动计划', url: '/pages/plan/index' },
|
|
|
+ { icon: '📋', text: '三本账', url: '/pages/assignment/index' }
|
|
|
+ ]
|
|
|
}
|
|
|
},
|
|
|
- onLoad() {
|
|
|
+ onLoad(options) {
|
|
|
+ this.courseId = (options && options.courseId) || ''
|
|
|
this.loadAll()
|
|
|
},
|
|
|
methods: {
|
|
|
loadAll() {
|
|
|
var self = this
|
|
|
- getMyCourse().then(function(resp) {
|
|
|
+ getMyCourse(self.courseId).then(function(resp) {
|
|
|
var d = resp.data || {}
|
|
|
var c = d.course || {}
|
|
|
self.course = c
|
|
|
@@ -156,6 +174,14 @@ export default {
|
|
|
}
|
|
|
}).catch(function() {})
|
|
|
},
|
|
|
+ onMenu(g) {
|
|
|
+ if (!g) return
|
|
|
+ if (g.tab) {
|
|
|
+ uni.switchTab({ url: g.url })
|
|
|
+ } else {
|
|
|
+ uni.navigateTo({ url: g.url })
|
|
|
+ }
|
|
|
+ },
|
|
|
applyEnter() {
|
|
|
var self = this
|
|
|
if (!self.course.id) return
|
|
|
@@ -194,11 +220,12 @@ export default {
|
|
|
var map = { upcoming: '未开始', active: '进行中', finished: '已结束', draft: '未发布' }
|
|
|
return map[st] || st || '-'
|
|
|
},
|
|
|
+ fmtDate(v) {
|
|
|
+ if (!v) return '-'
|
|
|
+ return formatDateTime(v)
|
|
|
+ },
|
|
|
goTo(url) {
|
|
|
uni.navigateTo({ url: url })
|
|
|
- },
|
|
|
- switchToTab(url) {
|
|
|
- uni.switchTab({ url: url })
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -220,8 +247,17 @@ export default {
|
|
|
.course-status.st-active { color: #22C55E; background: #F0FDF4; }
|
|
|
.course-status.st-finished { color: #94A3B8; background: #F1F5F9; }
|
|
|
.course-desc { font-size: 26rpx; color: #64748B; line-height: 1.6; margin-bottom: 8rpx; }
|
|
|
+.course-time { font-size: 24rpx; color: #94A3B8; margin-bottom: 8rpx; }
|
|
|
.course-class { font-size: 24rpx; color: #1E293B; background: #F1F5F9; border-radius: 8rpx; padding: 8rpx 16rpx; align-self: flex-start; }
|
|
|
|
|
|
+.stage-card { display: flex; align-items: center; background: #FFF; border-radius: 16rpx; padding: 28rpx 32rpx; margin-bottom: 24rpx; }
|
|
|
+.stage-icon { font-size: 48rpx; margin-right: 20rpx; }
|
|
|
+.stage-text { display: flex; flex-direction: column; }
|
|
|
+.stage-title { font-size: 30rpx; font-weight: 700; color: #1E293B; margin-bottom: 6rpx; }
|
|
|
+.stage-sub { font-size: 24rpx; color: #64748B; }
|
|
|
+
|
|
|
+.stage-title-block { font-size: 30rpx; font-weight: 600; color: #1E293B; margin-bottom: 16rpx; border-left: 8rpx solid #F97316; padding-left: 16rpx; }
|
|
|
+
|
|
|
.section-card { background: #FFF; border-radius: 16rpx; padding: 28rpx; margin-bottom: 24rpx; }
|
|
|
.section-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16rpx; }
|
|
|
.section-title { font-size: 30rpx; font-weight: 600; color: #1E293B; border-left: 8rpx solid #F97316; padding-left: 16rpx; }
|