mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-07-03 01:39:22 +00:00
1
This commit is contained in:
parent
dfdb662e11
commit
4f2fd40f78
@ -11,11 +11,35 @@
|
|||||||
<v-spacer />
|
<v-spacer />
|
||||||
|
|
||||||
<template #append>
|
<template #append>
|
||||||
|
<v-btn
|
||||||
|
icon="mdi-format-font-size-decrease"
|
||||||
|
variant="text"
|
||||||
|
@click="zoom('out')"
|
||||||
|
/>
|
||||||
|
<v-btn
|
||||||
|
icon="mdi-format-font-size-increase"
|
||||||
|
variant="text"
|
||||||
|
@click="zoom('up')"
|
||||||
|
/>
|
||||||
|
<v-menu
|
||||||
|
v-model="datePickerDialog"
|
||||||
|
:close-on-content-click="false"
|
||||||
|
|
||||||
|
>
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
<v-btn
|
<v-btn
|
||||||
icon="mdi-calendar"
|
icon="mdi-calendar"
|
||||||
variant="text"
|
variant="text"
|
||||||
@click="datePickerDialog = true"
|
v-bind="props"
|
||||||
/>
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<v-date-picker
|
||||||
|
v-model="selectedDate"
|
||||||
|
color="primary"
|
||||||
|
@update:model-value="handleDateSelect"
|
||||||
|
/>
|
||||||
|
</v-menu>
|
||||||
<v-btn
|
<v-btn
|
||||||
icon="mdi-refresh"
|
icon="mdi-refresh"
|
||||||
variant="text"
|
variant="text"
|
||||||
@ -100,25 +124,6 @@
|
|||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
<v-container fluid>
|
<v-container fluid>
|
||||||
<v-btn
|
|
||||||
icon="mdi-plus"
|
|
||||||
variant="text"
|
|
||||||
@click="zoom('up')"
|
|
||||||
/>
|
|
||||||
<v-btn
|
|
||||||
icon="mdi-minus"
|
|
||||||
variant="text"
|
|
||||||
@click="zoom('out')"
|
|
||||||
/>
|
|
||||||
<v-btn
|
|
||||||
v-if="!synced"
|
|
||||||
color="primary"
|
|
||||||
size="large"
|
|
||||||
:loading="downloadLoading"
|
|
||||||
@click="downloadData"
|
|
||||||
>
|
|
||||||
下载
|
|
||||||
</v-btn>
|
|
||||||
<v-btn
|
<v-btn
|
||||||
v-if="!synced"
|
v-if="!synced"
|
||||||
color="error"
|
color="error"
|
||||||
@ -200,33 +205,12 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<v-dialog
|
|
||||||
v-model="ServerSelectionDialog"
|
|
||||||
width="500"
|
|
||||||
>
|
|
||||||
<ServerSelection />
|
|
||||||
</v-dialog>
|
|
||||||
|
|
||||||
<v-snackbar
|
<v-snackbar
|
||||||
v-model="snackbar"
|
v-model="snackbar"
|
||||||
:timeout="2000"
|
:timeout="2000"
|
||||||
>
|
>
|
||||||
{{ snackbarText }}
|
{{ snackbarText }}
|
||||||
</v-snackbar>
|
</v-snackbar>
|
||||||
|
|
||||||
<v-dialog v-model="datePickerDialog" width="auto">
|
|
||||||
<v-card>
|
|
||||||
<v-card-title>选择日期</v-card-title>
|
|
||||||
<v-card-text>
|
|
||||||
<v-date-picker v-model="selectedDate" />
|
|
||||||
</v-card-text>
|
|
||||||
<v-card-actions>
|
|
||||||
<v-spacer />
|
|
||||||
<v-btn color="primary" @click="goToDate">确定</v-btn>
|
|
||||||
<v-btn @click="datePickerDialog = false">取消</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -256,11 +240,12 @@ export default {
|
|||||||
homeworkArrange: [[], []],
|
homeworkArrange: [[], []],
|
||||||
snackbar: false,
|
snackbar: false,
|
||||||
snackbarText: "",
|
snackbarText: "",
|
||||||
fontSize: 28,
|
fontSize: parseInt(localStorage.getItem('fontSize')) || 28,
|
||||||
ServerSelectionDialog: false,
|
|
||||||
datePickerDialog: false,
|
datePickerDialog: false,
|
||||||
selectedDate: null,
|
selectedDate: null,
|
||||||
refreshInterval: null,
|
refreshInterval: null,
|
||||||
|
autoSave: false,
|
||||||
|
refreshBeforeEdit: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -269,12 +254,19 @@ export default {
|
|||||||
return useDisplay().mobile.value;
|
return useDisplay().mobile.value;
|
||||||
},
|
},
|
||||||
titleText() {
|
titleText() {
|
||||||
const today = new Date().toISOString().split('T')[0];
|
const now = new Date();
|
||||||
const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0];
|
const year = now.getFullYear();
|
||||||
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(now.getDate()).padStart(2, '0');
|
||||||
|
const today = `${year}-${month}-${day}`;
|
||||||
|
|
||||||
|
const yesterday = new Date(now);
|
||||||
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
|
const yesterdayFormatted = `${yesterday.getFullYear()}-${String(yesterday.getMonth() + 1).padStart(2, '0')}-${String(yesterday.getDate()).padStart(2, '0')}`;
|
||||||
|
|
||||||
if (this.dateString === today) {
|
if (this.dateString === today) {
|
||||||
return '今天的作业';
|
return '今天的作业';
|
||||||
} else if (this.dateString === yesterday) {
|
} else if (this.dateString === yesterdayFormatted) {
|
||||||
return '昨天的作业';
|
return '昨天的作业';
|
||||||
} else {
|
} else {
|
||||||
return `${this.dateString}的作业`;
|
return `${this.dateString}的作业`;
|
||||||
@ -287,6 +279,8 @@ export default {
|
|||||||
this.updateBackendUrl();
|
this.updateBackendUrl();
|
||||||
await this.initializeData();
|
await this.initializeData();
|
||||||
this.setupAutoRefresh();
|
this.setupAutoRefresh();
|
||||||
|
this.autoSave = localStorage.getItem('autoSave') === 'true';
|
||||||
|
this.refreshBeforeEdit = localStorage.getItem('refreshBeforeEdit') === 'true';
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("初始化失败:", err);
|
console.error("初始化失败:", err);
|
||||||
this.showError("初始化失败,请刷新页面重试");
|
this.showError("初始化失败,请刷新页面重试");
|
||||||
@ -318,21 +312,30 @@ export default {
|
|||||||
|
|
||||||
setCurrentDate() {
|
setCurrentDate() {
|
||||||
if (this.$route.query.date) {
|
if (this.$route.query.date) {
|
||||||
// 验证并格式化路由中的日期
|
|
||||||
try {
|
try {
|
||||||
const date = new Date(this.$route.query.date);
|
const date = new Date(this.$route.query.date);
|
||||||
if (isNaN(date.getTime())) {
|
if (isNaN(date.getTime())) {
|
||||||
throw new Error('Invalid date');
|
throw new Error('Invalid date');
|
||||||
}
|
}
|
||||||
this.dateString = date.toISOString().split('T')[0];
|
// 使用本地时区格式化日期
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
this.dateString = `${year}-${month}-${day}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// 如果日期无效,使用今天的日期
|
// 如果日期无效,使用今天的日期
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
this.dateString = today.toISOString().split('T')[0];
|
const year = today.getFullYear();
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(today.getDate()).padStart(2, '0');
|
||||||
|
this.dateString = `${year}-${month}-${day}`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
this.dateString = today.toISOString().split('T')[0];
|
const year = today.getFullYear();
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(today.getDate()).padStart(2, '0');
|
||||||
|
this.dateString = `${year}-${month}-${day}`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -340,6 +343,11 @@ export default {
|
|||||||
if (this.currentEditSubject) {
|
if (this.currentEditSubject) {
|
||||||
this.homeworkData[this.currentEditSubject].content = this.textarea;
|
this.homeworkData[this.currentEditSubject].content = this.textarea;
|
||||||
this.synced = false;
|
this.synced = false;
|
||||||
|
|
||||||
|
// 如果启用了自动保存,关闭对话框时自动上传
|
||||||
|
if (this.autoSave) {
|
||||||
|
this.uploadData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.dialogVisible = false;
|
this.dialogVisible = false;
|
||||||
},
|
},
|
||||||
@ -354,7 +362,16 @@ export default {
|
|||||||
this.snackbarText = message;
|
this.snackbarText = message;
|
||||||
},
|
},
|
||||||
|
|
||||||
openDialog(subject) {
|
async openDialog(subject) {
|
||||||
|
// 如果启用了编辑前刷新,先刷新数据
|
||||||
|
if (this.refreshBeforeEdit) {
|
||||||
|
try {
|
||||||
|
await this.downloadData();
|
||||||
|
} catch (err) {
|
||||||
|
this.showError("刷新数据失败,可能显示的不是最新数据");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.currentEditSubject = subject;
|
this.currentEditSubject = subject;
|
||||||
this.dialogTitle = this.homeworkData[subject].name;
|
this.dialogTitle = this.homeworkData[subject].name;
|
||||||
this.textarea = this.homeworkData[subject].content;
|
this.textarea = this.homeworkData[subject].content;
|
||||||
@ -379,13 +396,18 @@ export default {
|
|||||||
toggleStudentStatus(index) {
|
toggleStudentStatus(index) {
|
||||||
if (this.selectedSet.has(index)) {
|
if (this.selectedSet.has(index)) {
|
||||||
this.selectedSet.delete(index);
|
this.selectedSet.delete(index);
|
||||||
this.lateSet.add(index); // Toggle to late
|
this.lateSet.add(index);
|
||||||
} else if (this.lateSet.has(index)) {
|
} else if (this.lateSet.has(index)) {
|
||||||
this.lateSet.delete(index);
|
this.lateSet.delete(index);
|
||||||
} else {
|
} else {
|
||||||
this.selectedSet.add(index); // Toggle to late
|
this.selectedSet.add(index);
|
||||||
}
|
}
|
||||||
this.synced = false;
|
this.synced = false;
|
||||||
|
|
||||||
|
// 如果启用了自动保存,状态改变时自动上传
|
||||||
|
if (this.autoSave) {
|
||||||
|
this.uploadData();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
cleanstudentslist()
|
cleanstudentslist()
|
||||||
{
|
{
|
||||||
@ -393,6 +415,10 @@ export default {
|
|||||||
this.lateSet.clear();
|
this.lateSet.clear();
|
||||||
this.synced = false;
|
this.synced = false;
|
||||||
|
|
||||||
|
// 如果启用了自动保存,清空后自动上传
|
||||||
|
if (this.autoSave) {
|
||||||
|
this.uploadData();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
zoom(direction) {
|
zoom(direction) {
|
||||||
const step = 2;
|
const step = 2;
|
||||||
@ -404,9 +430,12 @@ export default {
|
|||||||
this.contentStyle = {
|
this.contentStyle = {
|
||||||
"font-size": `${this.fontSize}px`,
|
"font-size": `${this.fontSize}px`,
|
||||||
};
|
};
|
||||||
|
localStorage.setItem('fontSize', this.fontSize.toString());
|
||||||
},
|
},
|
||||||
|
|
||||||
async uploadData() {
|
async uploadData() {
|
||||||
|
if (this.uploadLoading) return; // 防止重复上传
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.uploadLoading = true;
|
this.uploadLoading = true;
|
||||||
await axios.post(`${this.backurl}/homework`, {
|
await axios.post(`${this.backurl}/homework`, {
|
||||||
@ -514,12 +543,17 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
goToDate() {
|
handleDateSelect(newDate) {
|
||||||
if (this.selectedDate) {
|
if (newDate) {
|
||||||
const formattedDate = new Date(this.selectedDate).toISOString().split('T')[0];
|
// 使用本地时区处理日期,避免时区偏移
|
||||||
|
const date = new Date(newDate);
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
const formattedDate = `${year}-${month}-${day}`;
|
||||||
|
|
||||||
this.dateString = formattedDate;
|
this.dateString = formattedDate;
|
||||||
this.$router.push(`/?date=${formattedDate}`);
|
this.$router.push(`/?date=${formattedDate}`);
|
||||||
this.datePickerDialog = false;
|
|
||||||
this.downloadData();
|
this.downloadData();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title>学生列表设置</v-card-title>
|
<v-card-title>云端学生列表设置</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-textarea v-model="students" label="学生列表" required />
|
<v-textarea v-model="students" label="学生列表" required />
|
||||||
<v-btn color="primary" @click="saveStudents">保存</v-btn>
|
<v-btn color="primary" @click="saveStudents">保存</v-btn>
|
||||||
@ -41,10 +41,10 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card>
|
<v-card disabled>
|
||||||
<v-card-title>自动刷新设置</v-card-title>
|
<v-card-title>自动刷新设置</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-switch v-model="autoRefresh" label="启用自动刷新" />
|
<v-switch v-model="autoRefresh" label="启用自动刷新"/>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="refreshInterval"
|
v-model="refreshInterval"
|
||||||
type="number"
|
type="number"
|
||||||
@ -55,6 +55,64 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>字体设置</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
<v-row align="center">
|
||||||
|
<v-col>
|
||||||
|
<v-text-field
|
||||||
|
v-model="fontSize"
|
||||||
|
type="number"
|
||||||
|
label="字体大小"
|
||||||
|
suffix="px"
|
||||||
|
:rules="[
|
||||||
|
v => v >= 16 || '字体大小不能小于16px',
|
||||||
|
v => v <= 100 || '字体大小不能大于100px'
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="auto">
|
||||||
|
<v-btn color="primary" @click="saveFontSize">保存</v-btn>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="auto">
|
||||||
|
<v-btn color="error" @click="resetFontSize">重置</v-btn>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>编辑设置</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<v-switch
|
||||||
|
v-model="autoSave"
|
||||||
|
label="启用自动保存"
|
||||||
|
hint="编辑完成后自动上传到服务器"
|
||||||
|
persistent-hint
|
||||||
|
@change="saveEditSettings"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<v-switch
|
||||||
|
v-model="refreshBeforeEdit"
|
||||||
|
label="编辑前自动刷新"
|
||||||
|
hint="打开编辑框前自动从服务器获取最新数据"
|
||||||
|
persistent-hint
|
||||||
|
@change="saveEditSettings"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|
||||||
@ -77,6 +135,9 @@ export default {
|
|||||||
snackbarText: '',
|
snackbarText: '',
|
||||||
autoRefresh: false,
|
autoRefresh: false,
|
||||||
refreshInterval: 300,
|
refreshInterval: 300,
|
||||||
|
fontSize: '28',
|
||||||
|
autoSave: false,
|
||||||
|
refreshBeforeEdit: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -102,6 +163,14 @@ export default {
|
|||||||
|
|
||||||
this.autoRefresh = localStorage.getItem('autoRefresh') === 'true';
|
this.autoRefresh = localStorage.getItem('autoRefresh') === 'true';
|
||||||
this.refreshInterval = parseInt(localStorage.getItem('refreshInterval')) || 300;
|
this.refreshInterval = parseInt(localStorage.getItem('refreshInterval')) || 300;
|
||||||
|
|
||||||
|
const savedFontSize = localStorage.getItem('fontSize');
|
||||||
|
if (savedFontSize) {
|
||||||
|
this.fontSize = savedFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.autoSave = localStorage.getItem('autoSave') === 'true';
|
||||||
|
this.refreshBeforeEdit = localStorage.getItem('refreshBeforeEdit') === 'true';
|
||||||
},
|
},
|
||||||
|
|
||||||
saveServerSettings() {
|
saveServerSettings() {
|
||||||
@ -151,6 +220,38 @@ export default {
|
|||||||
this.showMessage('保存成功');
|
this.showMessage('保存成功');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
saveFontSize() {
|
||||||
|
try {
|
||||||
|
const size = parseInt(this.fontSize);
|
||||||
|
if (size >= 16 && size <= 100) {
|
||||||
|
localStorage.setItem('fontSize', size.toString());
|
||||||
|
this.showMessage('字体大小保存成功');
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid font size');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.showMessage('保存失败,字体大小必须在16-100之间');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
resetFontSize() {
|
||||||
|
localStorage.removeItem('fontSize');
|
||||||
|
this.fontSize = '28';
|
||||||
|
this.showMessage('字体大小已重置为默认值');
|
||||||
|
},
|
||||||
|
|
||||||
|
saveEditSettings() {
|
||||||
|
localStorage.setItem('autoSave', this.autoSave);
|
||||||
|
localStorage.setItem('refreshBeforeEdit', this.refreshBeforeEdit);
|
||||||
|
this.showMessage(
|
||||||
|
this.autoSave
|
||||||
|
? '已启用自动保存'
|
||||||
|
: this.refreshBeforeEdit
|
||||||
|
? '已启用编辑前刷新'
|
||||||
|
: '已更新编辑设置'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
showMessage(text) {
|
showMessage(text) {
|
||||||
this.snackbarText = text;
|
this.snackbarText = text;
|
||||||
this.snackbar = true;
|
this.snackbar = true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user