1
This commit is contained in:
+391
-172
@@ -53,114 +53,199 @@
|
||||
/>
|
||||
</template>
|
||||
</v-app-bar>
|
||||
<v-container
|
||||
class="main-window"
|
||||
fluid
|
||||
>
|
||||
<v-row>
|
||||
<v-col :cols="attendanceVisible ? 11 : 12">
|
||||
<div class="grid-masonry" ref="gridContainer">
|
||||
<div
|
||||
v-for="item in sortedItems"
|
||||
:key="item.key"
|
||||
class="grid-item"
|
||||
:class="{
|
||||
'empty-card': !item.content,
|
||||
[`grid-row-${item.rowSpan}`]: true
|
||||
}"
|
||||
:style="{
|
||||
'grid-row-end': `span ${item.rowSpan}`,
|
||||
order: item.order
|
||||
}"
|
||||
@click="openDialog(item.key)"
|
||||
>
|
||||
<v-card border height="100%">
|
||||
<v-card-title :class="{ 'text-subtitle-1': !item.content }">
|
||||
{{ item.name }}
|
||||
<div class="d-flex">
|
||||
<!-- 主要内容区域 -->
|
||||
<v-container
|
||||
class="main-window flex-grow-1"
|
||||
fluid
|
||||
>
|
||||
<div v-if="showNoDataMessage && !isToday" class="no-data-message">
|
||||
<v-card class="text-center pa-4" variant="outlined">
|
||||
<v-card-title class="text-h6">{{ noDataMessage }}</v-card-title>
|
||||
<v-card-text>
|
||||
<div class="text-body-1">该日期未上传作业数据</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div v-if="showNoDataMessage && isToday" class="no-data-message">
|
||||
<v-card class="text-center pa-4" variant="outlined">
|
||||
<v-card-title class="text-h6">开始今天的作业</v-card-title>
|
||||
<v-card-text>
|
||||
<div class="text-body-1 mb-4">今天还没有上传作业哦~</div>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="initializeAndOpenDialog"
|
||||
>
|
||||
开始添加作业
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div class="grid-masonry" ref="gridContainer">
|
||||
<div
|
||||
v-for="item in sortedItems"
|
||||
:key="item.key"
|
||||
class="grid-item"
|
||||
:class="{
|
||||
'empty-card': !item.content,
|
||||
[`grid-row-${item.rowSpan}`]: true
|
||||
}"
|
||||
:style="{
|
||||
'grid-row-end': `span ${item.rowSpan}`,
|
||||
order: item.order,
|
||||
cursor: uploadLoading || downloadLoading ? 'not-allowed' : 'pointer',
|
||||
opacity: uploadLoading || downloadLoading ? '0.7' : '1'
|
||||
}"
|
||||
@click="!uploadLoading && !downloadLoading && openDialog(item.key)"
|
||||
>
|
||||
<v-card border height="100%">
|
||||
<v-card-title :class="{ 'text-subtitle-1': !item.content }">
|
||||
{{ item.name }}
|
||||
</v-card-title>
|
||||
<v-card-text :style="item.content ? contentStyle : null">
|
||||
<template v-if="item.content">
|
||||
<v-list>
|
||||
<v-list-item
|
||||
v-for="text in splitPoint(item.content)"
|
||||
:key="text"
|
||||
>
|
||||
{{ text }}
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="text-center pa-2">
|
||||
<v-icon size="small" color="grey">mdi-plus</v-icon>
|
||||
<div class="text-caption text-grey">点击添加作业</div>
|
||||
</div>
|
||||
</template>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空科目按钮组 -->
|
||||
<div v-if="emptySubjectDisplay === 'button'" class="empty-subjects-container">
|
||||
<v-btn
|
||||
v-for="subject in emptySubjects"
|
||||
:key="subject.key"
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
class="empty-subject-btn"
|
||||
@click="!uploadLoading && !downloadLoading && openDialog(subject.key)"
|
||||
:disabled="uploadLoading || downloadLoading"
|
||||
>
|
||||
<v-icon start>mdi-plus</v-icon>
|
||||
{{ subject.name }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</v-container>
|
||||
|
||||
<!-- 出勤统计区域 -->
|
||||
<v-navigation-drawer
|
||||
v-if="studentList.length > 1"
|
||||
location="right"
|
||||
permanent
|
||||
width="300"
|
||||
class="attendance-drawer"
|
||||
>
|
||||
<v-card
|
||||
class="h-100"
|
||||
flat
|
||||
>
|
||||
<v-card-item>
|
||||
<v-card-title class="text-h6">
|
||||
<v-icon icon="mdi-account-multiple" class="mr-2" />
|
||||
出勤统计
|
||||
</v-card-title>
|
||||
</v-card-item>
|
||||
|
||||
<v-card-text>
|
||||
<div class="attendance-stats mb-4">
|
||||
<div class="d-flex justify-space-between align-center mb-2">
|
||||
<span class="text-subtitle-1">应到人数</span>
|
||||
<span class="text-h6">{{ studentList.length }}人</span>
|
||||
</div>
|
||||
<div class="d-flex justify-space-between align-center mb-2">
|
||||
<span class="text-subtitle-1">实到人数</span>
|
||||
<span class="text-h6 text-success">
|
||||
{{ studentList.length - selectedSet.size - lateSet.size }}人
|
||||
</span>
|
||||
</div>
|
||||
<v-divider class="my-2" />
|
||||
<div class="d-flex justify-space-between align-center mb-2">
|
||||
<span class="text-subtitle-1">请假人数</span>
|
||||
<span class="text-h6 text-error">{{ selectedSet.size }}人</span>
|
||||
</div>
|
||||
<div class="d-flex justify-space-between align-center">
|
||||
<span class="text-subtitle-1">迟到人数</span>
|
||||
<span class="text-h6 text-warning">{{ lateSet.size }}人</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="selectedSet.size > 0">
|
||||
<v-card
|
||||
variant="outlined"
|
||||
class="mb-4"
|
||||
>
|
||||
<v-card-title class="text-subtitle-1">
|
||||
<v-icon icon="mdi-account-off" class="mr-2" color="error" />
|
||||
请假名单
|
||||
</v-card-title>
|
||||
<v-card-text :style="item.content ? contentStyle : null">
|
||||
<template v-if="item.content">
|
||||
<v-list>
|
||||
<v-list-item
|
||||
v-for="text in splitPoint(item.content)"
|
||||
:key="text"
|
||||
>
|
||||
{{ text }}
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="text-center pa-2">
|
||||
<v-icon size="small" color="grey">mdi-plus</v-icon>
|
||||
<div class="text-caption text-grey">点击添加作业</div>
|
||||
</div>
|
||||
</template>
|
||||
<v-card-text>
|
||||
<v-list density="compact" nav>
|
||||
<v-list-item
|
||||
v-for="i in Array.from(selectedSet)"
|
||||
:key="'absent-' + i"
|
||||
:title="`${i + 1}. ${studentList[i]}`"
|
||||
prepend-icon="mdi-account"
|
||||
/>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 空科目按钮组 -->
|
||||
<div v-if="emptySubjectDisplay === 'button'" class="empty-subjects-container">
|
||||
<template v-if="lateSet.size > 0">
|
||||
<v-card
|
||||
variant="outlined"
|
||||
>
|
||||
<v-card-title class="text-subtitle-1">
|
||||
<v-icon icon="mdi-clock-alert" class="mr-2" color="warning" />
|
||||
迟到名单
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-list density="compact" nav>
|
||||
<v-list-item
|
||||
v-for="i in Array.from(lateSet)"
|
||||
:key="'late-' + i"
|
||||
:title="`${i + 1}. ${studentList[i]}`"
|
||||
prepend-icon="mdi-account-clock"
|
||||
/>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions class="pa-4">
|
||||
<v-btn
|
||||
v-for="subject in emptySubjects"
|
||||
:key="subject.key"
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
class="empty-subject-btn"
|
||||
@click="openDialog(subject.key)"
|
||||
>
|
||||
<v-icon start>mdi-plus</v-icon>
|
||||
{{ subject.name }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
v-if="studentList.length"
|
||||
class="attendance-area"
|
||||
:cols="1"
|
||||
@click="setAttendanceArea"
|
||||
>
|
||||
<h1>出勤</h1>
|
||||
<h2>应到:{{ studentList.length }}人</h2>
|
||||
<h2>
|
||||
实到:{{ studentList.length - selectedSet.size }}人
|
||||
</h2>
|
||||
<h2>请假:{{ selectedSet.size }} 人</h2>
|
||||
<h3
|
||||
v-for="(i, index) in selectedSet"
|
||||
:key="'absent-' + index"
|
||||
>
|
||||
{{ `${index + 1}. ${studentList[i]}` }}
|
||||
</h3>
|
||||
<h2>迟到:{{ lateSet.size }} 人</h2>
|
||||
|
||||
<h3
|
||||
v-for="(i, index) in lateSet"
|
||||
:key="'late-' + index"
|
||||
>
|
||||
{{ `${index + 1}. ${studentList[i]}` }}
|
||||
</h3>
|
||||
|
||||
<!-- 空科目按钮显示区域 -->
|
||||
<template v-if="showEmptySubjects && emptySubjectDisplay === 'button'">
|
||||
<v-divider class="my-4" />
|
||||
<h2>未填写作业</h2>
|
||||
<v-btn
|
||||
v-for="subject in emptySubjects"
|
||||
:key="subject.key"
|
||||
block
|
||||
variant="outlined"
|
||||
class="mb-2"
|
||||
@click.stop="openDialog(subject.key)"
|
||||
color="primary"
|
||||
prepend-icon="mdi-pencil"
|
||||
@click="setAttendanceArea"
|
||||
>
|
||||
{{ subject.name }}
|
||||
编辑出勤状态
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-navigation-drawer>
|
||||
</div>
|
||||
<v-container fluid>
|
||||
<v-btn
|
||||
v-if="!synced"
|
||||
@@ -331,11 +416,65 @@
|
||||
.main-window::-webkit-scrollbar-thumb:hover {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.no-data-message {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 200px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.attendance-drawer {
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.attendance-drawer :deep(.v-navigation-drawer__content) {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 优化滚动条样式 */
|
||||
.attendance-drawer :deep(.v-navigation-drawer__content::-webkit-scrollbar) {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.attendance-drawer :deep(.v-navigation-drawer__content::-webkit-scrollbar-track) {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.attendance-drawer :deep(.v-navigation-drawer__content::-webkit-scrollbar-thumb) {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.attendance-drawer :deep(.v-navigation-drawer__content::-webkit-scrollbar-thumb:hover) {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 960px) {
|
||||
.attendance-drawer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.text-success {
|
||||
color: rgb(var(--v-theme-success));
|
||||
}
|
||||
|
||||
.text-error {
|
||||
color: rgb(var(--v-theme-error));
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
color: rgb(var(--v-theme-warning));
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import { useDisplay } from "vuetify";
|
||||
import { getSetting, watchSettings } from '@/utils/settings';
|
||||
|
||||
export default {
|
||||
name: "HomeworkBoard",
|
||||
@@ -353,25 +492,24 @@ export default {
|
||||
dateString: "",
|
||||
synced: false,
|
||||
attendDialogVisible: false,
|
||||
contentStyle: { "font-size": "28px" },
|
||||
contentStyle: { "font-size": `${getSetting('font.size')}px` },
|
||||
uploadLoading: false,
|
||||
downloadLoading: false,
|
||||
homeworkData: {},
|
||||
homeworkArrange: [[], []],
|
||||
snackbar: false,
|
||||
snackbarText: "",
|
||||
fontSize: parseInt(localStorage.getItem('fontSize')) || 28,
|
||||
fontSize: getSetting('font.size'),
|
||||
datePickerDialog: false,
|
||||
selectedDate: null,
|
||||
refreshInterval: null,
|
||||
autoSave: false,
|
||||
refreshBeforeEdit: false,
|
||||
showEmptySubjects: localStorage.getItem('showEmptySubjects') === 'true',
|
||||
emptySubjectDisplay: localStorage.getItem('emptySubjectDisplay') || 'card',
|
||||
subjectOrder: [
|
||||
"语文", "数学", "英语", "物理", "化学",
|
||||
"生物", "政治", "历史", "地理", "其他"
|
||||
],
|
||||
showNoDataMessage: false,
|
||||
noDataMessage: '',
|
||||
isToday: false,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -405,7 +543,6 @@ export default {
|
||||
name: value.name,
|
||||
content: value.content,
|
||||
order: this.subjectOrder.indexOf(key),
|
||||
// 计算每个卡片的行数
|
||||
rowSpan: value.content ?
|
||||
Math.ceil((value.content.split('\n').filter(line => line.trim()).length + 1) * 0.8) : 1
|
||||
}))
|
||||
@@ -416,8 +553,12 @@ export default {
|
||||
return true;
|
||||
});
|
||||
|
||||
// 对项目进行排序和优化布局
|
||||
return this.optimizeGridLayout(items);
|
||||
// 根据排序模式选择不同的排序方法
|
||||
if (this.dynamicSort) {
|
||||
return this.optimizeGridLayout(items);
|
||||
} else {
|
||||
return this.fixedGridLayout(items);
|
||||
}
|
||||
},
|
||||
attendanceVisible() {
|
||||
return this.studentList.length > 0;
|
||||
@@ -435,6 +576,18 @@ export default {
|
||||
.filter(subject => !subject.content)
|
||||
.sort((a, b) => a.order - b.order);
|
||||
},
|
||||
autoSave() {
|
||||
return getSetting('edit.autoSave');
|
||||
},
|
||||
refreshBeforeEdit() {
|
||||
return getSetting('edit.refreshBeforeEdit');
|
||||
},
|
||||
emptySubjectDisplay() {
|
||||
return getSetting('display.emptySubjectDisplay');
|
||||
},
|
||||
dynamicSort() {
|
||||
return getSetting('display.dynamicSort');
|
||||
},
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
@@ -442,14 +595,26 @@ export default {
|
||||
this.updateBackendUrl();
|
||||
await this.initializeData();
|
||||
this.setupAutoRefresh();
|
||||
this.autoSave = localStorage.getItem('autoSave') === 'true';
|
||||
this.refreshBeforeEdit = localStorage.getItem('refreshBeforeEdit') === 'true';
|
||||
|
||||
// 监听设置变化
|
||||
this.unwatchSettings = watchSettings(() => {
|
||||
this.updateSettings();
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("初始化失败:", err);
|
||||
this.showError("初始化失败,请刷新页面重试");
|
||||
}
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
if (this.unwatchSettings) {
|
||||
this.unwatchSettings();
|
||||
}
|
||||
if (this.refreshInterval) {
|
||||
clearInterval(this.refreshInterval);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async initializeData() {
|
||||
const res = await axios.get(`${this.backurl}/config`);
|
||||
@@ -593,7 +758,7 @@ export default {
|
||||
this.contentStyle = {
|
||||
"font-size": `${this.fontSize}px`,
|
||||
};
|
||||
localStorage.setItem('fontSize', this.fontSize.toString());
|
||||
setSetting('font.size', this.fontSize);
|
||||
},
|
||||
|
||||
async uploadData() {
|
||||
@@ -630,64 +795,42 @@ export default {
|
||||
},
|
||||
|
||||
async downloadDataDirectly() {
|
||||
const formattedDate = new Date(this.dateString).toISOString().split('T')[0];
|
||||
const res = await axios.get(
|
||||
`${this.backurl}/homework?date=${formattedDate}`
|
||||
);
|
||||
this.homeworkData = res.data.data || this.homeworkData;
|
||||
try {
|
||||
const formattedDate = new Date(this.dateString).toISOString().split('T')[0];
|
||||
const res = await axios.get(
|
||||
`${this.backurl}/homework?date=${formattedDate}`
|
||||
);
|
||||
|
||||
const subjectOrder = [
|
||||
"语文",
|
||||
"数学",
|
||||
"英语",
|
||||
"物理",
|
||||
"化学",
|
||||
"生物",
|
||||
"政治",
|
||||
"历史",
|
||||
"地理",
|
||||
"其他",
|
||||
];
|
||||
// 1. 将对象转换成数组,方便排序
|
||||
let sortedSubjects = Object.keys(this.homeworkData).map((key) => ({
|
||||
key,
|
||||
...this.homeworkData[key],
|
||||
}));
|
||||
// 检查是否是今天的日期
|
||||
const today = new Date();
|
||||
const isToday = today.toISOString().split('T')[0] === formattedDate;
|
||||
this.isToday = isToday;
|
||||
|
||||
// 2. 按照指定的顺序排序
|
||||
sortedSubjects.sort((a, b) => {
|
||||
const indexA = subjectOrder.indexOf(a.key);
|
||||
const indexB = subjectOrder.indexOf(b.key);
|
||||
|
||||
// 优先根据学科顺序排序
|
||||
if (indexA !== indexB) {
|
||||
return indexA - indexB;
|
||||
if (!res.data.status) {
|
||||
this.showNoDataMessage = true;
|
||||
this.noDataMessage = res.data.msg || '未找到数据';
|
||||
// 不再初始化作业数据,保持为空
|
||||
this.homeworkData = {};
|
||||
this.selectedSet.clear();
|
||||
this.lateSet.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
// 3. 进一步排序:将 content 为空的项移动到最后
|
||||
sortedSubjects = [
|
||||
// 先放置有 content 的项
|
||||
...sortedSubjects.filter((item) => item.content != ""),
|
||||
// 再放置 content 为空的项
|
||||
...sortedSubjects.filter((item) => item.content == ""),
|
||||
];
|
||||
|
||||
// 4. 将排序后的数组转换回对象
|
||||
this.homeworkData = sortedSubjects.reduce((acc, curr) => {
|
||||
acc[curr.key] = { name: curr.name, content: curr.content };
|
||||
return acc;
|
||||
}, {});
|
||||
this.selectedSet = new Set(res.data.attendance || []);
|
||||
this.lateSet = new Set(res.data.late || []); // Initialize late set
|
||||
this.synced = true;
|
||||
// 有数据的情况
|
||||
this.showNoDataMessage = false;
|
||||
this.homeworkData = res.data.data || {};
|
||||
this.selectedSet = new Set(res.data.attendance || []);
|
||||
this.lateSet = new Set(res.data.late || []);
|
||||
this.synced = true;
|
||||
} catch (error) {
|
||||
console.error('下载数据失败:', error);
|
||||
this.showError('下载数据失败,请重试');
|
||||
}
|
||||
},
|
||||
|
||||
updateBackendUrl() {
|
||||
const domain = localStorage.getItem('backendServerDomain');
|
||||
const classNum = localStorage.getItem('classNumber');
|
||||
const domain = getSetting('server.domain');
|
||||
const classNum = getSetting('server.classNumber');
|
||||
|
||||
if (domain && classNum) {
|
||||
this.backurl = `${domain}/${classNum}`;
|
||||
@@ -696,8 +839,12 @@ export default {
|
||||
},
|
||||
|
||||
setupAutoRefresh() {
|
||||
const autoRefresh = localStorage.getItem('autoRefresh') === 'true';
|
||||
const interval = parseInt(localStorage.getItem('refreshInterval')) || 300;
|
||||
const autoRefresh = getSetting('refresh.auto');
|
||||
const interval = getSetting('refresh.interval');
|
||||
|
||||
if (this.refreshInterval) {
|
||||
clearInterval(this.refreshInterval);
|
||||
}
|
||||
|
||||
if (autoRefresh) {
|
||||
this.refreshInterval = setInterval(() => {
|
||||
@@ -706,6 +853,18 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
updateSettings() {
|
||||
// 更新字体大小
|
||||
this.fontSize = getSetting('font.size');
|
||||
this.contentStyle = { "font-size": `${this.fontSize}px` };
|
||||
|
||||
// 更新自动刷新
|
||||
this.setupAutoRefresh();
|
||||
|
||||
// 更新服务器设置
|
||||
this.updateBackendUrl();
|
||||
},
|
||||
|
||||
handleDateSelect(newDate) {
|
||||
if (newDate) {
|
||||
// 使用本地时区处理日期,避免时区偏移
|
||||
@@ -721,12 +880,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
if (this.refreshInterval) {
|
||||
clearInterval(this.refreshInterval);
|
||||
}
|
||||
},
|
||||
|
||||
optimizeGridLayout(items) {
|
||||
// 首先按内容长度和科目顺序排序
|
||||
const sortedItems = items.sort((a, b) => {
|
||||
@@ -760,7 +913,73 @@ export default {
|
||||
...item,
|
||||
order: index
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
fixedGridLayout(items) {
|
||||
// 定义每行的科目顺序
|
||||
const rowSubjects = [
|
||||
["语文", "数学", "英语"],
|
||||
["物理", "化学", "生物"],
|
||||
["政治", "历史", "地理", "其他"]
|
||||
];
|
||||
|
||||
// 按照固定布局排序
|
||||
return items.sort((a, b) => {
|
||||
// 找出科目所在的行号
|
||||
const getRowIndex = (subject) => {
|
||||
for (let i = 0; i < rowSubjects.length; i++) {
|
||||
if (rowSubjects[i].includes(subject)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return rowSubjects.length; // 其他科目放最后
|
||||
};
|
||||
|
||||
// 获取科目在行内的位置
|
||||
const getColumnIndex = (subject) => {
|
||||
for (const row of rowSubjects) {
|
||||
const index = row.indexOf(subject);
|
||||
if (index !== -1) return index;
|
||||
}
|
||||
return 999; // 未知科目放最后
|
||||
};
|
||||
|
||||
const rowA = getRowIndex(a.key);
|
||||
const rowB = getRowIndex(b.key);
|
||||
|
||||
if (rowA !== rowB) {
|
||||
return rowA - rowB;
|
||||
}
|
||||
|
||||
// 同一行内按照预定义顺序排序
|
||||
const colA = getColumnIndex(a.key);
|
||||
const colB = getColumnIndex(b.key);
|
||||
return colA - colB;
|
||||
}).map((item, index) => ({
|
||||
...item,
|
||||
order: index,
|
||||
// 固定布局时每个卡片占用相同的行高
|
||||
rowSpan: item.content ? 2 : 1
|
||||
}));
|
||||
},
|
||||
|
||||
initializeAndOpenDialog() {
|
||||
// 初始化作业数据
|
||||
this.initializeHomeworkData();
|
||||
this.showNoDataMessage = false;
|
||||
this.synced = false; // 设置为未同步状态
|
||||
|
||||
// 如果启用了自动保存,初始化后自动上传
|
||||
if (this.autoSave) {
|
||||
this.uploadData();
|
||||
}
|
||||
|
||||
// 打开第一个科目的对话框
|
||||
const firstSubject = Object.keys(this.homeworkData)[0];
|
||||
if (firstSubject) {
|
||||
this.openDialog(firstSubject);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
||||
Reference in New Issue
Block a user