hookehuyr

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

- 添加打卡管理页面,包含日历视图、打卡统计和学生动态
- 新增我的班级页面,实现班级成员管理和数据统计展示
- 更新路由配置和组件类型声明
- 优化页面交互和样式细节
......@@ -36,6 +36,7 @@ declare module 'vue' {
VanCell: typeof import('vant/es')['Cell']
VanCellGroup: typeof import('vant/es')['CellGroup']
VanCheckbox: typeof import('vant/es')['Checkbox']
VanCircle: typeof import('vant/es')['Circle']
VanCol: typeof import('vant/es')['Col']
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
VanDatePicker: typeof import('vant/es')['DatePicker']
......@@ -61,9 +62,12 @@ declare module 'vue' {
VanRate: typeof import('vant/es')['Rate']
VanRow: typeof import('vant/es')['Row']
VanSearch: typeof import('vant/es')['Search']
VanSticky: typeof import('vant/es')['Sticky']
VanSwipe: typeof import('vant/es')['Swipe']
VanSwipeItem: typeof import('vant/es')['SwipeItem']
VanTab: typeof import('vant/es')['Tab']
VanTabbar: typeof import('vant/es')['Tabbar']
VanTabbarItem: typeof import('vant/es')['TabbarItem']
VanTabs: typeof import('vant/es')['Tabs']
VanTag: typeof import('vant/es')['Tag']
VanUploader: typeof import('vant/es')['Uploader']
......
/*
* @Date: 2025-06-17 16:46:50
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-18 11:34:36
* @LastEditTime: 2025-06-19 13:23:04
* @FilePath: /mlaj/src/router/teacher.js
* @Description: 文件描述
*/
export default [
{
path: '/teacher/index',
path: '/teacher/checkin',
name: 'Teacher',
component: () => import('../views/teacher/testPage.vue'),
component: () => import('../views/teacher/checkinPage.vue'),
meta: {
title: '教师',
title: '打卡管理',
requiresAuth: true
},
},
......@@ -24,4 +24,13 @@ export default [
requiresAuth: true
},
},
{
path: '/teacher/myClass',
name: 'MyClass',
component: () => import('../views/teacher/myClassPage.vue'),
meta: {
title: '我的班级',
requiresAuth: true
},
},
]
......
......@@ -90,6 +90,15 @@
<FrostedGlass class="rounded-xl overflow-hidden mb-5">
<MenuItem
v-for="item in menuItems4"
:key="item.path"
v-bind="item"
@click="handleMenuClick(item.path)"
/>
</FrostedGlass>
<FrostedGlass class="rounded-xl overflow-hidden mb-5">
<MenuItem
v-for="item in menuItems3"
:key="item.path"
v-bind="item"
......@@ -295,6 +304,19 @@ const menuItems3 = ref([
},
]);
const menuItems4 = ref([
{
icon: "book",
title: "打卡管理",
path: "/teacher/checkin",
},
{
icon: "user",
title: "我的班级",
path: "/teacher/myClass",
},
]);
const handleCheckin = () => {
if (checkinData.value.length) {
showCheckInDialog.value = true;
......
<!--
* @Date: 2025-05-29 15:34:17
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-17 20:08:40
* @FilePath: /mlaj/src/views/teacher/testPage.vue
* @LastEditTime: 2025-06-19 14:49:38
* @FilePath: /mlaj/src/views/teacher/checkinPage.vue
* @Description: 文件描述
-->
<template>
<AppLayout :hasTitle="false">
<van-config-provider :theme-vars="themeVars">
<van-dropdown-menu active-color="#4caf50">
<van-dropdown-item v-model="value1" :options="option1" />
<van-dropdown-item v-model="value2" :options="option2" />
<van-dropdown-item v-model="value3" :options="option3" />
</van-dropdown-menu>
<van-sticky>
<van-dropdown-menu active-color="#4caf50">
<van-dropdown-item v-model="value1" :options="option1" @change="handleChange1" />
<van-dropdown-item v-model="value2" :options="option2" @change="handleChange2" />
<van-dropdown-item v-model="value3" :options="option3" @change="handleChange3" />
</van-dropdown-menu>
</van-sticky>
<van-calendar ref="myRefCalendar" :title="taskDetail.title" :poppable="false" :show-confirm="false" :style="{ height: calendarHeight }"
switch-mode="year-month" color="#4caf50" :formatter="formatter" row-height="50" :show-mark="false"
......@@ -22,21 +24,21 @@
<div style="padding: 0 1rem;">
<van-row gutter="15">
<van-col span="12">
<van-button type="primary" block icon="add-square">主要按钮</van-button>
<van-button type="primary" block icon="photo" @click="handleAdd">安排打卡</van-button>
</van-col>
<van-col span="12">
<van-button type="primary" block icon="video">主要按钮</van-button>
<van-button type="primary" block icon="video">设置作业</van-button>
</van-col>
</van-row>
</div>
<div v-if="showProgress" class="text-wrapper">
<div class="text-header">目标进度</div>
<div class="text-header">打卡统计</div>
<div style="background-color: #FFF; margin-top: 1rem;">
<div class="grade-percentage-main">
<van-row justify="space-between" style="margin: 0.5rem 0; font-size: 0.9rem;">
<van-col span="12">
<span>作业目标</span>
<span>年级目标</span>
</van-col>
<van-col span="12" style="text-align: right;">
<span style="font-weight: bold;">{{ progress1 }}%</span>
......@@ -65,13 +67,8 @@
</div>
</div>
<van-tabs v-model:active="active" style="margin: 0 1rem;">
<van-tab title="标签 1"></van-tab>
<van-tab title="标签 2"></van-tab>
<van-tab title="标签 3"></van-tab>
</van-tabs>
<div v-if="active === 0" style="padding: 0 1rem; color: #4caf50;">
<div style="padding: 0 1rem; color: #4caf50;">
<div class="text-header">学生动态</div>
<van-list
v-if="checkinDataList.length"
v-model:loading="loading"
......@@ -92,12 +89,12 @@
<div class="post-time">{{ post.user.time }}</div>
</div>
</van-col>
<van-col span="3">
<!-- <van-col span="3">
<div v-if="post.is_my" class="post-menu">
<van-icon name="edit" @click="editCheckin(post)" />
<van-icon name="delete-o" @click="delCheckin(post)" />
</div>
</van-col>
</van-col> -->
</van-row>
</div>
<div class="post-content">
......@@ -189,21 +186,33 @@ const value1 = ref(0);
const value2 = ref('a');
const value3 = ref('v');
const option1 = [
{ text: '全部商品', value: 0 },
{ text: '新款商品', value: 1 },
{ text: '活动商品', value: 2 },
{ text: '全部年级', value: 0 },
{ text: '一年级', value: 1 },
{ text: '二年级', value: 2 },
];
const option2 = [
{ text: '默认排序', value: 'a' },
{ text: '好评排序', value: 'b' },
{ text: '销量排序', value: 'c' },
{ text: '全部班级', value: 'a' },
{ text: '一班级', value: 'b' },
{ text: '二班级', value: 'c' },
];
const option3 = [
{ text: '默认排序', value: 'v' },
{ text: '好评排序', value: 'b' },
{ text: '销量排序', value: 'c' },
{ text: '全部课程', value: 'v' },
{ text: '一课程', value: 'b' },
{ text: '二课程', value: 'c' },
];
const handleChange1 = (val) => {
console.log('val', val);
}
const handleChange2 = (val) => {
console.log('val', val);
}
const handleChange3 = (val) => {
console.log('val', val);
}
const active = ref(0);
const myRefCalendar = ref(null);
......@@ -426,11 +435,12 @@ const stopAllVideos = () => {
});
};
const themeVars = {
const themeVars = reactive({
calendarSelectedDayBackground: '#4caf50',
calendarHeaderShadow: 'rgba(0, 0, 0, 0.1)',
calendarInfoLineHeight: '0.3rem',
}
buttonNormalFontSize: '1rem',
})
const progress1 = ref(0);
// const progress2 = ref(76);
......@@ -467,9 +477,16 @@ const formatter = (day) => {
// 检查是否已签到
if (checkin_days.includes(formattedDate)) {
day.className = 'calendar-checkin';
day.type = 'selected';
day.bottomInfo = '已签到';
// 如果是当前选中的已签到日期,使用特殊样式
if (selectedDate.value === formattedDate) {
day.className = 'calendar-selected';
day.type = 'selected';
day.bottomInfo = '已签到';
} else {
day.className = 'calendar-checkin';
day.type = 'selected';
day.bottomInfo = '已签到';
}
}
}
......@@ -483,14 +500,22 @@ const formatter = (day) => {
return day;
}
// 添加一个响应式变量来存储当前选中的日期
const selectedDate = ref('');
const onSelectDay = (day) => {
getTaskDetail(dayjs(day).format('YYYY-MM'));
// 更新当前选中的日期
const currentSelectedDate = dayjs(day).format('YYYY-MM-DD');
selectedDate.value = currentSelectedDate;
// 修改浏览器地址把当前的date加入地址栏, 页面不刷新
router.push({
path: route.path,
query: {
...route.query,
date: dayjs(day).format('YYYY-MM-DD')
date: currentSelectedDate
}
})
// 重置分页参数
......@@ -498,9 +523,10 @@ const onSelectDay = (day) => {
checkinDataList.value = []
finished.value = false
// 重新加载数据
onLoad(dayjs(day).format('YYYY-MM-DD'))
onLoad(currentSelectedDate)
}
const onClickSubtitle = (evt) => {
console.warn('点击了日期标题');
}
......@@ -685,6 +711,17 @@ const formatData = (data) => {
})
return formattedData;
}
const handleAdd = () => {
router.push({
path: '/teacher/form',
query: {
post_id: route.query.id,
type: 'image',
status: 'add',
}
})
}
</script>
<style lang="less">
......
This diff is collapsed. Click to expand it.