hookehuyr

feat(teacher): 新增教师模块打卡管理和我的班级功能

- 添加打卡管理页面,包含日历视图、打卡统计和学生动态
- 新增我的班级页面,实现班级成员管理和数据统计展示
- 更新路由配置和组件类型声明
- 优化页面交互和样式细节
...@@ -36,6 +36,7 @@ declare module 'vue' { ...@@ -36,6 +36,7 @@ declare module 'vue' {
36 VanCell: typeof import('vant/es')['Cell'] 36 VanCell: typeof import('vant/es')['Cell']
37 VanCellGroup: typeof import('vant/es')['CellGroup'] 37 VanCellGroup: typeof import('vant/es')['CellGroup']
38 VanCheckbox: typeof import('vant/es')['Checkbox'] 38 VanCheckbox: typeof import('vant/es')['Checkbox']
39 + VanCircle: typeof import('vant/es')['Circle']
39 VanCol: typeof import('vant/es')['Col'] 40 VanCol: typeof import('vant/es')['Col']
40 VanConfigProvider: typeof import('vant/es')['ConfigProvider'] 41 VanConfigProvider: typeof import('vant/es')['ConfigProvider']
41 VanDatePicker: typeof import('vant/es')['DatePicker'] 42 VanDatePicker: typeof import('vant/es')['DatePicker']
...@@ -61,9 +62,12 @@ declare module 'vue' { ...@@ -61,9 +62,12 @@ declare module 'vue' {
61 VanRate: typeof import('vant/es')['Rate'] 62 VanRate: typeof import('vant/es')['Rate']
62 VanRow: typeof import('vant/es')['Row'] 63 VanRow: typeof import('vant/es')['Row']
63 VanSearch: typeof import('vant/es')['Search'] 64 VanSearch: typeof import('vant/es')['Search']
65 + VanSticky: typeof import('vant/es')['Sticky']
64 VanSwipe: typeof import('vant/es')['Swipe'] 66 VanSwipe: typeof import('vant/es')['Swipe']
65 VanSwipeItem: typeof import('vant/es')['SwipeItem'] 67 VanSwipeItem: typeof import('vant/es')['SwipeItem']
66 VanTab: typeof import('vant/es')['Tab'] 68 VanTab: typeof import('vant/es')['Tab']
69 + VanTabbar: typeof import('vant/es')['Tabbar']
70 + VanTabbarItem: typeof import('vant/es')['TabbarItem']
67 VanTabs: typeof import('vant/es')['Tabs'] 71 VanTabs: typeof import('vant/es')['Tabs']
68 VanTag: typeof import('vant/es')['Tag'] 72 VanTag: typeof import('vant/es')['Tag']
69 VanUploader: typeof import('vant/es')['Uploader'] 73 VanUploader: typeof import('vant/es')['Uploader']
......
1 /* 1 /*
2 * @Date: 2025-06-17 16:46:50 2 * @Date: 2025-06-17 16:46:50
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-06-18 11:34:36 4 + * @LastEditTime: 2025-06-19 13:23:04
5 * @FilePath: /mlaj/src/router/teacher.js 5 * @FilePath: /mlaj/src/router/teacher.js
6 * @Description: 文件描述 6 * @Description: 文件描述
7 */ 7 */
8 export default [ 8 export default [
9 { 9 {
10 - path: '/teacher/index', 10 + path: '/teacher/checkin',
11 name: 'Teacher', 11 name: 'Teacher',
12 - component: () => import('../views/teacher/testPage.vue'), 12 + component: () => import('../views/teacher/checkinPage.vue'),
13 meta: { 13 meta: {
14 - title: '教师', 14 + title: '打卡管理',
15 requiresAuth: true 15 requiresAuth: true
16 }, 16 },
17 }, 17 },
...@@ -24,4 +24,13 @@ export default [ ...@@ -24,4 +24,13 @@ export default [
24 requiresAuth: true 24 requiresAuth: true
25 }, 25 },
26 }, 26 },
27 + {
28 + path: '/teacher/myClass',
29 + name: 'MyClass',
30 + component: () => import('../views/teacher/myClassPage.vue'),
31 + meta: {
32 + title: '我的班级',
33 + requiresAuth: true
34 + },
35 + },
27 ] 36 ]
......
...@@ -90,6 +90,15 @@ ...@@ -90,6 +90,15 @@
90 90
91 <FrostedGlass class="rounded-xl overflow-hidden mb-5"> 91 <FrostedGlass class="rounded-xl overflow-hidden mb-5">
92 <MenuItem 92 <MenuItem
93 + v-for="item in menuItems4"
94 + :key="item.path"
95 + v-bind="item"
96 + @click="handleMenuClick(item.path)"
97 + />
98 + </FrostedGlass>
99 +
100 + <FrostedGlass class="rounded-xl overflow-hidden mb-5">
101 + <MenuItem
93 v-for="item in menuItems3" 102 v-for="item in menuItems3"
94 :key="item.path" 103 :key="item.path"
95 v-bind="item" 104 v-bind="item"
...@@ -295,6 +304,19 @@ const menuItems3 = ref([ ...@@ -295,6 +304,19 @@ const menuItems3 = ref([
295 }, 304 },
296 ]); 305 ]);
297 306
307 +const menuItems4 = ref([
308 + {
309 + icon: "book",
310 + title: "打卡管理",
311 + path: "/teacher/checkin",
312 + },
313 + {
314 + icon: "user",
315 + title: "我的班级",
316 + path: "/teacher/myClass",
317 + },
318 +]);
319 +
298 const handleCheckin = () => { 320 const handleCheckin = () => {
299 if (checkinData.value.length) { 321 if (checkinData.value.length) {
300 showCheckInDialog.value = true; 322 showCheckInDialog.value = true;
......
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-06-17 20:08:40 4 + * @LastEditTime: 2025-06-19 14:49:38
5 - * @FilePath: /mlaj/src/views/teacher/testPage.vue 5 + * @FilePath: /mlaj/src/views/teacher/checkinPage.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
8 <template> 8 <template>
9 <AppLayout :hasTitle="false"> 9 <AppLayout :hasTitle="false">
10 <van-config-provider :theme-vars="themeVars"> 10 <van-config-provider :theme-vars="themeVars">
11 - <van-dropdown-menu active-color="#4caf50"> 11 + <van-sticky>
12 - <van-dropdown-item v-model="value1" :options="option1" /> 12 + <van-dropdown-menu active-color="#4caf50">
13 - <van-dropdown-item v-model="value2" :options="option2" /> 13 + <van-dropdown-item v-model="value1" :options="option1" @change="handleChange1" />
14 - <van-dropdown-item v-model="value3" :options="option3" /> 14 + <van-dropdown-item v-model="value2" :options="option2" @change="handleChange2" />
15 - </van-dropdown-menu> 15 + <van-dropdown-item v-model="value3" :options="option3" @change="handleChange3" />
16 + </van-dropdown-menu>
17 + </van-sticky>
16 18
17 <van-calendar ref="myRefCalendar" :title="taskDetail.title" :poppable="false" :show-confirm="false" :style="{ height: calendarHeight }" 19 <van-calendar ref="myRefCalendar" :title="taskDetail.title" :poppable="false" :show-confirm="false" :style="{ height: calendarHeight }"
18 switch-mode="year-month" color="#4caf50" :formatter="formatter" row-height="50" :show-mark="false" 20 switch-mode="year-month" color="#4caf50" :formatter="formatter" row-height="50" :show-mark="false"
...@@ -22,21 +24,21 @@ ...@@ -22,21 +24,21 @@
22 <div style="padding: 0 1rem;"> 24 <div style="padding: 0 1rem;">
23 <van-row gutter="15"> 25 <van-row gutter="15">
24 <van-col span="12"> 26 <van-col span="12">
25 - <van-button type="primary" block icon="add-square">主要按钮</van-button> 27 + <van-button type="primary" block icon="photo" @click="handleAdd">安排打卡</van-button>
26 </van-col> 28 </van-col>
27 <van-col span="12"> 29 <van-col span="12">
28 - <van-button type="primary" block icon="video">主要按钮</van-button> 30 + <van-button type="primary" block icon="video">设置作业</van-button>
29 </van-col> 31 </van-col>
30 </van-row> 32 </van-row>
31 </div> 33 </div>
32 34
33 <div v-if="showProgress" class="text-wrapper"> 35 <div v-if="showProgress" class="text-wrapper">
34 - <div class="text-header">目标进度</div> 36 + <div class="text-header">打卡统计</div>
35 <div style="background-color: #FFF; margin-top: 1rem;"> 37 <div style="background-color: #FFF; margin-top: 1rem;">
36 <div class="grade-percentage-main"> 38 <div class="grade-percentage-main">
37 <van-row justify="space-between" style="margin: 0.5rem 0; font-size: 0.9rem;"> 39 <van-row justify="space-between" style="margin: 0.5rem 0; font-size: 0.9rem;">
38 <van-col span="12"> 40 <van-col span="12">
39 - <span>作业目标</span> 41 + <span>年级目标</span>
40 </van-col> 42 </van-col>
41 <van-col span="12" style="text-align: right;"> 43 <van-col span="12" style="text-align: right;">
42 <span style="font-weight: bold;">{{ progress1 }}%</span> 44 <span style="font-weight: bold;">{{ progress1 }}%</span>
...@@ -65,13 +67,8 @@ ...@@ -65,13 +67,8 @@
65 </div> 67 </div>
66 </div> 68 </div>
67 69
68 - <van-tabs v-model:active="active" style="margin: 0 1rem;"> 70 + <div style="padding: 0 1rem; color: #4caf50;">
69 - <van-tab title="标签 1"></van-tab> 71 + <div class="text-header">学生动态</div>
70 - <van-tab title="标签 2"></van-tab>
71 - <van-tab title="标签 3"></van-tab>
72 - </van-tabs>
73 -
74 - <div v-if="active === 0" style="padding: 0 1rem; color: #4caf50;">
75 <van-list 72 <van-list
76 v-if="checkinDataList.length" 73 v-if="checkinDataList.length"
77 v-model:loading="loading" 74 v-model:loading="loading"
...@@ -92,12 +89,12 @@ ...@@ -92,12 +89,12 @@
92 <div class="post-time">{{ post.user.time }}</div> 89 <div class="post-time">{{ post.user.time }}</div>
93 </div> 90 </div>
94 </van-col> 91 </van-col>
95 - <van-col span="3"> 92 + <!-- <van-col span="3">
96 <div v-if="post.is_my" class="post-menu"> 93 <div v-if="post.is_my" class="post-menu">
97 <van-icon name="edit" @click="editCheckin(post)" /> 94 <van-icon name="edit" @click="editCheckin(post)" />
98 <van-icon name="delete-o" @click="delCheckin(post)" /> 95 <van-icon name="delete-o" @click="delCheckin(post)" />
99 </div> 96 </div>
100 - </van-col> 97 + </van-col> -->
101 </van-row> 98 </van-row>
102 </div> 99 </div>
103 <div class="post-content"> 100 <div class="post-content">
...@@ -189,21 +186,33 @@ const value1 = ref(0); ...@@ -189,21 +186,33 @@ const value1 = ref(0);
189 const value2 = ref('a'); 186 const value2 = ref('a');
190 const value3 = ref('v'); 187 const value3 = ref('v');
191 const option1 = [ 188 const option1 = [
192 - { text: '全部商品', value: 0 }, 189 + { text: '全部年级', value: 0 },
193 - { text: '新款商品', value: 1 }, 190 + { text: '一年级', value: 1 },
194 - { text: '活动商品', value: 2 }, 191 + { text: '二年级', value: 2 },
195 ]; 192 ];
196 const option2 = [ 193 const option2 = [
197 - { text: '默认排序', value: 'a' }, 194 + { text: '全部班级', value: 'a' },
198 - { text: '好评排序', value: 'b' }, 195 + { text: '一班级', value: 'b' },
199 - { text: '销量排序', value: 'c' }, 196 + { text: '二班级', value: 'c' },
200 ]; 197 ];
201 const option3 = [ 198 const option3 = [
202 - { text: '默认排序', value: 'v' }, 199 + { text: '全部课程', value: 'v' },
203 - { text: '好评排序', value: 'b' }, 200 + { text: '一课程', value: 'b' },
204 - { text: '销量排序', value: 'c' }, 201 + { text: '二课程', value: 'c' },
205 ]; 202 ];
206 203
204 +const handleChange1 = (val) => {
205 + console.log('val', val);
206 +}
207 +
208 +const handleChange2 = (val) => {
209 + console.log('val', val);
210 +}
211 +
212 +const handleChange3 = (val) => {
213 + console.log('val', val);
214 +}
215 +
207 const active = ref(0); 216 const active = ref(0);
208 217
209 const myRefCalendar = ref(null); 218 const myRefCalendar = ref(null);
...@@ -426,11 +435,12 @@ const stopAllVideos = () => { ...@@ -426,11 +435,12 @@ const stopAllVideos = () => {
426 }); 435 });
427 }; 436 };
428 437
429 -const themeVars = { 438 +const themeVars = reactive({
430 calendarSelectedDayBackground: '#4caf50', 439 calendarSelectedDayBackground: '#4caf50',
431 calendarHeaderShadow: 'rgba(0, 0, 0, 0.1)', 440 calendarHeaderShadow: 'rgba(0, 0, 0, 0.1)',
432 calendarInfoLineHeight: '0.3rem', 441 calendarInfoLineHeight: '0.3rem',
433 -} 442 + buttonNormalFontSize: '1rem',
443 +})
434 444
435 const progress1 = ref(0); 445 const progress1 = ref(0);
436 // const progress2 = ref(76); 446 // const progress2 = ref(76);
...@@ -467,9 +477,16 @@ const formatter = (day) => { ...@@ -467,9 +477,16 @@ const formatter = (day) => {
467 477
468 // 检查是否已签到 478 // 检查是否已签到
469 if (checkin_days.includes(formattedDate)) { 479 if (checkin_days.includes(formattedDate)) {
470 - day.className = 'calendar-checkin'; 480 + // 如果是当前选中的已签到日期,使用特殊样式
471 - day.type = 'selected'; 481 + if (selectedDate.value === formattedDate) {
472 - day.bottomInfo = '已签到'; 482 + day.className = 'calendar-selected';
483 + day.type = 'selected';
484 + day.bottomInfo = '已签到';
485 + } else {
486 + day.className = 'calendar-checkin';
487 + day.type = 'selected';
488 + day.bottomInfo = '已签到';
489 + }
473 } 490 }
474 } 491 }
475 492
...@@ -483,14 +500,22 @@ const formatter = (day) => { ...@@ -483,14 +500,22 @@ const formatter = (day) => {
483 return day; 500 return day;
484 } 501 }
485 502
503 +// 添加一个响应式变量来存储当前选中的日期
504 +const selectedDate = ref('');
505 +
486 const onSelectDay = (day) => { 506 const onSelectDay = (day) => {
487 getTaskDetail(dayjs(day).format('YYYY-MM')); 507 getTaskDetail(dayjs(day).format('YYYY-MM'));
508 +
509 + // 更新当前选中的日期
510 + const currentSelectedDate = dayjs(day).format('YYYY-MM-DD');
511 + selectedDate.value = currentSelectedDate;
512 +
488 // 修改浏览器地址把当前的date加入地址栏, 页面不刷新 513 // 修改浏览器地址把当前的date加入地址栏, 页面不刷新
489 router.push({ 514 router.push({
490 path: route.path, 515 path: route.path,
491 query: { 516 query: {
492 ...route.query, 517 ...route.query,
493 - date: dayjs(day).format('YYYY-MM-DD') 518 + date: currentSelectedDate
494 } 519 }
495 }) 520 })
496 // 重置分页参数 521 // 重置分页参数
...@@ -498,9 +523,10 @@ const onSelectDay = (day) => { ...@@ -498,9 +523,10 @@ const onSelectDay = (day) => {
498 checkinDataList.value = [] 523 checkinDataList.value = []
499 finished.value = false 524 finished.value = false
500 // 重新加载数据 525 // 重新加载数据
501 - onLoad(dayjs(day).format('YYYY-MM-DD')) 526 + onLoad(currentSelectedDate)
502 } 527 }
503 528
529 +
504 const onClickSubtitle = (evt) => { 530 const onClickSubtitle = (evt) => {
505 console.warn('点击了日期标题'); 531 console.warn('点击了日期标题');
506 } 532 }
...@@ -685,6 +711,17 @@ const formatData = (data) => { ...@@ -685,6 +711,17 @@ const formatData = (data) => {
685 }) 711 })
686 return formattedData; 712 return formattedData;
687 } 713 }
714 +
715 +const handleAdd = () => {
716 + router.push({
717 + path: '/teacher/form',
718 + query: {
719 + post_id: route.query.id,
720 + type: 'image',
721 + status: 'add',
722 + }
723 + })
724 +}
688 </script> 725 </script>
689 726
690 <style lang="less"> 727 <style lang="less">
......
This diff is collapsed. Click to expand it.