feat(日历组件): 添加作业筛选功能并优化交互
- 在日历组件中新增作业筛选功能,支持按课程类型筛选 - 调整日历折叠状态的点击区域和布局 - 移除部分未使用的样式代码 - 添加作业选择弹窗及相关事件处理
Showing
2 changed files
with
111 additions
and
17 deletions
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-01-25 15:34:17 | 2 | * @Date: 2025-01-25 15:34:17 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-11-13 20:03:33 | 4 | + * @LastEditTime: 2025-12-11 09:31:06 |
| 5 | * @FilePath: /mlaj/src/components/ui/CollapsibleCalendar.vue | 5 | * @FilePath: /mlaj/src/components/ui/CollapsibleCalendar.vue |
| 6 | * @Description: 可折叠日历组件 | 6 | * @Description: 可折叠日历组件 |
| 7 | --> | 7 | --> |
| 8 | <template> | 8 | <template> |
| 9 | <div class="collapsible-calendar "> | 9 | <div class="collapsible-calendar "> |
| 10 | <!-- 折叠状态显示 --> | 10 | <!-- 折叠状态显示 --> |
| 11 | - <div v-if="!isExpanded" class="calendar-collapsed" @click="expandCalendar"> | 11 | + <div v-if="!isExpanded" class="calendar-collapsed"> |
| 12 | <div class="calendar-header"> | 12 | <div class="calendar-header"> |
| 13 | <div class="calendar-icon"> | 13 | <div class="calendar-icon"> |
| 14 | <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | 14 | <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| ... | @@ -16,9 +16,13 @@ | ... | @@ -16,9 +16,13 @@ |
| 16 | <path d="M7 10H9V12H7V10ZM11 10H13V12H11V10ZM15 10H17V12H15V10Z" fill="#4caf50"/> | 16 | <path d="M7 10H9V12H7V10ZM11 10H13V12H11V10ZM15 10H17V12H15V10Z" fill="#4caf50"/> |
| 17 | </svg> | 17 | </svg> |
| 18 | </div> | 18 | </div> |
| 19 | - <div class="calendar-title-wrapper"> | 19 | + <!-- <div class="calendar-date-display"> |
| 20 | + <div class="calendar-date-main">{{ formattedCurrentDate }}</div> | ||
| 21 | + <div class="calendar-weekday">{{ formattedWeekday }}</div> | ||
| 22 | + </div> --> | ||
| 23 | + <div class="calendar-title-wrapper" @click="expandCalendar"> | ||
| 20 | <div class="calendar-title">{{ title }}</div> | 24 | <div class="calendar-title">{{ title }}</div> |
| 21 | - <div class="calendar-subtitle">点击选择日期</div> | 25 | + <div class="calendar-subtitle">点击切换日期</div> |
| 22 | </div> | 26 | </div> |
| 23 | </div> | 27 | </div> |
| 24 | <div class="calendar-content"> | 28 | <div class="calendar-content"> |
| ... | @@ -26,13 +30,24 @@ | ... | @@ -26,13 +30,24 @@ |
| 26 | <div class="calendar-date-main">{{ formattedCurrentDate }}</div> | 30 | <div class="calendar-date-main">{{ formattedCurrentDate }}</div> |
| 27 | <div class="calendar-weekday">{{ formattedWeekday }}</div> | 31 | <div class="calendar-weekday">{{ formattedWeekday }}</div> |
| 28 | </div> | 32 | </div> |
| 29 | - <div class="calendar-action"> | 33 | + <!-- <div class="calendar-action"> |
| 30 | <div class="calendar-action-text">指定日期</div> | 34 | <div class="calendar-action-text">指定日期</div> |
| 31 | <div class="calendar-arrow"> | 35 | <div class="calendar-arrow"> |
| 32 | <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | 36 | <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 33 | <path d="M7 10L12 15L17 10H7Z" fill="#4caf50"/> | 37 | <path d="M7 10L12 15L17 10H7Z" fill="#4caf50"/> |
| 34 | </svg> | 38 | </svg> |
| 35 | </div> | 39 | </div> |
| 40 | + </div> --> | ||
| 41 | + <div class="calendar-actions-wrapper"> | ||
| 42 | + <!-- 作业筛选 --> | ||
| 43 | + <div class="calendar-action course-filter" @click.stop="openCoursePicker"> | ||
| 44 | + <div class="calendar-action-text">{{ selectedCourseText }}</div> | ||
| 45 | + <div class="calendar-arrow"> | ||
| 46 | + <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 47 | + <path d="M7 10L12 15L17 10H7Z" fill="#4caf50"/> | ||
| 48 | + </svg> | ||
| 49 | + </div> | ||
| 50 | + </div> | ||
| 36 | </div> | 51 | </div> |
| 37 | </div> | 52 | </div> |
| 38 | </div> | 53 | </div> |
| ... | @@ -61,6 +76,23 @@ | ... | @@ -61,6 +76,23 @@ |
| 61 | </van-calendar> | 76 | </van-calendar> |
| 62 | </div> | 77 | </div> |
| 63 | </van-popup> | 78 | </van-popup> |
| 79 | + | ||
| 80 | + <!-- 作业选择弹窗 --> | ||
| 81 | + <van-popup | ||
| 82 | + v-model:show="showCoursePicker" | ||
| 83 | + | ||
| 84 | + round | ||
| 85 | + position="bottom" | ||
| 86 | + :style="{ minHeight: '30%', maxHeight: '80%', width: '100%' }" | ||
| 87 | + > | ||
| 88 | + <van-picker | ||
| 89 | + title="作业选择" | ||
| 90 | + :columns="courseColumns" | ||
| 91 | + @confirm="onConfirmCourse" | ||
| 92 | + @cancel="showCoursePicker = false" | ||
| 93 | + :default-index="0" | ||
| 94 | + /> | ||
| 95 | + </van-popup> | ||
| 64 | </div> | 96 | </div> |
| 65 | </template> | 97 | </template> |
| 66 | 98 | ||
| ... | @@ -85,13 +117,37 @@ const props = defineProps({ | ... | @@ -85,13 +117,37 @@ const props = defineProps({ |
| 85 | }) | 117 | }) |
| 86 | 118 | ||
| 87 | // Emits定义 | 119 | // Emits定义 |
| 88 | -const emit = defineEmits(['update:modelValue', 'select', 'click-subtitle', 'panel-change']) | 120 | +const emit = defineEmits(['update:modelValue', 'select', 'click-subtitle', 'panel-change', 'select-course']) |
| 89 | 121 | ||
| 90 | // 响应式数据 | 122 | // 响应式数据 |
| 91 | const isExpanded = ref(false) | 123 | const isExpanded = ref(false) |
| 92 | const calendarRef = ref(null) | 124 | const calendarRef = ref(null) |
| 93 | const currentDate = ref(props.modelValue || new Date()) | 125 | const currentDate = ref(props.modelValue || new Date()) |
| 94 | 126 | ||
| 127 | +// 作业筛选相关 | ||
| 128 | +const showCoursePicker = ref(false) | ||
| 129 | +const selectedCourseText = ref('全部作业') | ||
| 130 | +const courseColumns = [ | ||
| 131 | + { text: '全部作业', value: '' }, | ||
| 132 | + { text: '语文语文语文语文语文语文', value: 'chinese' }, | ||
| 133 | + { text: '数学', value: 'math' }, | ||
| 134 | + { text: '英语', value: 'english' }, | ||
| 135 | + { text: '物理', value: 'physics' }, | ||
| 136 | + { text: '化学', value: 'chemistry' } | ||
| 137 | +] | ||
| 138 | + | ||
| 139 | +const openCoursePicker = () => { | ||
| 140 | + showCoursePicker.value = true | ||
| 141 | +} | ||
| 142 | + | ||
| 143 | +const onConfirmCourse = (result) => { | ||
| 144 | + // 兼容 Vant 3/4 | ||
| 145 | + const option = result.selectedOptions ? result.selectedOptions[0] : result | ||
| 146 | + selectedCourseText.value = option.text | ||
| 147 | + showCoursePicker.value = false | ||
| 148 | + emit('select-course', option.value) | ||
| 149 | +} | ||
| 150 | + | ||
| 95 | // 计算属性:格式化当前日期显示 | 151 | // 计算属性:格式化当前日期显示 |
| 96 | const formattedCurrentDate = computed(() => { | 152 | const formattedCurrentDate = computed(() => { |
| 97 | return dayjs(currentDate.value).format('YYYY年MM月DD日') | 153 | return dayjs(currentDate.value).format('YYYY年MM月DD日') |
| ... | @@ -195,11 +251,11 @@ defineExpose({ | ... | @@ -195,11 +251,11 @@ defineExpose({ |
| 195 | border-radius: 16px 16px 0 0; | 251 | border-radius: 16px 16px 0 0; |
| 196 | } | 252 | } |
| 197 | 253 | ||
| 198 | - &:hover { | 254 | + // &:hover { |
| 199 | - transform: translateY(-2px); | 255 | + // transform: translateY(-2px); |
| 200 | - box-shadow: 0 8px 30px rgba(76, 175, 80, 0.12), 0 4px 16px rgba(0, 0, 0, 0.08); | 256 | + // box-shadow: 0 8px 30px rgba(76, 175, 80, 0.12), 0 4px 16px rgba(0, 0, 0, 0.08); |
| 201 | - border-color: rgba(76, 175, 80, 0.2); | 257 | + // border-color: rgba(76, 175, 80, 0.2); |
| 202 | - } | 258 | + // } |
| 203 | 259 | ||
| 204 | &:active { | 260 | &:active { |
| 205 | transform: translateY(-1px); | 261 | transform: translateY(-1px); |
| ... | @@ -233,9 +289,9 @@ defineExpose({ | ... | @@ -233,9 +289,9 @@ defineExpose({ |
| 233 | color: #2c3e50; | 289 | color: #2c3e50; |
| 234 | margin-bottom: 2px; | 290 | margin-bottom: 2px; |
| 235 | line-height: 1.3; | 291 | line-height: 1.3; |
| 236 | - overflow: hidden; | 292 | + // overflow: hidden; |
| 237 | - text-overflow: ellipsis; | 293 | + // text-overflow: ellipsis; |
| 238 | - white-space: nowrap; | 294 | + // white-space: nowrap; |
| 239 | } | 295 | } |
| 240 | 296 | ||
| 241 | .calendar-subtitle { | 297 | .calendar-subtitle { |
| ... | @@ -244,12 +300,30 @@ defineExpose({ | ... | @@ -244,12 +300,30 @@ defineExpose({ |
| 244 | font-weight: 400; | 300 | font-weight: 400; |
| 245 | } | 301 | } |
| 246 | } | 302 | } |
| 303 | + | ||
| 304 | + .calendar-date-display { | ||
| 305 | + flex: 0.8; | ||
| 306 | + | ||
| 307 | + .calendar-date-main { | ||
| 308 | + font-size: 16px; | ||
| 309 | + font-weight: 600; | ||
| 310 | + color: #34495e; | ||
| 311 | + margin-bottom: 4px; | ||
| 312 | + line-height: 1.2; | ||
| 313 | + } | ||
| 314 | + | ||
| 315 | + .calendar-weekday { | ||
| 316 | + font-size: 13px; | ||
| 317 | + color: #4caf50; | ||
| 318 | + font-weight: 500; | ||
| 319 | + } | ||
| 320 | + } | ||
| 247 | } | 321 | } |
| 248 | 322 | ||
| 249 | .calendar-content { | 323 | .calendar-content { |
| 250 | display: flex; | 324 | display: flex; |
| 251 | align-items: center; | 325 | align-items: center; |
| 252 | - justify-content: space-between; | 326 | + justify-content: end; |
| 253 | gap: 16px; | 327 | gap: 16px; |
| 254 | 328 | ||
| 255 | .calendar-date-display { | 329 | .calendar-date-display { |
| ... | @@ -270,6 +344,14 @@ defineExpose({ | ... | @@ -270,6 +344,14 @@ defineExpose({ |
| 270 | } | 344 | } |
| 271 | } | 345 | } |
| 272 | 346 | ||
| 347 | + .calendar-actions-wrapper { | ||
| 348 | + display: flex; | ||
| 349 | + flex-direction: column; | ||
| 350 | + align-items: flex-end; | ||
| 351 | + gap: 8px; | ||
| 352 | + flex-shrink: 0; | ||
| 353 | + } | ||
| 354 | + | ||
| 273 | .calendar-action { | 355 | .calendar-action { |
| 274 | display: flex; | 356 | display: flex; |
| 275 | align-items: center; | 357 | align-items: center; |
| ... | @@ -321,6 +403,6 @@ defineExpose({ | ... | @@ -321,6 +403,6 @@ defineExpose({ |
| 321 | 403 | ||
| 322 | // 自定义日历样式 | 404 | // 自定义日历样式 |
| 323 | :deep(.van-popup) { | 405 | :deep(.van-popup) { |
| 324 | - border-radius: 0 0 12px 12px; | 406 | + // border-radius: 0 0 12px 12px; |
| 325 | } | 407 | } |
| 326 | </style> | 408 | </style> | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-05-29 15:34:17 | 2 | * @Date: 2025-05-29 15:34:17 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-12-10 14:08:51 | 4 | + * @LastEditTime: 2025-12-10 21:32:42 |
| 5 | * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue | 5 | * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | --> | 7 | --> |
| ... | @@ -18,6 +18,7 @@ | ... | @@ -18,6 +18,7 @@ |
| 18 | @select="onSelectDay" | 18 | @select="onSelectDay" |
| 19 | @click-subtitle="onClickSubtitle" | 19 | @click-subtitle="onClickSubtitle" |
| 20 | @panel-change="onPanelChange" | 20 | @panel-change="onPanelChange" |
| 21 | + @select-course="onSelectCourse" | ||
| 21 | /> | 22 | /> |
| 22 | </div> | 23 | </div> |
| 23 | 24 | ||
| ... | @@ -532,6 +533,17 @@ const onPanelChange = ({ date }) => { | ... | @@ -532,6 +533,17 @@ const onPanelChange = ({ date }) => { |
| 532 | getTaskDetail(dayjs(date).format('YYYY-MM')); | 533 | getTaskDetail(dayjs(date).format('YYYY-MM')); |
| 533 | } | 534 | } |
| 534 | 535 | ||
| 536 | +const selectedCourseText = ref('') | ||
| 537 | + | ||
| 538 | +/** | ||
| 539 | + * 处理作业选择事件 | ||
| 540 | + * @param {string} course - 选中的作业 | ||
| 541 | + */ | ||
| 542 | +const onSelectCourse = (course) => { | ||
| 543 | + selectedCourseText.value = course.text; | ||
| 544 | + console.warn('选中的作业:', course); | ||
| 545 | +} | ||
| 546 | + | ||
| 535 | /** | 547 | /** |
| 536 | * 根据打卡类型获取对应的图标名称 | 548 | * 根据打卡类型获取对应的图标名称 |
| 537 | * @param {string} type - 打卡类型 | 549 | * @param {string} type - 打卡类型 | ... | ... |
-
Please register or login to post a comment