hookehuyr

feat(teacher/taskHomePage): 改进日历组件功能并优化样式

- 添加月份切换时获取打卡日期的功能
- 优化日历日期格式化逻辑,支持显示已打卡状态
- 调整日历弹窗高度和确认按钮显示
- 新增日历选中日期样式和今日标记
- 修复附件类型显示换行问题
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>
......