feat(teacher/taskHomePage): 改进日历组件功能并优化样式
- 添加月份切换时获取打卡日期的功能 - 优化日历日期格式化逻辑,支持显示已打卡状态 - 调整日历弹窗高度和确认按钮显示 - 新增日历选中日期样式和今日标记 - 修复附件类型显示换行问题
Showing
1 changed file
with
77 additions
and
26 deletions
| 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-12-12 18:11:45 | 4 | + * @LastEditTime: 2025-12-13 21:24:23 |
| 5 | * @FilePath: /mlaj/src/views/teacher/taskHomePage.vue | 5 | * @FilePath: /mlaj/src/views/teacher/taskHomePage.vue |
| 6 | * @Description: 教师端作业主页(头部介绍、统计、日历与学生完成情况;数据Mock) | 6 | * @Description: 教师端作业主页(头部介绍、统计、日历与学生完成情况;数据Mock) |
| 7 | --> | 7 | --> |
| ... | @@ -29,7 +29,8 @@ | ... | @@ -29,7 +29,8 @@ |
| 29 | <div class="detailItem">频次:{{ task_details.frequency }}</div> | 29 | <div class="detailItem">频次:{{ task_details.frequency }}</div> |
| 30 | <div v-if="task_details.begin_date" class="detailItem">开始时间:{{ task_details.begin_date }}</div> | 30 | <div v-if="task_details.begin_date" class="detailItem">开始时间:{{ task_details.begin_date }}</div> |
| 31 | <div v-if="task_details.end_date" class="detailItem">截止时间:{{ task_details.end_date }}</div> | 31 | <div v-if="task_details.end_date" class="detailItem">截止时间:{{ task_details.end_date }}</div> |
| 32 | - <div v-if="task_details.attachment_type.length" class="detailItem">附件类型:{{ task_details.attachment_type }}</div> | 32 | + <div v-if="task_details.attachment_type.length" class="detailItem">附件类型:{{ task_details.attachment_type |
| 33 | + }}</div> | ||
| 33 | <div v-if="task_type === 'checkin'" class="detailItem">类型:打卡签到</div> | 34 | <div v-if="task_type === 'checkin'" class="detailItem">类型:打卡签到</div> |
| 34 | </div> | 35 | </div> |
| 35 | </div> | 36 | </div> |
| ... | @@ -88,20 +89,15 @@ | ... | @@ -88,20 +89,15 @@ |
| 88 | <!-- <div class="mt-3 text-sm text-gray-600">当前选择:{{ current_date_text }}</div> --> | 89 | <!-- <div class="mt-3 text-sm text-gray-600">当前选择:{{ current_date_text }}</div> --> |
| 89 | <!-- 日历弹窗:点击“某个日期”弹出 --> | 90 | <!-- 日历弹窗:点击“某个日期”弹出 --> |
| 90 | <van-config-provider :theme-vars="themeVars"> | 91 | <van-config-provider :theme-vars="themeVars"> |
| 91 | - <van-calendar v-model:show="show_calendar_popup" :default-date="calendar_default_date" color="#10b981" | 92 | + <van-calendar v-model:show="show_calendar_popup" :default-date="calendar_default_date" color="#4caf50" |
| 92 | - :show-confirm="true" switch-mode="month" :formatter="formatter" @confirm="on_date_select" /> | 93 | + :show-confirm="false" switch-mode="month" :formatter="formatter" @select="on_date_select" @panel-change="onPanelChange" /> |
| 93 | </van-config-provider> | 94 | </van-config-provider> |
| 94 | </div> | 95 | </div> |
| 95 | 96 | ||
| 96 | <!-- 小作业选择弹窗 --> | 97 | <!-- 小作业选择弹窗 --> |
| 97 | <van-popup v-model:show="show_subtask_picker" position="bottom" round> | 98 | <van-popup v-model:show="show_subtask_picker" position="bottom" round> |
| 98 | - <van-picker | 99 | + <van-picker :columns="subtask_columns" @confirm="on_confirm_subtask" @cancel="show_subtask_picker = false" |
| 99 | - :columns="subtask_columns" | 100 | + show-toolbar title="选择作业" /> |
| 100 | - @confirm="on_confirm_subtask" | ||
| 101 | - @cancel="show_subtask_picker = false" | ||
| 102 | - show-toolbar | ||
| 103 | - title="选择作业" | ||
| 104 | - /> | ||
| 105 | </van-popup> | 101 | </van-popup> |
| 106 | 102 | ||
| 107 | <!-- 学生完成情况(参考图片2样式) --> | 103 | <!-- 学生完成情况(参考图片2样式) --> |
| ... | @@ -132,6 +128,7 @@ import { useRoute, useRouter } from 'vue-router' | ... | @@ -132,6 +128,7 @@ import { useRoute, useRouter } from 'vue-router' |
| 132 | import { useTitle } from '@vueuse/core' | 128 | import { useTitle } from '@vueuse/core' |
| 133 | import checkCorner from '@/assets/images/dui.png' | 129 | import checkCorner from '@/assets/images/dui.png' |
| 134 | import { getTeacherTaskDetailAPI } from '@/api/teacher' | 130 | import { getTeacherTaskDetailAPI } from '@/api/teacher' |
| 131 | +import { getCheckinTeacherCheckedDatesAPI } from '@/api/checkin' | ||
| 135 | import dayjs from 'dayjs' | 132 | import dayjs from 'dayjs' |
| 136 | 133 | ||
| 137 | const $route = useRoute() | 134 | const $route = useRoute() |
| ... | @@ -139,7 +136,7 @@ const $router = useRouter() | ... | @@ -139,7 +136,7 @@ const $router = useRouter() |
| 139 | useTitle('作业主页') | 136 | useTitle('作业主页') |
| 140 | 137 | ||
| 141 | const themeVars = { | 138 | const themeVars = { |
| 142 | - calendarPopupHeight: '60%', | 139 | + calendarPopupHeight: '55%', |
| 143 | } | 140 | } |
| 144 | 141 | ||
| 145 | // 弹窗显示状态:是否展示“某个日期”选择日历 | 142 | // 弹窗显示状态:是否展示“某个日期”选择日历 |
| ... | @@ -178,29 +175,49 @@ function select_yesterday() { | ... | @@ -178,29 +175,49 @@ function select_yesterday() { |
| 178 | calendar_default_date.value = null | 175 | calendar_default_date.value = null |
| 179 | } | 176 | } |
| 180 | 177 | ||
| 178 | +const currentMonth = ref(dayjs().format('YYYY-MM')); | ||
| 179 | +const selectedDate = ref(dayjs().format('YYYY-MM-DD')); | ||
| 180 | + | ||
| 181 | /** | 181 | /** |
| 182 | * 日历日期格式化函数 | 182 | * 日历日期格式化函数 |
| 183 | * @param {Object} day - 日历天对象 | 183 | * @param {Object} day - 日历天对象 |
| 184 | * @returns {Object} 处理后的日历天对象 | 184 | * @returns {Object} 处理后的日历天对象 |
| 185 | */ | 185 | */ |
| 186 | const formatter = (day) => { | 186 | const formatter = (day) => { |
| 187 | - const dateStr = format_date(day.date) | 187 | + const year = day.date.getFullYear(); |
| 188 | - const today = new Date() | 188 | + const month = day.date.getMonth() + 1; |
| 189 | - const todayStr = format_date(today) | 189 | + const date = day.date.getDate(); |
| 190 | - | 190 | + |
| 191 | - const yesterday = new Date(today) | 191 | + let checkin_days = myCheckinDates.value; |
| 192 | - yesterday.setDate(today.getDate() - 1) | 192 | + |
| 193 | - const yesterdayStr = format_date(yesterday) | 193 | + // 检查当前日期是否在签到日期列表中 |
| 194 | + if (checkin_days && checkin_days.length > 0) { | ||
| 195 | + // 格式化当前日期为YYYY-MM-DD格式,与checkin_days中的格式匹配 | ||
| 196 | + const formattedDate = `${year}-${month.toString().padStart(2, '0')}-${date.toString().padStart(2, '0')}`; | ||
| 197 | + | ||
| 198 | + // 检查是否已打卡 | ||
| 199 | + if (checkin_days.includes(formattedDate)) { | ||
| 200 | + // 如果是当前选中的已打卡日期,使用特殊样式 | ||
| 201 | + if (selectedDate.value === formattedDate) { | ||
| 202 | + day.className = 'calendar-selected'; | ||
| 203 | + day.type = 'selected'; | ||
| 204 | + day.bottomInfo = '已打卡'; | ||
| 205 | + } else { | ||
| 206 | + day.className = 'calendar-checkin'; | ||
| 207 | + day.type = 'selected'; | ||
| 208 | + day.bottomInfo = '已打卡'; | ||
| 209 | + } | ||
| 210 | + } | ||
| 211 | + } | ||
| 194 | 212 | ||
| 195 | - if (dateStr === todayStr) { | 213 | + // 选中今天的日期 |
| 214 | + if (dayjs(day.date).isSame(new Date(), 'day')) { | ||
| 196 | day.className = 'calendar-today'; | 215 | day.className = 'calendar-today'; |
| 197 | - day.bottomInfo = '今日' | 216 | + day.type = 'selected'; |
| 198 | - } else if (dateStr === yesterdayStr) { | 217 | + day.bottomInfo = '今日'; |
| 199 | - day.className = 'calendar-yesterday'; | ||
| 200 | - day.bottomInfo = '昨日' | ||
| 201 | } | 218 | } |
| 202 | 219 | ||
| 203 | - return day | 220 | + return day; |
| 204 | } | 221 | } |
| 205 | 222 | ||
| 206 | /** | 223 | /** |
| ... | @@ -263,6 +280,7 @@ const on_confirm_subtask = ({ selectedOptions }) => { | ... | @@ -263,6 +280,7 @@ const on_confirm_subtask = ({ selectedOptions }) => { |
| 263 | if (selectedOptions && selectedOptions[0]) { | 280 | if (selectedOptions && selectedOptions[0]) { |
| 264 | selectedSubtaskId.value = selectedOptions[0].value | 281 | selectedSubtaskId.value = selectedOptions[0].value |
| 265 | fetchData() | 282 | fetchData() |
| 283 | + getCheckedDates(dayjs().format('YYYY-MM')); | ||
| 266 | } | 284 | } |
| 267 | show_subtask_picker.value = false | 285 | show_subtask_picker.value = false |
| 268 | } | 286 | } |
| ... | @@ -339,8 +357,23 @@ watch(selected_date, () => { | ... | @@ -339,8 +357,23 @@ watch(selected_date, () => { |
| 339 | fetchData() | 357 | fetchData() |
| 340 | }) | 358 | }) |
| 341 | 359 | ||
| 360 | +const myCheckinDates = ref([]); | ||
| 361 | + | ||
| 362 | +// 获取用户打卡日期的函数 | ||
| 363 | +const getCheckedDates = async (month) => { | ||
| 364 | + const checkedDatesResult = await getCheckinTeacherCheckedDatesAPI({ | ||
| 365 | + id: task_id, | ||
| 366 | + subtask_id: selectedSubtaskId.value, | ||
| 367 | + month | ||
| 368 | + }); | ||
| 369 | + if (checkedDatesResult.code) { | ||
| 370 | + myCheckinDates.value = checkedDatesResult.data.my_checkin_dates; | ||
| 371 | + } | ||
| 372 | +} | ||
| 373 | + | ||
| 342 | onMounted(() => { | 374 | onMounted(() => { |
| 343 | fetchData() | 375 | fetchData() |
| 376 | + getCheckedDates(dayjs().format('YYYY-MM')); | ||
| 344 | }) | 377 | }) |
| 345 | 378 | ||
| 346 | /** | 379 | /** |
| ... | @@ -391,6 +424,12 @@ function on_date_select(val) { | ... | @@ -391,6 +424,12 @@ function on_date_select(val) { |
| 391 | calendar_default_date.value = is_date_obj ? val : parse_date_text(text) | 424 | calendar_default_date.value = is_date_obj ? val : parse_date_text(text) |
| 392 | } | 425 | } |
| 393 | 426 | ||
| 427 | +// 切换月份时触发 | ||
| 428 | +const onPanelChange = ({ date }) => { | ||
| 429 | + currentMonth.value = dayjs(date).format('YYYY-MM'); | ||
| 430 | + getCheckedDates(currentMonth.value); | ||
| 431 | +} | ||
| 432 | + | ||
| 394 | /** | 433 | /** |
| 395 | * 计算某日期下学生完成情况列表 | 434 | * 计算某日期下学生完成情况列表 |
| 396 | * @returns {{id:string,name:string,completed:boolean}[]} 学生状态列表 | 435 | * @returns {{id:string,name:string,completed:boolean}[]} 学生状态列表 |
| ... | @@ -438,7 +477,7 @@ function go_student_record(stu) { | ... | @@ -438,7 +477,7 @@ function go_student_record(stu) { |
| 438 | } | 477 | } |
| 439 | </script> | 478 | </script> |
| 440 | 479 | ||
| 441 | -<style lang="less" scoped> | 480 | +<style lang="less"> |
| 442 | .TaskHomePage { | 481 | .TaskHomePage { |
| 443 | min-height: 100vh; | 482 | min-height: 100vh; |
| 444 | background: linear-gradient(to bottom right, #f0fdf4, #f0fdfa, #eff6ff); | 483 | background: linear-gradient(to bottom right, #f0fdf4, #f0fdfa, #eff6ff); |
| ... | @@ -507,4 +546,16 @@ function go_student_record(stu) { | ... | @@ -507,4 +546,16 @@ function go_student_record(stu) { |
| 507 | } | 546 | } |
| 508 | } | 547 | } |
| 509 | } | 548 | } |
| 549 | + | ||
| 550 | +.calendar-checkin { | ||
| 551 | + .van-calendar__selected-day { | ||
| 552 | + background: #a2d8a3 !important; | ||
| 553 | + } | ||
| 554 | +} | ||
| 555 | + | ||
| 556 | +.calendar-today { | ||
| 557 | + .van-calendar__selected-day { | ||
| 558 | + background: #FAAB0C !important; | ||
| 559 | + } | ||
| 560 | +} | ||
| 510 | </style> | 561 | </style> | ... | ... |
-
Please register or login to post a comment