feat(教师端): 实现作业管理和学生记录功能
- 在教师端添加作业管理页面,支持分页加载作业列表 - 实现作业详情页面,展示作业信息和学生完成情况 - 修改学生记录页面,从URL获取用户ID和日期参数 - 添加相关API接口用于获取作业列表和详情 - 移除Mock数据,使用真实API获取数据
Showing
6 changed files
with
201 additions
and
85 deletions
| 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 | * 格式化日期范围 | ... | ... |
-
Please register or login to post a comment