JoinCheckInPage.vue
7.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
<!--
* @Date: 2025-11-17 13:42:00
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-11-17 14:22:00
* @FilePath: /mlaj/src/views/checkin/JoinCheckInPage.vue
* @Description: 文件描述
-->
<template>
<AppLayout :hasTitle="false">
<div class="join-check-in-page">
<!-- 头部课程信息 -->
<div class="joinHeader bg-white rounded-lg shadow px-4 py-3">
<div class="flex flex-col">
<van-image
height="8rem"
fit="cover"
:src="mock_task_info.course_cover_url"
class="rounded-lg"
/>
<div class="mt-3 text-center">
<div class="courseTitle text-base font-semibold text-gray-800">{{ mock_task_info.course_title }}</div>
<div class="teacher flex items-center mt-1 justify-center">
<van-image
round
width="1.4rem"
height="1.4rem"
fit="cover"
:src="mock_task_info.teacher_avatar"
/>
<span class="ml-2 text-sm text-gray-700">{{ mock_task_info.teacher_name }}</span>
</div>
<div class="schedule text-xs text-gray-500 mt-1">{{ mock_task_info.schedule_desc }}</div>
</div>
</div>
</div>
<!-- 作业信息 -->
<div class="infoCard bg-white rounded-lg shadow mt-4">
<div class="cardHeader px-4 py-3 border-b border-gray-100">
<div class="cardTitle text-sm font-semibold text-gray-800">作业信息</div>
</div>
<div class="cardBody px-4 py-3 space-y-2">
<div class="infoItem flex justify-between text-sm">
<div class="label text-gray-500">作业名称</div>
<div class="value text-gray-800">{{ mock_task_info.task_title }}</div>
</div>
<div class="infoItem flex justify-between text-sm">
<div class="label text-gray-500">所属班级</div>
<div class="value text-gray-800">{{ mock_task_info.grade_name }} · {{ mock_task_info.class_name }}</div>
</div>
<div class="infoItem flex justify-between text-sm">
<div class="label text-gray-500">目标次数</div>
<div class="value text-gray-800">{{ mock_task_info.target_number }} 次</div>
</div>
<div class="infoItem flex justify-between text-sm">
<div class="label text-gray-500">起止时间</div>
<div class="value text-gray-800">{{ mock_task_info.period_desc }}</div>
</div>
<div class="infoItem flex justify-between text-sm">
<div class="label text-gray-500">报名截止</div>
<div class="value text-gray-800">{{ mock_task_info.join_deadline_desc }}</div>
</div>
</div>
</div>
<!-- 作业说明 -->
<div class="infoCard bg-white rounded-lg shadow mt-4">
<div class="cardHeader px-4 py-3 border-b border-gray-100">
<div class="cardTitle text-sm font-semibold text-gray-800">作业说明</div>
</div>
<div class="cardBody px-4 py-3">
<div class="text-sm text-gray-700 leading-6 whitespace-pre-line">{{ mock_task_info.task_desc }}</div>
</div>
</div>
<!-- 加入按钮 -->
<div class="joinAction p-4 bg-gradient-to-t from-white/95 to-white/20">
<van-button type="primary" round block class="h-11 text-base font-semibold" @click="on_join_click">
加入该作业
</van-button>
</div>
</div>
</AppLayout>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useTitle } from "@vueuse/core";
import { showConfirmDialog } from 'vant'
import AppLayout from '@/components/layout/AppLayout.vue'
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
// Mock数据:课程与作业信息
const mock_task_info = ref({
course_title: '英语口语提升营',
course_cover_url: 'https://cdn.ipadbiz.cn/mlaj/images/cover_video_2.png?imageMogr2/thumbnail/200x/strip/quality/70',
teacher_name: '王老师',
teacher_avatar: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg?imageMogr2/thumbnail/200x/strip/quality/70',
schedule_desc: '每周二、周四晚 19:00-20:00',
grade_name: '五年级',
class_name: '二班',
task_title: '本周作业:日常口语练习',
task_desc: '请完成3次日常口语练习打卡,每次不少于60秒,可上传音频或视频。',
target_number: 3,
period_desc: '2025-11-01 至 2025-11-30',
join_deadline_desc: '2025-11-20 23:59',
})
// 目标打卡页作业ID(无真实数据前默认写死)
const target_checkin_id = ref('833668')
/**
* 载入页面Mock数据
* @returns {void}
* 注释:此处预留真实接口接入位置,当前为静态Mock。
*/
const load_mock_data = () => {
// 预留:后续可根据 $route.query.id 拉取真实数据并映射
}
/**
* 点击加入作业的处理
* @returns {Promise<void>}
* 注释:弹出确认框,确认后跳转到打卡页。
*/
const on_join_click = async () => {
try {
await showConfirmDialog({
title: '确认加入',
message: '是否确认加入该作业?加入后可前往打卡页进行每日打卡。',
confirmButtonColor: '#4caf50',
})
// 确认后跳转到打卡页
$router.push({
path: '/checkin/index',
query: {
id: target_checkin_id.value,
}
})
} catch (err) {
// 用户取消
}
}
onMounted(() => {
load_mock_data()
})
</script>
<style lang="less" scoped>
.join-check-in-page {
min-height: 100vh;
background: linear-gradient(to bottom right, #f0fdf4, #f0fdfa, #eff6ff);
padding: 1rem;
padding-bottom: 6rem;
.joinHeader {
.courseTitle {
line-height: 1.4;
}
.teacher {
.name {
color: #4caf50;
}
}
}
.infoCard {
.cardHeader {
.cardTitle {
color: #4caf50;
}
}
.cardBody {
.infoItem {
.label {
color: #6b7280;
}
.value {
color: #111827;
}
}
}
}
.joinAction {
box-shadow: 0 -6px 12px rgba(0,0,0,0.06);
}
}
</style>