hookehuyr

feat(教师端): 实现作业管理和学生记录功能

- 在教师端添加作业管理页面,支持分页加载作业列表
- 实现作业详情页面,展示作业信息和学生完成情况
- 修改学生记录页面,从URL获取用户ID和日期参数
- 添加相关API接口用于获取作业列表和详情
- 移除Mock数据,使用真实API获取数据
1 ### 1 ###
2 # @Date: 2025-03-20 23:40:15 2 # @Date: 2025-03-20 23:40:15
3 # @LastEditors: hookehuyr hookehuyr@gmail.com 3 # @LastEditors: hookehuyr hookehuyr@gmail.com
4 - # @LastEditTime: 2025-09-30 15:45:25 4 + # @LastEditTime: 2025-12-02 18:34:41
5 # @FilePath: /mlaj/.env.development 5 # @FilePath: /mlaj/.env.development
6 # @Description: 文件描述 6 # @Description: 文件描述
7 ### 7 ###
......
1 /* 1 /*
2 * @Date: 2025-06-06 09:26:16 2 * @Date: 2025-06-06 09:26:16
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-11-17 14:33:59 4 + * @LastEditTime: 2025-12-01 14:06:29
5 * @FilePath: /mlaj/src/api/checkin.js 5 * @FilePath: /mlaj/src/api/checkin.js
6 * @Description: 签到模块相关接口 6 * @Description: 签到模块相关接口
7 */ 7 */
...@@ -113,6 +113,7 @@ export const dislikeUploadTaskInfoAPI = (params) => fn(fetch.post(Api.TASK_UPLO ...@@ -113,6 +113,7 @@ export const dislikeUploadTaskInfoAPI = (params) => fn(fetch.post(Api.TASK_UPLO
113 * @param group_id 课程ID 113 * @param group_id 课程ID
114 * @param team_id 大分组ID 114 * @param team_id 大分组ID
115 * @param subteam_id 小分组ID 115 * @param subteam_id 小分组ID
116 + * @param created_by 学员ID
116 * @param date 日期 117 * @param date 日期
117 * @param keyword 搜索 118 * @param keyword 搜索
118 * @param order_by_time asc=正序,desc=倒序。默认为倒序 119 * @param order_by_time asc=正序,desc=倒序。默认为倒序
......
1 /* 1 /*
2 * @Date: 2025-06-23 11:46:21 2 * @Date: 2025-06-23 11:46:21
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-11-10 10:56:17 4 + * @LastEditTime: 2025-12-01 14:13:18
5 * @FilePath: /mlaj/src/api/teacher.js 5 * @FilePath: /mlaj/src/api/teacher.js
6 * @Description: 文件描述 6 * @Description: 文件描述
7 */ 7 */
...@@ -11,6 +11,8 @@ const Api = { ...@@ -11,6 +11,8 @@ const Api = {
11 TEACHER_GRADE_CLASS_LIST: '/srv/?a=user&t=teacher_grade_class_group_list', 11 TEACHER_GRADE_CLASS_LIST: '/srv/?a=user&t=teacher_grade_class_group_list',
12 TEACHER_FIND_SETTINGS: '/srv/?a=task&t=teacher_find_settings', 12 TEACHER_FIND_SETTINGS: '/srv/?a=task&t=teacher_find_settings',
13 TEACHER_ADD_TASK: '/srv/?a=task&t=teacher_add', 13 TEACHER_ADD_TASK: '/srv/?a=task&t=teacher_add',
14 + TEACHER_LIST_TASK: '/srv/?a=task&t=teacher_list',
15 + TEACHER_DETAIL_TASK: '/srv/?a=task&t=teacher_detail',
14 STUDENT_LIST: '/srv/?a=user&t=student_list', 16 STUDENT_LIST: '/srv/?a=user&t=student_list',
15 STUDENT_DETAIL: '/srv/?a=user&t=student_detail', 17 STUDENT_DETAIL: '/srv/?a=user&t=student_detail',
16 STUDENT_STAT: '/srv/?a=user&t=student_stat', 18 STUDENT_STAT: '/srv/?a=user&t=student_stat',
...@@ -56,6 +58,47 @@ export const getTeacherFindSettingsAPI = (params) => fn(fetch.get(Api.TEACHER_FI ...@@ -56,6 +58,47 @@ export const getTeacherFindSettingsAPI = (params) => fn(fetch.get(Api.TEACHER_FI
56 export const setTeacherTaskAPI = (params) => fn(fetch.post(Api.TEACHER_ADD_TASK, params)) 58 export const setTeacherTaskAPI = (params) => fn(fetch.post(Api.TEACHER_ADD_TASK, params))
57 59
58 /** 60 /**
61 + * 获取老师的作业列表
62 + * @param {*} group_id 课程ID
63 + * @param {*} team_id 大分组ID
64 + * @param {*} subteam_id 小分组ID
65 + * @param {*} limit 条数 100
66 + * @param {*} page 页码 0
67 + * @returns {Object} data {
68 + * id integer 作业id
69 + * title string 作业名称
70 + * cycle string 作业周期 0=本周期 30=每月 7=每周 1=每日
71 + * frequency integer 每周期交作业的次数
72 + * attachment_type array[string] 提交类型 text=文本 image=图片 video=视频 audio=音频
73 + * begin_date string 开始时间
74 + * end_date number 结束时间
75 + * task_type string 任务类型 checkin=签到 file=上传附件
76 + * }
77 + */
78 +export const getTeacherTaskListAPI = (params) => fn(fetch.get(Api.TEACHER_LIST_TASK, params))
79 +
80 +/**
81 + * 获取老师的作业详情
82 + * @param {*} id 作业ID
83 + * @param {*} date 日期。默认是今天 示例值: [""]
84 + * @returns {Object} data {
85 + * id integer 作业id
86 + * begin_date string 开始时间
87 + * end_date string 结束时间
88 + * task_type string 任务类型 checkin=签到 file=上传附件
89 + * title string 作业名称
90 + * cycle string 作业周期 0=本周期 30=每月 7=每周 1=每日
91 + * frequency integer 每周期交作业的次数
92 + * attachment_type array[string] 提交类型 text=文本 image=图片 video=视频 audio=音频
93 + * note string 作业描述
94 + * need_commit_count integer 需要提交次数
95 + * real_commit_count integer 已提交次数
96 + * user_list [{id 用户ID, name 姓名, avatar 头像, is_commit 是否提交了作业}]
97 + * }
98 + */
99 +export const getTeacherTaskDetailAPI = (params) => fn(fetch.get(Api.TEACHER_DETAIL_TASK, params))
100 +
101 +/**
59 * 获取学员列表 102 * 获取学员列表
60 * @param {*} grade_id 年级ID 103 * @param {*} grade_id 年级ID
61 * @param {*} class_id 班级ID 104 * @param {*} class_id 班级ID
......
1 <!-- 1 <!--
2 * @Date: 2025-11-19 22:05:00 2 * @Date: 2025-11-19 22:05:00
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-11-19 22:12:24 4 + * @LastEditTime: 2025-12-02 18:44:51
5 * @FilePath: /mlaj/src/views/teacher/studentRecordPage.vue 5 * @FilePath: /mlaj/src/views/teacher/studentRecordPage.vue
6 * @Description: 学生作业记录页面(仅作业记录与点评功能),固定 user_id 与 group_id 6 * @Description: 学生作业记录页面(仅作业记录与点评功能),固定 user_id 与 group_id
7 --> 7 -->
...@@ -120,16 +120,16 @@ import { useTitle } from '@vueuse/core' ...@@ -120,16 +120,16 @@ import { useTitle } from '@vueuse/core'
120 import { showSuccessToast, showFailToast, showLoadingToast } from 'vant' 120 import { showSuccessToast, showFailToast, showLoadingToast } from 'vant'
121 import VideoPlayer from '@/components/ui/VideoPlayer.vue' 121 import VideoPlayer from '@/components/ui/VideoPlayer.vue'
122 import AudioPlayer from '@/components/ui/AudioPlayer.vue' 122 import AudioPlayer from '@/components/ui/AudioPlayer.vue'
123 -import { getStudentUploadListAPI, addCheckinFeedbackAPI } from '@/api/teacher' 123 +import { addCheckinFeedbackAPI } from '@/api/teacher'
124 -import { likeUploadTaskInfoAPI, dislikeUploadTaskInfoAPI } from '@/api/checkin' 124 +import { likeUploadTaskInfoAPI, dislikeUploadTaskInfoAPI, getCheckinTeacherListAPI } from '@/api/checkin'
125 125
126 const $route = useRoute() 126 const $route = useRoute()
127 const $router = useRouter() 127 const $router = useRouter()
128 useTitle($route.meta.title) 128 useTitle($route.meta.title)
129 129
130 -// 固定的用户与班级ID 130 +// 从url获取固定的用户与班级ID
131 -const fixedUserId = 817017 131 +const fixedUserId = Number($route.query.created_by)
132 -const fixedGroupId = 816653 132 +const fixedDate = $route.query.date
133 133
134 // 列表相关状态 134 // 列表相关状态
135 const checkinDataList = ref([]) 135 const checkinDataList = ref([])
...@@ -401,15 +401,15 @@ function stopAllVideos() { ...@@ -401,15 +401,15 @@ function stopAllVideos() {
401 */ 401 */
402 async function onLoad() { 402 async function onLoad() {
403 const nextPage = page.value 403 const nextPage = page.value
404 - const res = await getStudentUploadListAPI({ 404 + const res = await getCheckinTeacherListAPI({
405 limit: limit.value, 405 limit: limit.value,
406 page: nextPage, 406 page: nextPage,
407 - user_id: fixedUserId, 407 + created_by: fixedUserId,
408 - group_id: fixedGroupId, 408 + date: fixedDate,
409 }) 409 })
410 if (res.code) { 410 if (res.code) {
411 - checkinDataList.value = [...checkinDataList.value, ...formatData(res.data)] 411 + checkinDataList.value = [...checkinDataList.value, ...formatData(res.data.checkin_list)]
412 - finished.value = res.data.length < limit.value 412 + finished.value = res.data.checkin_list.length < limit.value
413 page.value = nextPage + 1 413 page.value = nextPage + 1
414 } 414 }
415 loading.value = false 415 loading.value = false
......
1 <!-- 1 <!--
2 * @Date: 2025-11-19 21:00:00 2 * @Date: 2025-11-19 21:00:00
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-11-21 16:19:23 4 + * @LastEditTime: 2025-12-02 18:48:32
5 * @FilePath: /mlaj/src/views/teacher/taskHomePage.vue 5 * @FilePath: /mlaj/src/views/teacher/taskHomePage.vue
6 * @Description: 教师端作业主页(头部介绍、统计、日历与学生完成情况;数据Mock) 6 * @Description: 教师端作业主页(头部介绍、统计、日历与学生完成情况;数据Mock)
7 --> 7 -->
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
10 <!-- 头部卡片:名称、介绍、细项(参考图片1结构) --> 10 <!-- 头部卡片:名称、介绍、细项(参考图片1结构) -->
11 <div class="headCard bg-white rounded-lg shadow px-4 py-4"> 11 <div class="headCard bg-white rounded-lg shadow px-4 py-4">
12 <div class="title text-2xl font-bold text-gray-900 mb-2">{{ task_title }}</div> 12 <div class="title text-2xl font-bold text-gray-900 mb-2">{{ task_title }}</div>
13 - <div class="intro text-base text-gray-700 leading-relaxed mb-3">{{ task_intro }}</div> 13 + <div class="intro text-base text-gray-700 leading-relaxed mb-3" v-html="task_intro"></div>
14 <!-- 三图展示(可选),使用CDN示例地址并加压缩参数 --> 14 <!-- 三图展示(可选),使用CDN示例地址并加压缩参数 -->
15 <!-- <div class="images grid grid-cols-3 gap-3 mb-3"> 15 <!-- <div class="images grid grid-cols-3 gap-3 mb-3">
16 <img v-for="(img, idx) in task_images" :key="idx" :src="img" 16 <img v-for="(img, idx) in task_images" :key="idx" :src="img"
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
28 <div class="statsCard bg-white rounded-lg shadow px-4 py-4 mt-4"> 28 <div class="statsCard bg-white rounded-lg shadow px-4 py-4 mt-4">
29 <van-row gutter="16"> 29 <van-row gutter="16">
30 <!-- 出勤率 --> 30 <!-- 出勤率 -->
31 - <van-col span="12"> 31 + <!-- <van-col span="12">
32 <div class="text-center"> 32 <div class="text-center">
33 <div class="relative w-16 h-16 mx-auto mb-2"> 33 <div class="relative w-16 h-16 mx-auto mb-2">
34 <van-circle v-model:current-rate="checkin_count" :rate="checkin_count" :text="checkin_text" 34 <van-circle v-model:current-rate="checkin_count" :rate="checkin_count" :text="checkin_text"
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
36 </div> 36 </div>
37 <div class="text-sm text-gray-600">出勤率</div> 37 <div class="text-sm text-gray-600">出勤率</div>
38 </div> 38 </div>
39 - </van-col> 39 + </van-col> -->
40 <!-- 任务完成 --> 40 <!-- 任务完成 -->
41 <van-col span="12"> 41 <van-col span="12">
42 <div class="text-center"> 42 <div class="text-center">
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
84 <!-- 学生完成情况(参考图片2样式) --> 84 <!-- 学生完成情况(参考图片2样式) -->
85 <div class="studentsCard bg-white rounded-lg shadow px-4 py-4 mt-4"> 85 <div class="studentsCard bg-white rounded-lg shadow px-4 py-4 mt-4">
86 <div class="flex items-center justify-between mb-3"> 86 <div class="flex items-center justify-between mb-3">
87 - <div class="text-base font-semibold text-gray-800">完成情况({{ completed_count }}/{{ students.length }}) 87 + <div class="text-base font-semibold text-gray-800">完成情况({{ completed_count }}/{{ user_list.length }})
88 </div> 88 </div>
89 <!-- <div class="text-xs text-gray-500">当前日期:{{ current_date_text }}</div> --> 89 <!-- <div class="text-xs text-gray-500">当前日期:{{ current_date_text }}</div> -->
90 <div class="text-xs text-gray-500">点击查看作业记录</div> 90 <div class="text-xs text-gray-500">点击查看作业记录</div>
...@@ -104,10 +104,11 @@ ...@@ -104,10 +104,11 @@
104 </template> 104 </template>
105 105
106 <script setup> 106 <script setup>
107 -import { ref, computed } from 'vue' 107 +import { ref, computed, onMounted, watch } from 'vue'
108 import { useRoute, useRouter } from 'vue-router' 108 import { useRoute, useRouter } from 'vue-router'
109 import { useTitle } from '@vueuse/core' 109 import { useTitle } from '@vueuse/core'
110 import checkCorner from '@/assets/images/dui.png' 110 import checkCorner from '@/assets/images/dui.png'
111 +import { getTeacherTaskDetailAPI } from '@/api/teacher'
111 112
112 const $route = useRoute() 113 const $route = useRoute()
113 const $router = useRouter() 114 const $router = useRouter()
...@@ -157,63 +158,106 @@ function open_specific_date_picker() { ...@@ -157,63 +158,106 @@ function open_specific_date_picker() {
157 } 158 }
158 159
159 // 160 //
160 -// Mock:作业基础信息 161 +// API 数据状态
161 // 162 //
162 const task_id = $route.params.id || '0' 163 const task_id = $route.params.id || '0'
163 -const task_title = ref('组长每日共修打卡内容') 164 +const task_title = ref('')
164 -const task_intro = ref('组长与副组长以上每日语音打卡内容:《义工宣言》《万事如意祈请文》《吉祥圆满感恩文》') 165 +const task_intro = ref('')
166 +// 图片暂时保留 Mock 或从 API 扩展字段获取(当前 API 未返回图片列表,暂时保留为空或 Mock)
165 const task_images = ref([ 167 const task_images = ref([
166 'https://cdn.ipadbiz.cn/mlaj/demo-task-1.png?imageMogr2/thumbnail/200x/strip/quality/70', 168 'https://cdn.ipadbiz.cn/mlaj/demo-task-1.png?imageMogr2/thumbnail/200x/strip/quality/70',
167 'https://cdn.ipadbiz.cn/mlaj/demo-task-2.png?imageMogr2/thumbnail/200x/strip/quality/70', 169 'https://cdn.ipadbiz.cn/mlaj/demo-task-2.png?imageMogr2/thumbnail/200x/strip/quality/70',
168 'https://cdn.ipadbiz.cn/mlaj/demo-task-3.png?imageMogr2/thumbnail/200x/strip/quality/70' 170 'https://cdn.ipadbiz.cn/mlaj/demo-task-3.png?imageMogr2/thumbnail/200x/strip/quality/70'
169 ]) 171 ])
170 const task_details = ref({ 172 const task_details = ref({
171 - cycle: '每天', 173 + cycle: '',
172 - frequency: '每日一次', 174 + frequency: '',
173 - time_range: '00:00 ~ 23:59', 175 + time_range: '',
174 - attachment_type: '语音/文本' 176 + attachment_type: ''
175 }) 177 })
176 178
177 // 179 //
178 -// Mock:统计数据 180 +// 统计数据
179 // 181 //
180 -const checkin_count = ref(56) 182 +const checkin_count = ref(0)
181 -const upload_count = ref(62) 183 +const upload_count = ref(0)
182 const checkin_text = computed(() => `${checkin_count.value}%`) 184 const checkin_text = computed(() => `${checkin_count.value}%`)
183 const upload_text = computed(() => `${upload_count.value}%`) 185 const upload_text = computed(() => `${upload_count.value}%`)
184 186
185 // 187 //
186 -// Mock:学生与完成记录 188 +// 学生与完成记录
187 -// 注:每个学生给出若干已完成的日期字符串(YYYY-MM-DD)
188 // 189 //
189 const today = new Date() 190 const today = new Date()
190 const selected_date = ref(format_date(today)) 191 const selected_date = ref(format_date(today))
191 -const students = ref([ 192 +const user_list = ref([])
192 - { id: '1', name: '王菲', completed_dates: ['2025-11-18', selected_date.value] }, 193 +
193 - { id: '2', name: '朱明献', completed_dates: ['2025-11-18'] }, 194 +/**
194 - { id: '3', name: '陈小云', completed_dates: [] }, 195 + * 获取作业详情和学生完成情况
195 - { id: '4', name: '冯新虎', completed_dates: [selected_date.value] }, 196 + */
196 - { id: '5', name: '罗睿', completed_dates: ['2025-11-17', '2025-11-18'] }, 197 +async function fetchData() {
197 - { id: '6', name: '吴绍婷', completed_dates: [] }, 198 + try {
198 - { id: '7', name: '焦淑敏', completed_dates: [selected_date.value] }, 199 + const res = await getTeacherTaskDetailAPI({
199 - { id: '8', name: '李言斐', completed_dates: [] }, 200 + id: task_id,
200 - { id: '9', name: '陈正统', completed_dates: [] }, 201 + date: selected_date.value
201 - { id: '10', name: '杨子娟', completed_dates: [] }, 202 + })
202 - { id: '11', name: '方萍', completed_dates: [selected_date.value] }, 203 +
203 - { id: '12', name: '冯静', completed_dates: [selected_date.value] }, 204 + if (res.code) {
204 - { id: '13', name: '尤瑞', completed_dates: [] }, 205 + task_title.value = res.data.title
205 - { id: '14', name: '鲁镇伟', completed_dates: [] }, 206 + task_intro.value = res.data.note
206 - { id: '15', name: '黄润', completed_dates: [selected_date.value] }, 207 +
207 - { id: '16', name: '王亚琼', completed_dates: [selected_date.value] }, 208 + // 格式化周期显示
208 - { id: '17', name: '高晓云', completed_dates: [selected_date.value] }, 209 + const cycleMap = {
209 - { id: '18', name: '张朗', completed_dates: [] }, 210 + '0': '本周期',
210 - { id: '19', name: '姚娟', completed_dates: [selected_date.value] }, 211 + '30': '每月',
211 - { id: '20', name: '李凯', completed_dates: [selected_date.value] }, 212 + '7': '每周',
212 - { id: '21', name: '李鑫', completed_dates: [] }, 213 + '1': '每日' // 假设 1 代表每日
213 - { id: '22', name: '礼忠斌', completed_dates: [] }, 214 + }
214 - { id: '23', name: '谭小梅', completed_dates: [selected_date.value] }, 215 + // 如果后端返回的是数字字符串,尝试映射,否则直接显示
215 - { id: '24', name: '赵红梅', completed_dates: [] } 216 + const cycleText = cycleMap[res.data.cycle] || res.data.cycle || '每日'
216 -]) 217 +
218 + // 格式化附件类型
219 + let attachmentText = '文本'
220 + if (Array.isArray(res.data.attachment_type)) {
221 + const typeMap = {
222 + 'text': '文本',
223 + 'image': '图片',
224 + 'video': '视频',
225 + 'audio': '音频'
226 + }
227 + attachmentText = res.data.attachment_type.map(t => typeMap[t] || t).join('/')
228 + } else if (res.data.attachment_type) {
229 + attachmentText = res.data.attachment_type
230 + }
231 +
232 + task_details.value = {
233 + cycle: cycleText,
234 + frequency: `每周期${res.data.frequency || 1}次`,
235 + time_range: `${res.data.begin_date || '00:00'} ~ ${res.data.end_date || '23:59'}`, // 注意:API返回的begin_date/end_date可能是日期也可能是时间,这里暂且直接展示
236 + attachment_type: attachmentText
237 + }
238 +
239 + user_list.value = res.data.user_list || []
240 +
241 + // 计算完成率
242 + if (res.data.need_commit_count > 0) {
243 + upload_count.value = Math.round((res.data.real_commit_count / res.data.need_commit_count) * 100)
244 + } else {
245 + upload_count.value = 0
246 + }
247 + }
248 + } catch (error) {
249 + console.error('Failed to fetch task details:', error)
250 + }
251 +}
252 +
253 +// 监听日期变化,重新获取数据
254 +watch(selected_date, () => {
255 + fetchData()
256 +})
257 +
258 +onMounted(() => {
259 + fetchData()
260 +})
217 261
218 /** 262 /**
219 * 将日期对象格式化为 YYYY-MM-DD 263 * 将日期对象格式化为 YYYY-MM-DD
...@@ -266,13 +310,13 @@ function on_date_select(val) { ...@@ -266,13 +310,13 @@ function on_date_select(val) {
266 /** 310 /**
267 * 计算某日期下学生完成情况列表 311 * 计算某日期下学生完成情况列表
268 * @returns {{id:string,name:string,completed:boolean}[]} 学生状态列表 312 * @returns {{id:string,name:string,completed:boolean}[]} 学生状态列表
269 - * 注释:根据 selected_date 在每个学生的 completed_dates 中判断是否完成。
270 */ 313 */
271 const students_status = computed(() => { 314 const students_status = computed(() => {
272 - return students.value.map(stu => ({ 315 + return user_list.value.map(stu => ({
273 id: stu.id, 316 id: stu.id,
274 name: stu.name, 317 name: stu.name,
275 - completed: stu.completed_dates.includes(selected_date.value) 318 + completed: !!stu.is_commit,
319 + avatar: stu.avatar // 保留头像字段以便将来使用
276 })) 320 }))
277 }) 321 })
278 322
...@@ -295,7 +339,7 @@ const current_date_text = computed(() => selected_date.value) ...@@ -295,7 +339,7 @@ const current_date_text = computed(() => selected_date.value)
295 */ 339 */
296 function go_student_record(stu) { 340 function go_student_record(stu) {
297 // 跳转到固定ID的作业记录页面,当前版本不使用传入ID 341 // 跳转到固定ID的作业记录页面,当前版本不使用传入ID
298 - $router.push({ name: 'StudentRecord' }) 342 + $router.push({ name: 'StudentRecord', query: { created_by: stu.id, date: selected_date.value } })
299 } 343 }
300 </script> 344 </script>
301 345
......
1 <!-- 1 <!--
2 * @Date: 2025-11-19 10:18:00 2 * @Date: 2025-11-19 10:18:00
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-11-19 20:25:40 4 + * @LastEditTime: 2025-12-01 14:30:47
5 * @FilePath: /mlaj/src/views/teacher/taskManagePage.vue 5 * @FilePath: /mlaj/src/views/teacher/taskManagePage.vue
6 - * @Description: 教师端作业管理页面(列表展示作业名称与开始/截止时间,数据先Mock) 6 + * @Description: 教师端作业管理页面
7 --> 7 -->
8 <template> 8 <template>
9 <div class="TaskManagePage"> 9 <div class="TaskManagePage">
10 - <!-- 页面头部 -->
11 - <!-- <div class="pageHeader bg-white rounded-lg shadow px-4 py-3">
12 - <div class="flex items-center justify-between">
13 - <div class="title text-base font-semibold text-gray-800">作业管理</div>
14 - </div>
15 - </div> -->
16 -
17 <!-- 作业列表 --> 10 <!-- 作业列表 -->
11 + <van-list
12 + v-model:loading="loading"
13 + :finished="finished"
14 + finished-text="没有更多了"
15 + @load="onLoad"
16 + >
18 <div class="listWrapper mt-4"> 17 <div class="listWrapper mt-4">
19 <div v-for="task in task_list" :key="task.id" class="taskItem bg-white rounded-lg shadow px-4 py-3 mb-3"> 18 <div v-for="task in task_list" :key="task.id" class="taskItem bg-white rounded-lg shadow px-4 py-3 mb-3">
20 <div class="flex items-center justify-between"> 19 <div class="flex items-center justify-between">
...@@ -34,32 +33,61 @@ ...@@ -34,32 +33,61 @@
34 </div> 33 </div>
35 </div> 34 </div>
36 </div> 35 </div>
36 + </van-list>
37 </div> 37 </div>
38 -
39 - <!--
40 - 页面说明:
41 - - 列表项显示作业名称与开始/截止时间,样式参考项目统一风格(白卡片+阴影+圆角)。
42 - - 数据暂用Mock,后续可替换为真实API。
43 - -->
44 </template> 38 </template>
45 39
46 <script setup> 40 <script setup>
47 import { ref } from 'vue' 41 import { ref } from 'vue'
48 import { useRoute, useRouter } from 'vue-router' 42 import { useRoute, useRouter } from 'vue-router'
49 import { useTitle } from '@vueuse/core' 43 import { useTitle } from '@vueuse/core'
44 +import { getTeacherTaskListAPI } from '@/api/teacher'
50 45
51 const $route = useRoute() 46 const $route = useRoute()
52 const $router = useRouter() 47 const $router = useRouter()
53 useTitle($route.meta.title) 48 useTitle($route.meta.title)
54 49
55 -// 50 +// 分页状态
56 -// Mock数据:作业列表 51 +const loading = ref(false)
57 -// 52 +const finished = ref(false)
58 -const task_list = ref([ 53 +const page = ref(0)
59 - { id: '101', title: '英语口语练习', begin_date: '2025-11-01', end_date: '2025-11-30' }, 54 +const limit = 10
60 - { id: '102', title: '语文古诗背诵', begin_date: '2025-11-05', end_date: '2025-11-25' }, 55 +
61 - { id: '103', title: '数学口算巩固', begin_date: '2025-11-10', end_date: '2025-12-10' } 56 +// 作业列表数据
62 -]) 57 +const task_list = ref([])
58 +
59 +/**
60 + * 加载列表数据
61 + */
62 +const onLoad = async () => {
63 + try {
64 + const params = {
65 + page: page.value,
66 + limit: limit
67 + }
68 + const res = await getTeacherTaskListAPI(params)
69 +
70 + // 假设接口返回的数据是数组,如果是 { data: [] } 结构请调整
71 + const list = Array.isArray(res) ? res.data : (res.data || [])
72 +
73 + if (list.length > 0) {
74 + task_list.value.push(...list)
75 + page.value++
76 + }
77 +
78 + // 加载状态结束
79 + loading.value = false
80 +
81 + // 数据全部加载完成
82 + if (list.length < limit) {
83 + finished.value = true
84 + }
85 + } catch (error) {
86 + console.error('获取作业列表失败', error)
87 + loading.value = false
88 + finished.value = true
89 + }
90 +}
63 91
64 /** 92 /**
65 * 格式化日期范围 93 * 格式化日期范围
......