hookehuyr

feat(教师页面): 添加课程分组级联筛选组件并实现相关功能

refactor(签到页面): 使用课程分组级联筛选替换原有筛选逻辑

feat(签到模块): 增加补卡日期显示功能

docs(API): 更新接口参数和返回值的文档说明

style(组件): 优化筛选组件样式与交互
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-03 12:37:12 4 + # @LastEditTime: 2025-09-30 15:45:25
5 # @FilePath: /mlaj/.env.development 5 # @FilePath: /mlaj/.env.development
6 # @Description: 文件描述 6 # @Description: 文件描述
7 ### 7 ###
...@@ -23,8 +23,8 @@ VITE_PIN = ...@@ -23,8 +23,8 @@ VITE_PIN =
23 # 反向代理服务器地址 23 # 反向代理服务器地址
24 # VITE_PROXY_TARGET = https://oa.anxinchashi.com/ 24 # VITE_PROXY_TARGET = https://oa.anxinchashi.com/
25 # VITE_PROXY_TARGET = http://behalo.onwall.cn/ 25 # VITE_PROXY_TARGET = http://behalo.onwall.cn/
26 -# VITE_PROXY_TARGET = http://oa-dev.onwall.cn/ 26 +VITE_PROXY_TARGET = http://oa-dev.onwall.cn/
27 -VITE_PROXY_TARGET = https://oa.behalo.cc/ 27 +# VITE_PROXY_TARGET = https://oa.behalo.cc/
28 # VITE_PROXY_TARGET = https://www.wxgzjs.cn/ 28 # VITE_PROXY_TARGET = https://www.wxgzjs.cn/
29 29
30 # PC端地址 30 # PC端地址
......
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-10-27 15:51:02 4 + * @LastEditTime: 2025-11-10 10:37:44
5 * @FilePath: /mlaj/src/api/checkin.js 5 * @FilePath: /mlaj/src/api/checkin.js
6 * @Description: 签到模块相关接口 6 * @Description: 签到模块相关接口
7 */ 7 */
...@@ -111,6 +111,8 @@ export const dislikeUploadTaskInfoAPI = (params) => fn(fetch.post(Api.TASK_UPLO ...@@ -111,6 +111,8 @@ export const dislikeUploadTaskInfoAPI = (params) => fn(fetch.post(Api.TASK_UPLO
111 * @param grade_id 年级ID 111 * @param grade_id 年级ID
112 * @param class_id 班级ID 112 * @param class_id 班级ID
113 * @param group_id 课程ID 113 * @param group_id 课程ID
114 + * @param team_id 大分组ID
115 + * @param subteam_id 小分组ID
114 * @param date 日期 116 * @param date 日期
115 * @param keyword 搜索 117 * @param keyword 搜索
116 * @param order_by_time asc=正序,desc=倒序。默认为倒序 118 * @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-10-13 10:09:15 4 + * @LastEditTime: 2025-11-07 17:16:04
5 * @FilePath: /mlaj/src/api/teacher.js 5 * @FilePath: /mlaj/src/api/teacher.js
6 * @Description: 文件描述 6 * @Description: 文件描述
7 */ 7 */
...@@ -23,9 +23,9 @@ const Api = { ...@@ -23,9 +23,9 @@ const Api = {
23 23
24 /** 24 /**
25 * 获取老师的年级、班级、课程列表信息 25 * 获取老师的年级、班级、课程列表信息
26 - * @param {*} grade_id 年级ID 用来缩小班级、课程的筛选范围 26 + * @param {*} group_id 课程ID,用来缩小大分组的筛选范围
27 - * @param {*} class_id 班级ID 用来缩小课程的筛选范围 27 + * @param {*} team_id 大分组ID,用来缩小大分组的筛选范围
28 - * @returns {Object} data { grade_list [{id, grade_name}], class_list [{id, class_name}], group_list [{id, title}] } 28 + * @returns {Object} data { grade_list [{id, grade_name}], class_list [{id, class_name}], group_list [{id, title}], team_list [{id, team_name}], subteam_list [{id, subteam_name}] }
29 */ 29 */
30 export const getTeacherGradeClassListAPI = (params) => fn(fetch.get(Api.TEACHER_GRADE_CLASS_LIST, params)) 30 export const getTeacherGradeClassListAPI = (params) => fn(fetch.get(Api.TEACHER_GRADE_CLASS_LIST, params))
31 31
......
...@@ -16,6 +16,7 @@ declare module 'vue' { ...@@ -16,6 +16,7 @@ declare module 'vue' {
16 CollapsibleCalendar: typeof import('./components/ui/CollapsibleCalendar.vue')['default'] 16 CollapsibleCalendar: typeof import('./components/ui/CollapsibleCalendar.vue')['default']
17 ConfirmDialog: typeof import('./components/ui/ConfirmDialog.vue')['default'] 17 ConfirmDialog: typeof import('./components/ui/ConfirmDialog.vue')['default']
18 CourseCard: typeof import('./components/ui/CourseCard.vue')['default'] 18 CourseCard: typeof import('./components/ui/CourseCard.vue')['default']
19 + CourseGroupCascader: typeof import('./components/ui/CourseGroupCascader.vue')['default']
19 CourseImageCard: typeof import('./components/ui/CourseImageCard.vue')['default'] 20 CourseImageCard: typeof import('./components/ui/CourseImageCard.vue')['default']
20 CourseList: typeof import('./components/courses/CourseList.vue')['default'] 21 CourseList: typeof import('./components/courses/CourseList.vue')['default']
21 FormPage: typeof import('./components/infoEntry/formPage.vue')['default'] 22 FormPage: typeof import('./components/infoEntry/formPage.vue')['default']
...@@ -31,6 +32,7 @@ declare module 'vue' { ...@@ -31,6 +32,7 @@ declare module 'vue' {
31 RouterView: typeof import('vue-router')['RouterView'] 32 RouterView: typeof import('vue-router')['RouterView']
32 SearchBar: typeof import('./components/ui/SearchBar.vue')['default'] 33 SearchBar: typeof import('./components/ui/SearchBar.vue')['default']
33 SummerCampCard: typeof import('./components/ui/SummerCampCard.vue')['default'] 34 SummerCampCard: typeof import('./components/ui/SummerCampCard.vue')['default']
35 + TeacherFilter: typeof import('./components/ui/TeacherFilter.vue')['default']
34 TermsPopup: typeof import('./components/ui/TermsPopup.vue')['default'] 36 TermsPopup: typeof import('./components/ui/TermsPopup.vue')['default']
35 UploadVideoPopup: typeof import('./components/ui/UploadVideoPopup.vue')['default'] 37 UploadVideoPopup: typeof import('./components/ui/UploadVideoPopup.vue')['default']
36 UserAgreement: typeof import('./components/ui/UserAgreement.vue')['default'] 38 UserAgreement: typeof import('./components/ui/UserAgreement.vue')['default']
......
1 +<!--
2 + * @Author: hookehuyr hookehuyr@gmail.com
3 + * @Date: 2025-11-07 11:00:00
4 + * @LastEditors: hookehuyr hookehuyr@gmail.com
5 + * @LastEditTime: 2025-11-07 17:46:23
6 + * @FilePath: /mlaj/src/components/ui/CourseGroupCascader.vue
7 + * @Description: 教师页面筛选组件(年级/班级/课程),内部管理v-model与options并对外emit change事件
8 +-->
9 +<template>
10 + <!-- 课程 / 年级 / 班级 级联筛选 -->
11 + <van-dropdown-menu active-color="#10b981" swipe-threshold="2">
12 + <van-dropdown-item v-model="select_course_value" :options="course_option" @change="on_course_change" />
13 + <van-dropdown-item v-model="select_major_group_value" :options="major_group_option"
14 + @change="on_major_group_change" />
15 + <van-dropdown-item v-model="select_minor_group_value" :options="minor_group_option"
16 + @change="on_minor_group_change" />
17 + </van-dropdown-menu>
18 +</template>
19 +
20 +<script setup>
21 +import { ref, onMounted } from 'vue'
22 +import { getTeacherGradeClassListAPI } from "@/api/teacher";
23 +
24 +// 组件对外事件
25 +const emit = defineEmits(['change'])
26 +
27 +// 本组件内部管理的选择值(课程 / 年级 / 班级)
28 +const select_course_value = ref(null)
29 +const select_major_group_value = ref(null)
30 +const select_minor_group_value = ref(null)
31 +
32 +// 本组件内部管理的选项数据(课程 / 年级 / 班级)
33 +const course_option = ref([])
34 +const major_group_option = ref([])
35 +const minor_group_option = ref([])
36 +
37 +// 获取筛选选项列表
38 +const getFilterList = async (group_id = null, team_id = null) => {
39 + const { code, data } = await getTeacherGradeClassListAPI({ group_id, team_id });
40 + if (code) {
41 + // 处理数据
42 + course_option.value = data.group_list?.map(item => {
43 + return {
44 + text: item.title,
45 + value: item.id,
46 + }
47 + });
48 + course_option.value.unshift({
49 + text: '全部课程',
50 + value: null,
51 + });
52 + major_group_option.value = data.team_list?.map(item => {
53 + return {
54 + text: item.team_name,
55 + value: item.id,
56 + }
57 + });
58 + major_group_option.value.unshift({
59 + text: '全部年级',
60 + value: null,
61 + });
62 + minor_group_option.value = data.subteam_list?.map(item => {
63 + return {
64 + text: item.subteam_name,
65 + value: item.id,
66 + }
67 + });
68 + minor_group_option.value.unshift({
69 + text: '全部班级',
70 + value: null,
71 + });
72 + }
73 +}
74 +
75 +/**
76 + * 课程变化处理
77 + * @param {number|null} val 选中的课程ID
78 + * @returns {void}
79 + */
80 +const on_course_change = async (val) => {
81 + select_course_value.value = val
82 + // 切换课程时重置分组选择
83 + select_major_group_value.value = null
84 + select_minor_group_value.value = null
85 + // 重建年级选项
86 + getFilterList(val)
87 + // 对外发出change事件,标识来源与值
88 + emit('change', { type: 'course', value: val })
89 +}
90 +
91 +/**
92 + * 年级变化处理
93 + * @param {number|null} val 选中的年级ID
94 + * @returns {void}
95 + */
96 +const on_major_group_change = async (val) => {
97 + select_major_group_value.value = val
98 + // 切换年级时重置班级选择并重建班级选项
99 + select_minor_group_value.value = null
100 + getFilterList(select_course_value.value, val)
101 + // 对外发出change事件,标识来源与值
102 + emit('change', { type: 'major_group', value: val })
103 +}
104 +
105 +/**
106 + * 班级变化处理
107 + * @param {number|null} val 选中的班级ID
108 + * @returns {void}
109 + */
110 +const on_minor_group_change = (val) => {
111 + select_minor_group_value.value = val
112 + // 对外发出change事件,标识来源与值
113 + emit('change', { type: 'minor_group', value: val })
114 +}
115 +
116 +/**
117 + * 组件挂载时初始化筛选选项
118 + * @returns {void}
119 + */
120 +onMounted(async () => {
121 + getFilterList()
122 +})
123 +</script>
124 +
125 +<style lang="less">
126 +// 保持与页面一致的下拉菜单样式(如需可局部覆盖)
127 +.van-dropdown-menu {
128 + background-color: white;
129 + border-radius: 0.75rem;
130 + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
131 +}
132 +
133 +.van-dropdown-item {
134 + .van-cell__title {
135 + white-space: nowrap;
136 + overflow: hidden;
137 + text-overflow: ellipsis;
138 + max-width: 100%;
139 + flex: 0 0 80%;
140 + }
141 +
142 + .van-cell__value {
143 + flex: 0 0 20%;
144 + }
145 +}
146 +</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-10-15 15:09:29 4 + * @LastEditTime: 2025-11-10 10:38:27
5 * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue 5 * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -428,6 +428,7 @@ const formatter = (day) => { ...@@ -428,6 +428,7 @@ const formatter = (day) => {
428 const date = day.date.getDate(); 428 const date = day.date.getDate();
429 429
430 let checkin_days = myCheckinDates.value; 430 let checkin_days = myCheckinDates.value;
431 + let fill_checkin_days = myFillCheckinDates.value;
431 432
432 // 禁用未来日期 433 // 禁用未来日期
433 if (dayjs(day.date).isAfter(new Date(), 'day')) { 434 if (dayjs(day.date).isAfter(new Date(), 'day')) {
...@@ -456,6 +457,25 @@ const formatter = (day) => { ...@@ -456,6 +457,25 @@ const formatter = (day) => {
456 } 457 }
457 } 458 }
458 459
460 + // 检查当前日期是否在补卡日期列表中
461 + if (fill_checkin_days && fill_checkin_days.length > 0) {
462 + // 格式化当前日期为YYYY-MM-DD格式,与fill_checkin_days中的格式匹配
463 + const formattedDate = `${year}-${month.toString().padStart(2, '0')}-${date.toString().padStart(2, '0')}`;
464 + // 检查是否已补卡
465 + if (fill_checkin_days.includes(formattedDate)) {
466 + // 如果是当前选中的已补卡日期,使用特殊样式
467 + if (selectedDate.value === formattedDate) {
468 + day.className = 'calendar-selected';
469 + day.type = 'selected';
470 + day.bottomInfo = '待补卡';
471 + } else {
472 + day.className = 'calendar-fill-checkin';
473 + day.type = 'selected';
474 + day.bottomInfo = '待补卡';
475 + }
476 + }
477 + }
478 +
459 // 选中今天的日期 479 // 选中今天的日期
460 if (dayjs(day.date).isSame(new Date(), 'day')) { 480 if (dayjs(day.date).isSame(new Date(), 'day')) {
461 day.className = 'calendar-today'; 481 day.className = 'calendar-today';
...@@ -651,6 +671,7 @@ const delCheckin = (post) => { ...@@ -651,6 +671,7 @@ const delCheckin = (post) => {
651 671
652 const taskDetail = ref({}); 672 const taskDetail = ref({});
653 const myCheckinDates = ref([]); 673 const myCheckinDates = ref([]);
674 +const myFillCheckinDates = ref([]);
654 const checkinDataList = ref([]); 675 const checkinDataList = ref([]);
655 const showProgress = ref(true); 676 const showProgress = ref(true);
656 677
...@@ -666,6 +687,8 @@ const getTaskDetail = async (month) => { ...@@ -666,6 +687,8 @@ const getTaskDetail = async (month) => {
666 teamAvatars.value = data.checkin_avatars; 687 teamAvatars.value = data.checkin_avatars;
667 // 获取当前用户的打卡日期 688 // 获取当前用户的打卡日期
668 myCheckinDates.value = data.my_checkin_dates; 689 myCheckinDates.value = data.my_checkin_dates;
690 + // 获取当前用户的补卡日期
691 + myFillCheckinDates.value = data.makeup_checkin_dates;
669 // 把['2025-06-06'] 转化为 [6] 只取日期去掉0 692 // 把['2025-06-06'] 转化为 [6] 只取日期去掉0
670 // myCheckinDates.value = myCheckinDates.value.map(date => { 693 // myCheckinDates.value = myCheckinDates.value.map(date => {
671 // return dayjs(date).date(); 694 // return dayjs(date).date();
...@@ -812,6 +835,12 @@ const formatData = (data) => { ...@@ -812,6 +835,12 @@ const formatData = (data) => {
812 } 835 }
813 } 836 }
814 837
838 +.calendar-fill-checkin {
839 + .van-calendar__selected-day {
840 + background: #a2d8a3 !important;
841 + }
842 +}
843 +
815 .calendar-today { 844 .calendar-today {
816 .van-calendar__selected-day { 845 .van-calendar__selected-day {
817 background: #FAAB0C !important; 846 background: #FAAB0C !important;
......
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-10-27 16:34:26 4 + * @LastEditTime: 2025-11-10 10:43:07
5 * @FilePath: /mlaj/src/views/teacher/checkinPage.vue 5 * @FilePath: /mlaj/src/views/teacher/checkinPage.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -9,11 +9,13 @@ ...@@ -9,11 +9,13 @@
9 <AppLayout :hasTitle="false"> 9 <AppLayout :hasTitle="false">
10 <van-config-provider :theme-vars="themeVars"> 10 <van-config-provider :theme-vars="themeVars">
11 <van-sticky> 11 <van-sticky>
12 - <van-dropdown-menu active-color="#4caf50" swipe-threshold="2"> 12 + <!-- <van-dropdown-menu active-color="#4caf50" swipe-threshold="2">
13 <van-dropdown-item v-model="selectGradeValue" :options="gradeOption" @change="handleGradeChange" /> 13 <van-dropdown-item v-model="selectGradeValue" :options="gradeOption" @change="handleGradeChange" />
14 <van-dropdown-item v-model="selectClassValue" :options="classOption" @change="handleClassChange" /> 14 <van-dropdown-item v-model="selectClassValue" :options="classOption" @change="handleClassChange" />
15 <van-dropdown-item v-model="selectCourseValue" :options="courseOption" @change="handleCourseChange" /> 15 <van-dropdown-item v-model="selectCourseValue" :options="courseOption" @change="handleCourseChange" />
16 - </van-dropdown-menu> 16 + </van-dropdown-menu> -->
17 + <!-- 课程, 大分组, 小分组 筛选 -->
18 + <CourseGroupCascader @change="on_cascade_change" />
17 </van-sticky> 19 </van-sticky>
18 20
19 <van-calendar ref="myRefCalendar" :show-title="false" :poppable="false" :show-confirm="false" 21 <van-calendar ref="myRefCalendar" :show-title="false" :poppable="false" :show-confirm="false"
...@@ -22,6 +24,7 @@ ...@@ -22,6 +24,7 @@
22 @panel-change="onPanelChange" 24 @panel-change="onPanelChange"
23 @click-subtitle="onClickSubtitle"> 25 @click-subtitle="onClickSubtitle">
24 </van-calendar> 26 </van-calendar>
27 +
25 <div style="padding: 0 1rem; margin-top: 1rem;"> 28 <div style="padding: 0 1rem; margin-top: 1rem;">
26 <van-row gutter="15"> 29 <van-row gutter="15">
27 <van-col span="12"> 30 <van-col span="12">
...@@ -191,10 +194,11 @@ import AppLayout from "@/components/layout/AppLayout.vue"; ...@@ -191,10 +194,11 @@ import AppLayout from "@/components/layout/AppLayout.vue";
191 import FrostedGlass from "@/components/ui/FrostedGlass.vue"; 194 import FrostedGlass from "@/components/ui/FrostedGlass.vue";
192 import VideoPlayer from "@/components/ui/VideoPlayer.vue"; 195 import VideoPlayer from "@/components/ui/VideoPlayer.vue";
193 import AudioPlayer from "@/components/ui/AudioPlayer.vue"; 196 import AudioPlayer from "@/components/ui/AudioPlayer.vue";
197 +import CourseGroupCascader from '@/components/ui/CourseGroupCascader.vue'
194 import { useTitle } from '@vueuse/core'; 198 import { useTitle } from '@vueuse/core';
195 import dayjs from 'dayjs'; 199 import dayjs from 'dayjs';
196 200
197 -import { getTaskDetailAPI, getCheckinTeacherListAPI, checkinTaskReviewAPI, likeUploadTaskInfoAPI, dislikeUploadTaskInfoAPI,getCheckinTeacherCheckedDatesAPI } from "@/api/checkin"; 201 +import { getTaskDetailAPI, getCheckinTeacherListAPI, checkinTaskReviewAPI, likeUploadTaskInfoAPI, dislikeUploadTaskInfoAPI, getCheckinTeacherCheckedDatesAPI } from "@/api/checkin";
198 import { getTeacherGradeClassListAPI } from "@/api/teacher"; 202 import { getTeacherGradeClassListAPI } from "@/api/teacher";
199 203
200 const route = useRoute() 204 const route = useRoute()
...@@ -214,6 +218,18 @@ const courseOption = ref([]); ...@@ -214,6 +218,18 @@ const courseOption = ref([]);
214 218
215 const currentMonth = ref(dayjs().format('YYYY-MM')); 219 const currentMonth = ref(dayjs().format('YYYY-MM'));
216 220
221 +/**
222 + * 重置分页参数并重新加载数据
223 + */
224 +const resetAndReload = () => {
225 + // 重置分页参数
226 + page.value = 0
227 + checkinDataList.value = []
228 + finished.value = false
229 + // 重新加载数据
230 + onLoad()
231 +}
232 +
217 const handleGradeChange = async (val) => { 233 const handleGradeChange = async (val) => {
218 console.log('val', val); 234 console.log('val', val);
219 selectGradeValue.value = val; 235 selectGradeValue.value = val;
...@@ -259,6 +275,37 @@ const handleCourseChange = (val) => { ...@@ -259,6 +275,37 @@ const handleCourseChange = (val) => {
259 onLoad() 275 onLoad()
260 } 276 }
261 277
278 +// 级联筛选选中值
279 +const selected_course_id = ref(null)
280 +const selected_major_group_id = ref(null)
281 +const selected_minor_group_id = ref(null)
282 +
283 +/**
284 + * 级联筛选组件变化事件处理
285 + * @param {Object} payload - 事件数据,包含 { type, value }
286 + * @returns {void}
287 + */
288 +const on_cascade_change = (payload) => {
289 + if (!payload) return
290 + const { type, value } = payload
291 + if (type === 'course') {
292 + selected_course_id.value = value
293 + selected_major_group_id.value = null
294 + selected_minor_group_id.value = null
295 + } else if (type === 'major_group') {
296 + selected_major_group_id.value = value
297 + selected_minor_group_id.value = null
298 + } else if (type === 'minor_group') {
299 + selected_minor_group_id.value = value
300 + }
301 + // 级联筛选变化
302 + console.log('级联筛选变化: ', payload)
303 + // 重新获取打卡日期
304 + getCheckedDates(currentMonth.value);
305 + // 重置分页参数并重新加载数据
306 + resetAndReload();
307 +}
308 +
262 const active = ref(0); 309 const active = ref(0);
263 310
264 const myRefCalendar = ref(null); 311 const myRefCalendar = ref(null);
...@@ -698,9 +745,12 @@ const getTaskDetail = async (month) => { ...@@ -698,9 +745,12 @@ const getTaskDetail = async (month) => {
698 // 获取用户打卡日期的函数 745 // 获取用户打卡日期的函数
699 const getCheckedDates = async (month) => { 746 const getCheckedDates = async (month) => {
700 const checkedDatesResult = await getCheckinTeacherCheckedDatesAPI({ 747 const checkedDatesResult = await getCheckinTeacherCheckedDatesAPI({
701 - grade_id: selectGradeValue.value, 748 + // grade_id: selectGradeValue.value,
702 - class_id: selectClassValue.value, 749 + // class_id: selectClassValue.value,
703 - group_id: selectCourseValue.value, 750 + // group_id: selectCourseValue.value,
751 + group_id: selected_course_id.value,
752 + team_id: selected_major_group_id.value,
753 + subteam_id: selected_minor_group_id.value,
704 month 754 month
705 }); 755 });
706 if (checkedDatesResult.code) { 756 if (checkedDatesResult.code) {
...@@ -725,9 +775,12 @@ const onLoad = async (date) => { ...@@ -725,9 +775,12 @@ const onLoad = async (date) => {
725 limit: limit.value, 775 limit: limit.value,
726 page: nextPage, 776 page: nextPage,
727 date: current_date, 777 date: current_date,
728 - grade_id: selectGradeValue.value, 778 + // grade_id: selectGradeValue.value,
729 - class_id: selectClassValue.value, 779 + // class_id: selectClassValue.value,
730 - course_id: selectCourseValue.value, 780 + // course_id: selectCourseValue.value,
781 + group_id: selected_course_id.value,
782 + team_id: selected_major_group_id.value,
783 + subteam_id: selected_minor_group_id.value,
731 }); 784 });
732 if (res.code) { 785 if (res.code) {
733 // 整理数据结构 786 // 整理数据结构
...@@ -792,7 +845,7 @@ onMounted(async () => { ...@@ -792,7 +845,7 @@ onMounted(async () => {
792 onLoad(dayjs().format('YYYY-MM-DD')); 845 onLoad(dayjs().format('YYYY-MM-DD'));
793 } 846 }
794 // 获取老师的年级、班级、课程列表信息 847 // 获取老师的年级、班级、课程列表信息
795 - getFilterList(); 848 + // getFilterList();
796 }) 849 })
797 850
798 const formatData = (data) => { 851 const formatData = (data) => {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
2 * @Author: hookehuyr hookehuyr@gmail.com 2 * @Author: hookehuyr hookehuyr@gmail.com
3 * @Date: 2025-01-20 10:00:00 3 * @Date: 2025-01-20 10:00:00
4 * @LastEditors: hookehuyr hookehuyr@gmail.com 4 * @LastEditors: hookehuyr hookehuyr@gmail.com
5 - * @LastEditTime: 2025-09-26 11:31:09 5 + * @LastEditTime: 2025-11-07 18:03:23
6 * @FilePath: /mlaj/src/views/teacher/myClassPage.vue 6 * @FilePath: /mlaj/src/views/teacher/myClassPage.vue
7 * @Description: 我的班级页面 7 * @Description: 我的班级页面
8 --> 8 -->
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
28 </div> 28 </div>
29 29
30 <!-- 筛选器 --> 30 <!-- 筛选器 -->
31 - <div> 31 + <!-- <div>
32 <van-sticky> 32 <van-sticky>
33 <van-dropdown-menu active-color="#10b981" swipe-threshold="2"> 33 <van-dropdown-menu active-color="#10b981" swipe-threshold="2">
34 <van-dropdown-item v-model="selectGradeValue" :options="gradeOption" @change="handleGradeChange" /> 34 <van-dropdown-item v-model="selectGradeValue" :options="gradeOption" @change="handleGradeChange" />
...@@ -36,6 +36,12 @@ ...@@ -36,6 +36,12 @@
36 <van-dropdown-item v-model="selectCourseValue" :options="courseOption" @change="handleCourseChange" /> 36 <van-dropdown-item v-model="selectCourseValue" :options="courseOption" @change="handleCourseChange" />
37 </van-dropdown-menu> 37 </van-dropdown-menu>
38 </van-sticky> 38 </van-sticky>
39 + </div> -->
40 + <!-- 课程, 大分组, 小分组 筛选 -->
41 + <div>
42 + <van-sticky>
43 + <CourseGroupCascader @change="on_cascade_change" />
44 + </van-sticky>
39 </div> 45 </div>
40 46
41 <div style="height: 0.5rem;"></div> 47 <div style="height: 0.5rem;"></div>
...@@ -159,6 +165,7 @@ import { useRouter } from 'vue-router' ...@@ -159,6 +165,7 @@ import { useRouter } from 'vue-router'
159 import AppLayout from '@/layouts/AppLayout.vue' 165 import AppLayout from '@/layouts/AppLayout.vue'
160 import { useTitle } from '@vueuse/core'; 166 import { useTitle } from '@vueuse/core';
161 import { useAuth } from '@/contexts/auth' 167 import { useAuth } from '@/contexts/auth'
168 +import CourseGroupCascader from '@/components/ui/CourseGroupCascader.vue'
162 169
163 import { getTeacherGradeClassListAPI, getStudentListAPI } from "@/api/teacher"; 170 import { getTeacherGradeClassListAPI, getStudentListAPI } from "@/api/teacher";
164 171
...@@ -277,6 +284,35 @@ const handleCourseChange = (val) => { ...@@ -277,6 +284,35 @@ const handleCourseChange = (val) => {
277 resetAndReload(); 284 resetAndReload();
278 } 285 }
279 286
287 +// 级联筛选选中值
288 +const selected_course_id = ref(null)
289 +const selected_major_group_id = ref(null)
290 +const selected_minor_group_id = ref(null)
291 +
292 +/**
293 + * 级联筛选组件变化事件处理
294 + * @param {Object} payload - 事件数据,包含 { type, value }
295 + * @returns {void}
296 + */
297 +const on_cascade_change = (payload) => {
298 + if (!payload) return
299 + const { type, value } = payload
300 + if (type === 'course') {
301 + selected_course_id.value = value
302 + selected_major_group_id.value = null
303 + selected_minor_group_id.value = null
304 + } else if (type === 'major_group') {
305 + selected_major_group_id.value = value
306 + selected_minor_group_id.value = null
307 + } else if (type === 'minor_group') {
308 + selected_minor_group_id.value = value
309 + }
310 + // 级联筛选变化
311 + console.log('级联筛选变化: ', payload)
312 + // 重置分页参数并重新加载数据
313 + resetAndReload();
314 +}
315 +
280 /** 316 /**
281 * 处理排序变化 317 * 处理排序变化
282 * @param {string} value - 选中的排序方式 318 * @param {string} value - 选中的排序方式
...@@ -368,9 +404,12 @@ const onLoad = async () => { ...@@ -368,9 +404,12 @@ const onLoad = async () => {
368 const res = await getStudentListAPI({ 404 const res = await getStudentListAPI({
369 limit: limit.value, 405 limit: limit.value,
370 page: nextPage, 406 page: nextPage,
371 - grade_id: selectGradeValue.value, 407 + // grade_id: selectGradeValue.value,
372 - class_id: selectClassValue.value, 408 + // class_id: selectClassValue.value,
373 - course_id: selectCourseValue.value, 409 + // course_id: selectCourseValue.value,
410 + group_id: selected_course_id.value,
411 + team_id: selected_major_group_id.value,
412 + subteam_id: selected_minor_group_id.value,
374 keyword: searchKeyword.value, 413 keyword: searchKeyword.value,
375 }); 414 });
376 415
...@@ -439,7 +478,7 @@ const getFilterList = async (grade_id=null, class_id=null) => { ...@@ -439,7 +478,7 @@ const getFilterList = async (grade_id=null, class_id=null) => {
439 */ 478 */
440 onMounted(async () => { 479 onMounted(async () => {
441 // 获取老师的年级、班级、课程列表信息 480 // 获取老师的年级、班级、课程列表信息
442 - getFilterList(); 481 + // getFilterList();
443 }) 482 })
444 483
445 /** 484 /**
......