1
0
mirror of https://github.com/ZeroCatDev/Classworks.git synced 2025-07-03 01:39:22 +00:00
This commit is contained in:
SunWuyuan 2025-03-15 16:52:49 +08:00
parent 6b3ee0074e
commit 137c305cf8
No known key found for this signature in database
GPG Key ID: A6A54CF66F56BB64
3 changed files with 97 additions and 44 deletions

View File

@ -1,7 +1,11 @@
<template> <template>
<v-app> <v-app>
<router-view /> <router-view v-slot="{ Component, route }">
<global-message /> <transition name="md3" mode="out-in">
<component :is="Component" :key="route.path" />
</transition>
</router-view>
<global-message />
</v-app> </v-app>
</template> </template>

View File

@ -4,8 +4,8 @@
:color="colors[message?.type] || colors.info" :color="colors[message?.type] || colors.info"
:timeout="2000" :timeout="2000"
location="bottom" location="bottom"
class="global-snackbar"
multi-line multi-line
variant="tonal"
> >
<div class="d-flex align-center"> <div class="d-flex align-center">
<v-icon :icon="icons[message?.type] || icons.info" class="mr-2" /> <v-icon :icon="icons[message?.type] || icons.info" class="mr-2" />
@ -62,8 +62,5 @@ export default defineComponent({
</script> </script>
<style scoped> <style scoped>
.global-snackbar {
max-width: 400px;
margin: 0 auto;
}
</style> </style>

View File

@ -133,7 +133,12 @@
@click="setAttendanceArea()" @click="setAttendanceArea()"
> >
<h1>出勤</h1> <h1>出勤</h1>
<h2>应到: {{ state.studentList.length - state.boardData.attendance.exclude.length }}</h2> <h2>
应到:
{{
state.studentList.length - state.boardData.attendance.exclude.length
}}
</h2>
<h2> <h2>
实到: 实到:
{{ {{
@ -144,15 +149,24 @@
}} }}
</h2> </h2>
<h2>请假: {{ state.boardData.attendance.absent.length }}</h2> <h2>请假: {{ state.boardData.attendance.absent.length }}</h2>
<h3 v-for="(name, index) in state.boardData.attendance.absent" :key="'absent-' + index"> <h3
v-for="(name, index) in state.boardData.attendance.absent"
:key="'absent-' + index"
>
{{ `${index + 1}. ${name}` }} {{ `${index + 1}. ${name}` }}
</h3> </h3>
<h2>迟到: {{ state.boardData.attendance.late.length }}</h2> <h2>迟到: {{ state.boardData.attendance.late.length }}</h2>
<h3 v-for="(name, index) in state.boardData.attendance.late" :key="'late-' + index"> <h3
v-for="(name, index) in state.boardData.attendance.late"
:key="'late-' + index"
>
{{ `${index + 1}. ${name}` }} {{ `${index + 1}. ${name}` }}
</h3> </h3>
<h2>不参与: {{ state.boardData.attendance.exclude.length }}</h2> <h2>不参与: {{ state.boardData.attendance.exclude.length }}</h2>
<h3 v-for="(name, index) in state.boardData.attendance.exclude" :key="'exclude-' + index"> <h3
v-for="(name, index) in state.boardData.attendance.exclude"
:key="'exclude-' + index"
>
{{ `${index + 1}. ${name}` }} {{ `${index + 1}. ${name}` }}
</h3> </h3>
</v-col> </v-col>
@ -208,7 +222,11 @@
{{ state.snackbarText }} {{ state.snackbarText }}
</v-snackbar> </v-snackbar>
<v-dialog v-model="state.attendanceDialog" max-width="600"> <v-dialog
v-model="state.attendanceDialog"
max-width="600"
@update:model-value="handleAttendanceDialogClose"
>
<v-card> <v-card>
<v-card-title class="text-h6"> 编辑出勤状态 </v-card-title> <v-card-title class="text-h6"> 编辑出勤状态 </v-card-title>
@ -295,9 +313,7 @@
<!-- 添加确认对话框 --> <!-- 添加确认对话框 -->
<v-dialog v-model="confirmDialog.show" max-width="400"> <v-dialog v-model="confirmDialog.show" max-width="400">
<v-card> <v-card>
<v-card-title class="text-h6"> <v-card-title class="text-h6"> 确认保存 </v-card-title>
确认保存
</v-card-title>
<v-card-text> <v-card-text>
您正在修改 {{ state.dateString }} 的数据确定要保存吗 您正在修改 {{ state.dateString }} 的数据确定要保存吗
</v-card-text> </v-card-text>
@ -306,9 +322,7 @@
<v-btn color="grey" variant="text" @click="confirmDialog.reject"> <v-btn color="grey" variant="text" @click="confirmDialog.reject">
取消 取消
</v-btn> </v-btn>
<v-btn color="primary" @click="confirmDialog.resolve"> <v-btn color="primary" @click="confirmDialog.resolve"> 确认保存 </v-btn>
确认保存
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
@ -320,7 +334,7 @@ import dataProvider from "@/utils/dataProvider";
import { getSetting, watchSettings, setSetting } from "@/utils/settings"; import { getSetting, watchSettings, setSetting } from "@/utils/settings";
import { useDisplay } from "vuetify"; import { useDisplay } from "vuetify";
import "../styles/index.scss"; import "../styles/index.scss";
import "../styles/transitions.scss"; // import "../styles/transitions.scss"; //
import { debounce, throttle } from "@/utils/debounce"; import { debounce, throttle } from "@/utils/debounce";
export default { export default {
@ -340,8 +354,8 @@ export default {
attendance: { attendance: {
absent: [], absent: [],
late: [], late: [],
exclude: [] exclude: [],
} },
}, },
dialogVisible: false, dialogVisible: false,
dialogTitle: "", dialogTitle: "",
@ -615,7 +629,7 @@ export default {
this.state.noDataMessage = response.error.message; this.state.noDataMessage = response.error.message;
this.state.boardData = { this.state.boardData = {
homework: {}, homework: {},
attendance: { absent: [], late: [], exclude: [] } attendance: { absent: [], late: [], exclude: [] },
}; };
} else { } else {
throw new Error(response.error.message); throw new Error(response.error.message);
@ -637,7 +651,11 @@ export default {
// //
if (isAutoSave && !this.canAutoSave) { if (isAutoSave && !this.canAutoSave) {
if (this.shouldShowBlockedMessage) { if (this.shouldShowBlockedMessage) {
this.showMessage('需要手动保存', '已禁止自动保存非当天数据', 'warning'); this.showMessage(
"需要手动保存",
"已禁止自动保存非当天数据",
"warning"
);
} }
return false; return false;
} }
@ -656,7 +674,7 @@ export default {
await this.uploadData(); await this.uploadData();
return true; return true;
} catch (error) { } catch (error) {
this.$message.error('保存失败', error.message || '请重试'); this.$message.error("保存失败", error.message || "请重试");
return false; return false;
} }
}, },
@ -668,7 +686,9 @@ export default {
if (content) { if (content) {
// //
this.state.boardData.homework[this.currentEditSubject] = { this.state.boardData.homework[this.currentEditSubject] = {
name: this.state.availableSubjects.find(s => s.key === this.currentEditSubject)?.name, name: this.state.availableSubjects.find(
(s) => s.key === this.currentEditSubject
)?.name,
content, content,
}; };
this.state.synced = false; this.state.synced = false;
@ -770,13 +790,22 @@ export default {
toggleStudentStatus(index) { toggleStudentStatus(index) {
const student = this.state.studentList[index]; const student = this.state.studentList[index];
if (this.state.boardData.attendance.absent.includes(student)) { if (this.state.boardData.attendance.absent.includes(student)) {
this.state.boardData.attendance.absent = this.state.boardData.attendance.absent.filter(name => name !== student); this.state.boardData.attendance.absent =
this.state.boardData.attendance.absent.filter(
(name) => name !== student
);
this.state.boardData.attendance.late.push(student); this.state.boardData.attendance.late.push(student);
} else if (this.state.boardData.attendance.late.includes(student)) { } else if (this.state.boardData.attendance.late.includes(student)) {
this.state.boardData.attendance.late = this.state.boardData.attendance.late.filter(name => name !== student); this.state.boardData.attendance.late =
this.state.boardData.attendance.late.filter(
(name) => name !== student
);
this.state.boardData.attendance.exclude.push(student); this.state.boardData.attendance.exclude.push(student);
} else if (this.state.boardData.attendance.exclude.includes(student)) { } else if (this.state.boardData.attendance.exclude.includes(student)) {
this.state.boardData.attendance.exclude = this.state.boardData.attendance.exclude.filter(name => name !== student); this.state.boardData.attendance.exclude =
this.state.boardData.attendance.exclude.filter(
(name) => name !== student
);
} else { } else {
this.state.boardData.attendance.absent.push(student); this.state.boardData.attendance.absent.push(student);
} }
@ -933,7 +962,7 @@ export default {
this.state.boardData.attendance = { this.state.boardData.attendance = {
absent: [], absent: [],
late: [], late: [],
exclude: [] exclude: [],
}; };
this.state.synced = false; this.state.synced = false;
}, },
@ -955,27 +984,43 @@ export default {
isPresent(index) { isPresent(index) {
const student = this.state.studentList[index]; const student = this.state.studentList[index];
const { absent, late, exclude } = this.state.boardData.attendance; const { absent, late, exclude } = this.state.boardData.attendance;
return !absent.includes(student) && !late.includes(student) && !exclude.includes(student); return (
!absent.includes(student) &&
!late.includes(student) &&
!exclude.includes(student)
);
}, },
isAbsent(index) { isAbsent(index) {
return this.state.boardData.attendance.absent.includes(this.state.studentList[index]); return this.state.boardData.attendance.absent.includes(
this.state.studentList[index]
);
}, },
isLate(index) { isLate(index) {
return this.state.boardData.attendance.late.includes(this.state.studentList[index]); return this.state.boardData.attendance.late.includes(
this.state.studentList[index]
);
}, },
isExclude(index) { isExclude(index) {
return this.state.boardData.attendance.exclude.includes(this.state.studentList[index]); return this.state.boardData.attendance.exclude.includes(
this.state.studentList[index]
);
}, },
setPresent(index) { setPresent(index) {
const student = this.state.studentList[index]; const student = this.state.studentList[index];
const { absent, late, exclude } = this.state.boardData.attendance; const { absent, late, exclude } = this.state.boardData.attendance;
this.state.boardData.attendance.absent = absent.filter(name => name !== student); this.state.boardData.attendance.absent = absent.filter(
this.state.boardData.attendance.late = late.filter(name => name !== student); (name) => name !== student
this.state.boardData.attendance.exclude = exclude.filter(name => name !== student); );
this.state.boardData.attendance.late = late.filter(
(name) => name !== student
);
this.state.boardData.attendance.exclude = exclude.filter(
(name) => name !== student
);
this.state.synced = false; this.state.synced = false;
}, },
@ -1008,7 +1053,7 @@ export default {
async saveAttendance() { async saveAttendance() {
try { try {
await this.uploadData(); // 使 await this.trySave(true);
this.state.attendanceDialog = false; this.state.attendanceDialog = false;
} catch (error) { } catch (error) {
console.error("保存出勤状态失败:", error); console.error("保存出勤状态失败:", error);
@ -1032,8 +1077,8 @@ export default {
const rect = card.getBoundingClientRect(); const rect = card.getBoundingClientRect();
const x = ((e.clientX - rect.left) / rect.width) * 100; const x = ((e.clientX - rect.left) / rect.width) * 100;
const y = ((e.clientY - rect.top) / rect.height) * 100; const y = ((e.clientY - rect.top) / rect.height) * 100;
card.style.setProperty('--x', `${x}%`); card.style.setProperty("--x", `${x}%`);
card.style.setProperty('--y', `${y}%`); card.style.setProperty("--y", `${y}%`);
}, },
handleTouchMove(e) { handleTouchMove(e) {
@ -1043,8 +1088,8 @@ export default {
const rect = card.getBoundingClientRect(); const rect = card.getBoundingClientRect();
const x = ((touch.clientX - rect.left) / rect.width) * 100; const x = ((touch.clientX - rect.left) / rect.width) * 100;
const y = ((touch.clientY - rect.top) / rect.height) * 100; const y = ((touch.clientY - rect.top) / rect.height) * 100;
card.style.setProperty('--x', `${x}%`); card.style.setProperty("--x", `${x}%`);
card.style.setProperty('--y', `${y}%`); card.style.setProperty("--y", `${y}%`);
} }
}, },
@ -1058,8 +1103,8 @@ export default {
}, },
reject: () => { reject: () => {
this.confirmDialog.show = false; this.confirmDialog.show = false;
reject(new Error('用户取消保存')); reject(new Error("用户取消保存"));
} },
}; };
}); });
}, },
@ -1074,7 +1119,7 @@ export default {
cancelSave() { cancelSave() {
this.confirmDialog.show = false; this.confirmDialog.show = false;
if (this.confirmDialog.reject) { if (this.confirmDialog.reject) {
this.confirmDialog.reject(new Error('用户取消保存')); this.confirmDialog.reject(new Error("用户取消保存"));
} }
}, },
@ -1082,6 +1127,13 @@ export default {
async manualUpload() { async manualUpload() {
return this.trySave(false); return this.trySave(false);
}, },
async handleAttendanceDialogClose(newValue) {
if (!newValue && !this.state.synced) {
//
await this.trySave(true);
}
},
}, },
}; };
</script> </script>