mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-07-03 01:39:22 +00:00
1
This commit is contained in:
parent
39d6bfec60
commit
8aaf537f84
@ -246,27 +246,42 @@ export default {
|
|||||||
index: -1,
|
index: -1,
|
||||||
name: ''
|
name: ''
|
||||||
},
|
},
|
||||||
savedState: null // 初始为 null,用于判断是否已初始化
|
savedState: { // 初始化为当前值而不是 null
|
||||||
|
list: [],
|
||||||
|
text: ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
// 使用 modelValue 初始化保存状态
|
// 移除这里的初始化,改为在 mounted 中处理
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
// 使用 nextTick 确保在 DOM 更新后初始化
|
||||||
|
this.$nextTick(() => {
|
||||||
this.savedState = {
|
this.savedState = {
|
||||||
list: [...this.modelValue.list],
|
list: [...this.modelValue.list],
|
||||||
text: this.modelValue.text
|
text: this.modelValue.text
|
||||||
}
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
originalList: {
|
originalList: {
|
||||||
handler(newList) {
|
handler(newList) {
|
||||||
// 仅在首次加载时更新保存状态
|
// 只在初始加载和空列表时更新
|
||||||
if (!this.savedState || this.savedState.list.length === 0) {
|
if (this.modelValue.list.length === 0) {
|
||||||
this.savedState = {
|
const newState = {
|
||||||
list: [...newList],
|
list: [...newList],
|
||||||
text: newList.join('\n')
|
text: newList.join('\n')
|
||||||
}
|
};
|
||||||
|
// 同步更新两个状态
|
||||||
|
this.savedState = { ...newState };
|
||||||
|
this.updateModelValue({
|
||||||
|
...this.modelValue,
|
||||||
|
...newState
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
immediate: true
|
immediate: true
|
||||||
@ -285,14 +300,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
hasChanges() {
|
hasChanges() {
|
||||||
if (!this.savedState) return false;
|
|
||||||
|
|
||||||
const currentState = JSON.stringify({
|
const currentState = JSON.stringify({
|
||||||
list: this.modelValue.list,
|
list: this.modelValue.list,
|
||||||
text: this.modelValue.text
|
text: this.modelValue.text
|
||||||
});
|
});
|
||||||
const savedState = JSON.stringify(this.savedState);
|
const savedState = JSON.stringify(this.savedState);
|
||||||
return currentState !== savedState;
|
// 检查 savedState 是否为初始状态
|
||||||
|
return this.savedState.list.length > 0 && currentState !== savedState;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -329,6 +343,14 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 更新保存状态
|
||||||
|
updateSavedState() {
|
||||||
|
this.savedState = {
|
||||||
|
list: [...this.modelValue.list],
|
||||||
|
text: this.modelValue.text
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
// 学生管理方法
|
// 学生管理方法
|
||||||
addStudent() {
|
addStudent() {
|
||||||
const name = this.newStudentName.trim();
|
const name = this.newStudentName.trim();
|
||||||
@ -401,12 +423,12 @@ export default {
|
|||||||
|
|
||||||
// 保存和加载处理
|
// 保存和加载处理
|
||||||
async handleSave() {
|
async handleSave() {
|
||||||
|
try {
|
||||||
await this.$emit('save');
|
await this.$emit('save');
|
||||||
// 保存时更新状态
|
this.updateSavedState();
|
||||||
this.savedState = {
|
} catch (error) {
|
||||||
list: [...this.modelValue.list],
|
console.error('保存失败:', error);
|
||||||
text: this.modelValue.text
|
}
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleTextInput(value) {
|
handleTextInput(value) {
|
||||||
@ -417,7 +439,7 @@ export default {
|
|||||||
|
|
||||||
this.updateModelValue({
|
this.updateModelValue({
|
||||||
text: value,
|
text: value,
|
||||||
list: list
|
list
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,16 +21,9 @@
|
|||||||
variant="text"
|
variant="text"
|
||||||
@click="zoom('up')"
|
@click="zoom('up')"
|
||||||
/>
|
/>
|
||||||
<v-menu
|
<v-menu v-model="state.datePickerDialog" :close-on-content-click="false">
|
||||||
v-model="state.datePickerDialog"
|
|
||||||
:close-on-content-click="false"
|
|
||||||
>
|
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-btn
|
<v-btn icon="mdi-calendar" variant="text" v-bind="props" />
|
||||||
icon="mdi-calendar"
|
|
||||||
variant="text"
|
|
||||||
v-bind="props"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<v-date-picker
|
<v-date-picker
|
||||||
@ -45,11 +38,7 @@
|
|||||||
:loading="loading.download"
|
:loading="loading.download"
|
||||||
@click="downloadData"
|
@click="downloadData"
|
||||||
/>
|
/>
|
||||||
<v-btn
|
<v-btn icon="mdi-cog" variant="text" @click="$router.push('/settings')" />
|
||||||
icon="mdi-cog"
|
|
||||||
variant="text"
|
|
||||||
@click="$router.push('/settings')"
|
|
||||||
/>
|
|
||||||
<v-btn
|
<v-btn
|
||||||
icon="mdi-bell"
|
icon="mdi-bell"
|
||||||
variant="text"
|
variant="text"
|
||||||
@ -61,15 +50,9 @@
|
|||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<!-- 主要内容区域 -->
|
<!-- 主要内容区域 -->
|
||||||
<v-container
|
<v-container class="main-window flex-grow-1" fluid>
|
||||||
class="main-window flex-grow-1"
|
|
||||||
fluid
|
|
||||||
>
|
|
||||||
<!-- 有内容的科目卡片 -->
|
<!-- 有内容的科目卡片 -->
|
||||||
<div
|
<div ref="gridContainer" class="grid-masonry">
|
||||||
ref="gridContainer"
|
|
||||||
class="grid-masonry"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
v-for="item in sortedItems"
|
v-for="item in sortedItems"
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
@ -80,10 +63,7 @@
|
|||||||
}"
|
}"
|
||||||
@click="!isEditingDisabled && openDialog(item.key)"
|
@click="!isEditingDisabled && openDialog(item.key)"
|
||||||
>
|
>
|
||||||
<v-card
|
<v-card border height="100%">
|
||||||
border
|
|
||||||
height="100%"
|
|
||||||
>
|
|
||||||
<v-card-title>{{ item.name }}</v-card-title>
|
<v-card-title>{{ item.name }}</v-card-title>
|
||||||
<v-card-text :style="state.contentStyle">
|
<v-card-text :style="state.contentStyle">
|
||||||
<v-list>
|
<v-list>
|
||||||
@ -102,26 +82,19 @@
|
|||||||
<!-- 单独显示空科目 -->
|
<!-- 单独显示空科目 -->
|
||||||
<div class="empty-subjects mt-4">
|
<div class="empty-subjects mt-4">
|
||||||
<template v-if="emptySubjectDisplay === 'button'">
|
<template v-if="emptySubjectDisplay === 'button'">
|
||||||
<v-btn-group class="gap-2 flex-wrap">
|
<v-btn-group divided variant="outlined">
|
||||||
<v-btn
|
<v-btn
|
||||||
v-for="subject in unusedSubjects"
|
v-for="subject in unusedSubjects"
|
||||||
:key="subject.key"
|
:key="subject.key"
|
||||||
variant="tonal"
|
|
||||||
color="primary"
|
|
||||||
:disabled="isEditingDisabled"
|
:disabled="isEditingDisabled"
|
||||||
@click="openDialog(subject.key)"
|
@click="openDialog(subject.key)"
|
||||||
>
|
>
|
||||||
<v-icon start>
|
<v-icon start> mdi-plus </v-icon>
|
||||||
mdi-plus
|
|
||||||
</v-icon>
|
|
||||||
{{ subject.name }}
|
{{ subject.name }}
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-btn-group>
|
</v-btn-group>
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div v-else class="empty-subjects-grid">
|
||||||
v-else
|
|
||||||
class="empty-subjects-grid"
|
|
||||||
>
|
|
||||||
<v-card
|
<v-card
|
||||||
v-for="subject in unusedSubjects"
|
v-for="subject in unusedSubjects"
|
||||||
:key="subject.key"
|
:key="subject.key"
|
||||||
@ -134,15 +107,8 @@
|
|||||||
{{ subject.name }}
|
{{ subject.name }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="text-center">
|
<v-card-text class="text-center">
|
||||||
<v-icon
|
<v-icon size="small" color="grey"> mdi-plus </v-icon>
|
||||||
size="small"
|
<div class="text-caption text-grey">点击添加作业</div>
|
||||||
color="grey"
|
|
||||||
>
|
|
||||||
mdi-plus
|
|
||||||
</v-icon>
|
|
||||||
<div class="text-caption text-grey">
|
|
||||||
点击添加作业
|
|
||||||
</div>
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</div>
|
</div>
|
||||||
@ -157,20 +123,26 @@
|
|||||||
@click="setAttendanceArea()"
|
@click="setAttendanceArea()"
|
||||||
>
|
>
|
||||||
<h1>出勤</h1>
|
<h1>出勤</h1>
|
||||||
<h2>应到: {{ state.studentList.length }}人</h2>
|
<h2>应到: {{ state.studentList.length - state.excludeSet.size }}人</h2>
|
||||||
<h2>实到: {{ state.studentList.length - state.selectedSet.size }}人</h2>
|
<h2>
|
||||||
|
实到:
|
||||||
|
{{
|
||||||
|
state.studentList.length -
|
||||||
|
state.selectedSet.size -
|
||||||
|
state.lateSet.size -
|
||||||
|
state.excludeSet.size
|
||||||
|
}}人
|
||||||
|
</h2>
|
||||||
<h2>请假: {{ state.selectedSet.size }}人</h2>
|
<h2>请假: {{ state.selectedSet.size }}人</h2>
|
||||||
<h3
|
<h3 v-for="(i, index) in state.selectedSet" :key="'absent-' + index">
|
||||||
v-for="(i, index) in state.selectedSet"
|
|
||||||
:key="'absent-' + index"
|
|
||||||
>
|
|
||||||
{{ `${index + 1}. ${state.studentList[i]}` }}
|
{{ `${index + 1}. ${state.studentList[i]}` }}
|
||||||
</h3>
|
</h3>
|
||||||
<h2>迟到: {{ state.lateSet.size }}人</h2>
|
<h2>迟到: {{ state.lateSet.size }}人</h2>
|
||||||
<h3
|
<h3 v-for="(i, index) in state.lateSet" :key="'late-' + index">
|
||||||
v-for="(i, index) in state.lateSet"
|
{{ `${index + 1}. ${state.studentList[i]}` }}
|
||||||
:key="'late-' + index"
|
</h3>
|
||||||
>
|
<h2>不参与: {{ state.excludeSet.size }}人</h2>
|
||||||
|
<h3 v-for="(i, index) in state.excludeSet" :key="'exclude-' + index">
|
||||||
{{ `${index + 1}. ${state.studentList[i]}` }}
|
{{ `${index + 1}. ${state.studentList[i]}` }}
|
||||||
</h3>
|
</h3>
|
||||||
</v-col>
|
</v-col>
|
||||||
@ -186,14 +158,9 @@
|
|||||||
>
|
>
|
||||||
上传
|
上传
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn v-else color="success" size="large" @click="showSyncMessage">
|
||||||
v-else
|
同步完成 </v-btn
|
||||||
color="success"
|
><v-btn
|
||||||
size="large"
|
|
||||||
@click="showSyncMessage"
|
|
||||||
>
|
|
||||||
同步完成
|
|
||||||
</v-btn><v-btn
|
|
||||||
v-if="showRandomButton"
|
v-if="showRandomButton"
|
||||||
color="yellow"
|
color="yellow"
|
||||||
prepend-icon="mdi-account-question"
|
prepend-icon="mdi-account-question"
|
||||||
@ -227,65 +194,13 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<v-dialog
|
<v-snackbar v-model="state.snackbar" :timeout="2000">
|
||||||
v-model="state.attendDialogVisible"
|
|
||||||
width="800"
|
|
||||||
>
|
|
||||||
<v-card>
|
|
||||||
<v-card-title>设置学生出勤状态</v-card-title>
|
|
||||||
<v-card-text>
|
|
||||||
<v-btn @click="cleanstudentslist">
|
|
||||||
全勤
|
|
||||||
</v-btn>
|
|
||||||
<v-container fluid>
|
|
||||||
<v-row>
|
|
||||||
<v-col
|
|
||||||
v-for="(name, i) in state.studentList"
|
|
||||||
:key="i"
|
|
||||||
cols="12"
|
|
||||||
sm="6"
|
|
||||||
md="4"
|
|
||||||
>
|
|
||||||
<v-card
|
|
||||||
border
|
|
||||||
:class="{
|
|
||||||
selected: state.selectedSet.has(i) || state.lateSet.has(i),
|
|
||||||
}"
|
|
||||||
:color="
|
|
||||||
state.selectedSet.has(i)
|
|
||||||
? 'primary'
|
|
||||||
: state.lateSet.has(i)
|
|
||||||
? 'orange'
|
|
||||||
: ''
|
|
||||||
"
|
|
||||||
@click="toggleStudentStatus(i)"
|
|
||||||
>
|
|
||||||
<v-card-text>
|
|
||||||
{{ `${i + 1}. ${name}` }}
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-container>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
|
|
||||||
<v-snackbar
|
|
||||||
v-model="state.snackbar"
|
|
||||||
:timeout="2000"
|
|
||||||
>
|
|
||||||
{{ state.snackbarText }}
|
{{ state.snackbarText }}
|
||||||
</v-snackbar>
|
</v-snackbar>
|
||||||
|
|
||||||
<v-dialog
|
<v-dialog v-model="state.attendanceDialog" max-width="600">
|
||||||
v-model="state.attendanceDialog"
|
|
||||||
max-width="600"
|
|
||||||
>
|
|
||||||
<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>
|
||||||
<v-expansion-panels>
|
<v-expansion-panels>
|
||||||
@ -346,6 +261,12 @@
|
|||||||
size="small"
|
size="small"
|
||||||
@click="setLate(index)"
|
@click="setLate(index)"
|
||||||
/>
|
/>
|
||||||
|
<v-btn
|
||||||
|
:color="isExclude(index) ? 'grey' : ''"
|
||||||
|
icon="mdi-account-cancel"
|
||||||
|
size="small"
|
||||||
|
@click="setExclude(index)"
|
||||||
|
/>
|
||||||
</v-btn-group>
|
</v-btn-group>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
@ -354,12 +275,7 @@
|
|||||||
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn color="primary" @click="saveAttendance"> 保存 </v-btn>
|
||||||
color="primary"
|
|
||||||
@click="saveAttendance"
|
|
||||||
>
|
|
||||||
保存
|
|
||||||
</v-btn>
|
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
@ -389,6 +305,7 @@ export default {
|
|||||||
studentList: [],
|
studentList: [],
|
||||||
selectedSet: new Set(),
|
selectedSet: new Set(),
|
||||||
lateSet: new Set(),
|
lateSet: new Set(),
|
||||||
|
excludeSet: new Set(), // 新增不参与集合
|
||||||
dialogVisible: false,
|
dialogVisible: false,
|
||||||
dialogTitle: "",
|
dialogTitle: "",
|
||||||
textarea: "",
|
textarea: "",
|
||||||
@ -630,6 +547,7 @@ export default {
|
|||||||
this.state.homeworkData = {};
|
this.state.homeworkData = {};
|
||||||
this.state.selectedSet = new Set();
|
this.state.selectedSet = new Set();
|
||||||
this.state.lateSet = new Set();
|
this.state.lateSet = new Set();
|
||||||
|
this.state.excludeSet = new Set(); // 添加不参与状态
|
||||||
} else {
|
} else {
|
||||||
throw new Error(response.error.message);
|
throw new Error(response.error.message);
|
||||||
}
|
}
|
||||||
@ -639,6 +557,7 @@ export default {
|
|||||||
this.state.homeworkData = homework;
|
this.state.homeworkData = homework;
|
||||||
this.state.selectedSet = new Set(attendance.absent || []);
|
this.state.selectedSet = new Set(attendance.absent || []);
|
||||||
this.state.lateSet = new Set(attendance.late || []);
|
this.state.lateSet = new Set(attendance.late || []);
|
||||||
|
this.state.excludeSet = new Set(attendance.exclude || []); // 添加不参与状态
|
||||||
this.state.synced = true;
|
this.state.synced = true;
|
||||||
this.state.showNoDataMessage = false;
|
this.state.showNoDataMessage = false;
|
||||||
this.showMessage("下载成功", "数据已更新");
|
this.showMessage("下载成功", "数据已更新");
|
||||||
@ -663,6 +582,7 @@ export default {
|
|||||||
attendance: {
|
attendance: {
|
||||||
absent: Array.from(this.state.selectedSet),
|
absent: Array.from(this.state.selectedSet),
|
||||||
late: Array.from(this.state.lateSet),
|
late: Array.from(this.state.lateSet),
|
||||||
|
exclude: Array.from(this.state.excludeSet), // 添加不参与状态
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
this.state.dateString
|
this.state.dateString
|
||||||
@ -766,7 +686,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
setAttendanceArea() {
|
setAttendanceArea() {
|
||||||
this.state.attendDialogVisible = true;
|
this.state.attendanceDialog = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleStudentStatus(index) {
|
toggleStudentStatus(index) {
|
||||||
@ -775,6 +695,9 @@ export default {
|
|||||||
this.state.lateSet.add(index);
|
this.state.lateSet.add(index);
|
||||||
} else if (this.state.lateSet.has(index)) {
|
} else if (this.state.lateSet.has(index)) {
|
||||||
this.state.lateSet.delete(index);
|
this.state.lateSet.delete(index);
|
||||||
|
this.state.excludeSet.add(index);
|
||||||
|
} else if (this.state.excludeSet.has(index)) {
|
||||||
|
this.state.excludeSet.delete(index);
|
||||||
} else {
|
} else {
|
||||||
this.state.selectedSet.add(index);
|
this.state.selectedSet.add(index);
|
||||||
}
|
}
|
||||||
@ -787,6 +710,7 @@ export default {
|
|||||||
cleanstudentslist() {
|
cleanstudentslist() {
|
||||||
this.state.selectedSet.clear();
|
this.state.selectedSet.clear();
|
||||||
this.state.lateSet.clear();
|
this.state.lateSet.clear();
|
||||||
|
this.state.excludeSet.clear();
|
||||||
this.state.synced = false;
|
this.state.synced = false;
|
||||||
if (this.autoSave) {
|
if (this.autoSave) {
|
||||||
this.uploadData();
|
this.uploadData();
|
||||||
@ -932,6 +856,7 @@ export default {
|
|||||||
setAllPresent() {
|
setAllPresent() {
|
||||||
this.state.selectedSet.clear();
|
this.state.selectedSet.clear();
|
||||||
this.state.lateSet.clear();
|
this.state.lateSet.clear();
|
||||||
|
this.state.excludeSet.clear();
|
||||||
},
|
},
|
||||||
|
|
||||||
setAllAbsent() {
|
setAllAbsent() {
|
||||||
@ -948,7 +873,9 @@ export default {
|
|||||||
|
|
||||||
isPresent(index) {
|
isPresent(index) {
|
||||||
return (
|
return (
|
||||||
!this.state.selectedSet.has(index) && !this.state.lateSet.has(index)
|
!this.state.selectedSet.has(index) &&
|
||||||
|
!this.state.lateSet.has(index) &&
|
||||||
|
!this.state.excludeSet.has(index)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -960,19 +887,32 @@ export default {
|
|||||||
return this.state.lateSet.has(index);
|
return this.state.lateSet.has(index);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isExclude(index) {
|
||||||
|
return this.state.excludeSet.has(index);
|
||||||
|
},
|
||||||
|
|
||||||
setPresent(index) {
|
setPresent(index) {
|
||||||
this.state.selectedSet.delete(index);
|
this.state.selectedSet.delete(index);
|
||||||
this.state.lateSet.delete(index);
|
this.state.lateSet.delete(index);
|
||||||
|
this.state.excludeSet.delete(index);
|
||||||
},
|
},
|
||||||
|
|
||||||
setAbsent(index) {
|
setAbsent(index) {
|
||||||
this.state.selectedSet.add(index);
|
this.state.selectedSet.add(index);
|
||||||
this.state.lateSet.delete(index);
|
this.state.lateSet.delete(index);
|
||||||
|
this.state.excludeSet.delete(index);
|
||||||
},
|
},
|
||||||
|
|
||||||
setLate(index) {
|
setLate(index) {
|
||||||
this.state.lateSet.add(index);
|
this.state.lateSet.add(index);
|
||||||
this.state.selectedSet.delete(index);
|
this.state.selectedSet.delete(index);
|
||||||
|
this.state.excludeSet.delete(index);
|
||||||
|
},
|
||||||
|
|
||||||
|
setExclude(index) {
|
||||||
|
this.state.excludeSet.add(index);
|
||||||
|
this.state.selectedSet.delete(index);
|
||||||
|
this.state.lateSet.delete(index);
|
||||||
},
|
},
|
||||||
|
|
||||||
async saveAttendance() {
|
async saveAttendance() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user