mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-07-05 02:59:23 +00:00
1
This commit is contained in:
parent
e31578ee10
commit
367954cfa6
@ -14,6 +14,8 @@
|
|||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
"roboto-fontface": "*",
|
"roboto-fontface": "*",
|
||||||
"vue": "^3.4.31",
|
"vue": "^3.4.31",
|
||||||
|
"vue-masonry-wall": "^0.3.2",
|
||||||
|
"vue-waterfall-plugin-next": "^2.6.5",
|
||||||
"vuetify": "^3.6.14"
|
"vuetify": "^3.6.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
42
pnpm-lock.yaml
generated
42
pnpm-lock.yaml
generated
@ -20,6 +20,12 @@ importers:
|
|||||||
vue:
|
vue:
|
||||||
specifier: ^3.4.31
|
specifier: ^3.4.31
|
||||||
version: 3.5.13
|
version: 3.5.13
|
||||||
|
vue-masonry-wall:
|
||||||
|
specifier: ^0.3.2
|
||||||
|
version: 0.3.2(lodash@4.17.21)(vue@3.5.13)
|
||||||
|
vue-waterfall-plugin-next:
|
||||||
|
specifier: ^2.6.5
|
||||||
|
version: 2.6.5
|
||||||
vuetify:
|
vuetify:
|
||||||
specifier: ^3.6.14
|
specifier: ^3.6.14
|
||||||
version: 3.7.4(vite-plugin-vuetify@2.0.4)(vue@3.5.13)
|
version: 3.7.4(vite-plugin-vuetify@2.0.4)(vue@3.5.13)
|
||||||
@ -360,55 +366,46 @@ packages:
|
|||||||
resolution: {integrity: sha512-6npqOKEPRZkLrMcvyC/32OzJ2srdPzCylJjiTJT2c0bwwSGm7nz2F9mNQ1WrAqCBZROcQn91Fno+khFhVijmFA==}
|
resolution: {integrity: sha512-6npqOKEPRZkLrMcvyC/32OzJ2srdPzCylJjiTJT2c0bwwSGm7nz2F9mNQ1WrAqCBZROcQn91Fno+khFhVijmFA==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.27.2':
|
'@rollup/rollup-linux-arm-musleabihf@4.27.2':
|
||||||
resolution: {integrity: sha512-V9Xg6eXtgBtHq2jnuQwM/jr2mwe2EycnopO8cbOvpzFuySCGtKlPCI3Hj9xup/pJK5Q0388qfZZy2DqV2J8ftw==}
|
resolution: {integrity: sha512-V9Xg6eXtgBtHq2jnuQwM/jr2mwe2EycnopO8cbOvpzFuySCGtKlPCI3Hj9xup/pJK5Q0388qfZZy2DqV2J8ftw==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.27.2':
|
'@rollup/rollup-linux-arm64-gnu@4.27.2':
|
||||||
resolution: {integrity: sha512-uCFX9gtZJoQl2xDTpRdseYuNqyKkuMDtH6zSrBTA28yTfKyjN9hQ2B04N5ynR8ILCoSDOrG/Eg+J2TtJ1e/CSA==}
|
resolution: {integrity: sha512-uCFX9gtZJoQl2xDTpRdseYuNqyKkuMDtH6zSrBTA28yTfKyjN9hQ2B04N5ynR8ILCoSDOrG/Eg+J2TtJ1e/CSA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.27.2':
|
'@rollup/rollup-linux-arm64-musl@4.27.2':
|
||||||
resolution: {integrity: sha512-/PU9P+7Rkz8JFYDHIi+xzHabOu9qEWR07L5nWLIUsvserrxegZExKCi2jhMZRd0ATdboKylu/K5yAXbp7fYFvA==}
|
resolution: {integrity: sha512-/PU9P+7Rkz8JFYDHIi+xzHabOu9qEWR07L5nWLIUsvserrxegZExKCi2jhMZRd0ATdboKylu/K5yAXbp7fYFvA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-powerpc64le-gnu@4.27.2':
|
'@rollup/rollup-linux-powerpc64le-gnu@4.27.2':
|
||||||
resolution: {integrity: sha512-eCHmol/dT5odMYi/N0R0HC8V8QE40rEpkyje/ZAXJYNNoSfrObOvG/Mn+s1F/FJyB7co7UQZZf6FuWnN6a7f4g==}
|
resolution: {integrity: sha512-eCHmol/dT5odMYi/N0R0HC8V8QE40rEpkyje/ZAXJYNNoSfrObOvG/Mn+s1F/FJyB7co7UQZZf6FuWnN6a7f4g==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.27.2':
|
'@rollup/rollup-linux-riscv64-gnu@4.27.2':
|
||||||
resolution: {integrity: sha512-DEP3Njr9/ADDln3kNi76PXonLMSSMiCir0VHXxmGSHxCxDfQ70oWjHcJGfiBugzaqmYdTC7Y+8Int6qbnxPBIQ==}
|
resolution: {integrity: sha512-DEP3Njr9/ADDln3kNi76PXonLMSSMiCir0VHXxmGSHxCxDfQ70oWjHcJGfiBugzaqmYdTC7Y+8Int6qbnxPBIQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.27.2':
|
'@rollup/rollup-linux-s390x-gnu@4.27.2':
|
||||||
resolution: {integrity: sha512-NHGo5i6IE/PtEPh5m0yw5OmPMpesFnzMIS/lzvN5vknnC1sXM5Z/id5VgcNPgpD+wHmIcuYYgW+Q53v+9s96lQ==}
|
resolution: {integrity: sha512-NHGo5i6IE/PtEPh5m0yw5OmPMpesFnzMIS/lzvN5vknnC1sXM5Z/id5VgcNPgpD+wHmIcuYYgW+Q53v+9s96lQ==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.27.2':
|
'@rollup/rollup-linux-x64-gnu@4.27.2':
|
||||||
resolution: {integrity: sha512-PaW2DY5Tan+IFvNJGHDmUrORadbe/Ceh8tQxi8cmdQVCCYsLoQo2cuaSj+AU+YRX8M4ivS2vJ9UGaxfuNN7gmg==}
|
resolution: {integrity: sha512-PaW2DY5Tan+IFvNJGHDmUrORadbe/Ceh8tQxi8cmdQVCCYsLoQo2cuaSj+AU+YRX8M4ivS2vJ9UGaxfuNN7gmg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.27.2':
|
'@rollup/rollup-linux-x64-musl@4.27.2':
|
||||||
resolution: {integrity: sha512-dOlWEMg2gI91Qx5I/HYqOD6iqlJspxLcS4Zlg3vjk1srE67z5T2Uz91yg/qA8sY0XcwQrFzWWiZhMNERylLrpQ==}
|
resolution: {integrity: sha512-dOlWEMg2gI91Qx5I/HYqOD6iqlJspxLcS4Zlg3vjk1srE67z5T2Uz91yg/qA8sY0XcwQrFzWWiZhMNERylLrpQ==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-win32-arm64-msvc@4.27.2':
|
'@rollup/rollup-win32-arm64-msvc@4.27.2':
|
||||||
resolution: {integrity: sha512-euMIv/4x5Y2/ImlbGl88mwKNXDsvzbWUlT7DFky76z2keajCtcbAsN9LUdmk31hAoVmJJYSThgdA0EsPeTr1+w==}
|
resolution: {integrity: sha512-euMIv/4x5Y2/ImlbGl88mwKNXDsvzbWUlT7DFky76z2keajCtcbAsN9LUdmk31hAoVmJJYSThgdA0EsPeTr1+w==}
|
||||||
@ -1727,11 +1724,24 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=6.0.0'
|
eslint: '>=6.0.0'
|
||||||
|
|
||||||
|
vue-masonry-wall@0.3.2:
|
||||||
|
resolution: {integrity: sha512-uy/tY9Lz6zVZCXmS78sv5u1yf70gAC+ElFXdV8miJfLiNnzXXt2i03I8sccx2YXDKk1IOZv6wDbKTUL8ethvfw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
lodash: ^4.17.15
|
||||||
|
vue: ^2.6.10
|
||||||
|
|
||||||
|
vue-observe-visibility@0.4.6:
|
||||||
|
resolution: {integrity: sha512-xo0CEVdkjSjhJoDdLSvoZoQrw/H2BlzB5jrCBKGZNXN2zdZgMuZ9BKrxXDjNP2AxlcCoKc8OahI3F3r3JGLv2Q==}
|
||||||
|
|
||||||
vue-router@4.4.5:
|
vue-router@4.4.5:
|
||||||
resolution: {integrity: sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==}
|
resolution: {integrity: sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: ^3.2.0
|
vue: ^3.2.0
|
||||||
|
|
||||||
|
vue-waterfall-plugin-next@2.6.5:
|
||||||
|
resolution: {integrity: sha512-8ACGbdjoyKLiJfnKXB8h8f9eE14lhyzfI1N1nrfVAIRczSpNY1KRwGOnVXN5OHqheLl3V1C0uVVRPtjTJkHkhw==}
|
||||||
|
|
||||||
vue@3.5.13:
|
vue@3.5.13:
|
||||||
resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
|
resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -2088,7 +2098,7 @@ snapshots:
|
|||||||
|
|
||||||
'@vue/shared@3.5.13': {}
|
'@vue/shared@3.5.13': {}
|
||||||
|
|
||||||
'@vuetify/loader-shared@2.0.3(vue@3.5.13)(vuetify@3.7.4(vite-plugin-vuetify@2.0.4)(vue@3.5.13))':
|
'@vuetify/loader-shared@2.0.3(vue@3.5.13)(vuetify@3.7.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
upath: 2.0.1
|
upath: 2.0.1
|
||||||
vue: 3.5.13
|
vue: 3.5.13
|
||||||
@ -3443,7 +3453,7 @@ snapshots:
|
|||||||
|
|
||||||
vite-plugin-vuetify@2.0.4(vite@5.4.11(sass-embedded@1.81.0)(sass@1.77.8))(vue@3.5.13)(vuetify@3.7.4):
|
vite-plugin-vuetify@2.0.4(vite@5.4.11(sass-embedded@1.81.0)(sass@1.77.8))(vue@3.5.13)(vuetify@3.7.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vuetify/loader-shared': 2.0.3(vue@3.5.13)(vuetify@3.7.4(vite-plugin-vuetify@2.0.4)(vue@3.5.13))
|
'@vuetify/loader-shared': 2.0.3(vue@3.5.13)(vuetify@3.7.4)
|
||||||
debug: 4.3.7
|
debug: 4.3.7
|
||||||
upath: 2.0.1
|
upath: 2.0.1
|
||||||
vite: 5.4.11(sass-embedded@1.81.0)(sass@1.77.8)
|
vite: 5.4.11(sass-embedded@1.81.0)(sass@1.77.8)
|
||||||
@ -3479,11 +3489,21 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
vue-masonry-wall@0.3.2(lodash@4.17.21)(vue@3.5.13):
|
||||||
|
dependencies:
|
||||||
|
lodash: 4.17.21
|
||||||
|
vue: 3.5.13
|
||||||
|
vue-observe-visibility: 0.4.6
|
||||||
|
|
||||||
|
vue-observe-visibility@0.4.6: {}
|
||||||
|
|
||||||
vue-router@4.4.5(vue@3.5.13):
|
vue-router@4.4.5(vue@3.5.13):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/devtools-api': 6.6.4
|
'@vue/devtools-api': 6.6.4
|
||||||
vue: 3.5.13
|
vue: 3.5.13
|
||||||
|
|
||||||
|
vue-waterfall-plugin-next@2.6.5: {}
|
||||||
|
|
||||||
vue@3.5.13:
|
vue@3.5.13:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-dom': 3.5.13
|
'@vue/compiler-dom': 3.5.13
|
||||||
|
@ -58,46 +58,68 @@
|
|||||||
fluid
|
fluid
|
||||||
>
|
>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="11">
|
<v-col :cols="attendanceVisible ? 11 : 12">
|
||||||
<v-container
|
<div class="grid-masonry" ref="gridContainer">
|
||||||
fluid
|
<div
|
||||||
style="padding-left: 2px; padding-right: 2px"
|
v-for="item in sortedItems"
|
||||||
>
|
:key="item.key"
|
||||||
<v-row
|
class="grid-item"
|
||||||
v-for="subjects in homeworkArrange"
|
:class="{
|
||||||
:key="subjects.name"
|
'empty-card': !item.content,
|
||||||
|
[`grid-row-${item.rowSpan}`]: true
|
||||||
|
}"
|
||||||
|
:style="{
|
||||||
|
'grid-row-end': `span ${item.rowSpan}`,
|
||||||
|
order: item.order
|
||||||
|
}"
|
||||||
|
@click="openDialog(item.key)"
|
||||||
>
|
>
|
||||||
<v-col
|
<v-card border height="100%">
|
||||||
v-for="subject in subjects"
|
<v-card-title :class="{ 'text-subtitle-1': !item.content }">
|
||||||
:key="subject"
|
{{ item.name }}
|
||||||
cols="4"
|
</v-card-title>
|
||||||
style="padding: 2px !important"
|
<v-card-text :style="item.content ? contentStyle : null">
|
||||||
@click="openDialog(subject)"
|
<template v-if="item.content">
|
||||||
>
|
|
||||||
<v-card border>
|
|
||||||
<v-card-title>{{ homeworkData[subject].name }}</v-card-title>
|
|
||||||
<v-card-text :style="contentStyle">
|
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-for="text in splitPoint(homeworkData[subject].content)"
|
v-for="text in splitPoint(item.content)"
|
||||||
:key="text"
|
:key="text"
|
||||||
>
|
>
|
||||||
{{ text }}
|
{{ text }}
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-card-text>
|
</template>
|
||||||
</v-card>
|
<template v-else>
|
||||||
</v-col>
|
<div class="text-center pa-2">
|
||||||
</v-row>
|
<v-icon size="small" color="grey">mdi-plus</v-icon>
|
||||||
</v-container>
|
<div class="text-caption text-grey">点击添加作业</div>
|
||||||
<div />
|
</div>
|
||||||
</v-col>
|
</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="openDialog(subject.key)"
|
||||||
|
>
|
||||||
|
<v-icon start>mdi-plus</v-icon>
|
||||||
|
{{ subject.name }}
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
<v-col
|
<v-col
|
||||||
v-if="studentList.length"
|
v-if="studentList.length"
|
||||||
class="attendance-area"
|
class="attendance-area"
|
||||||
cols="1"
|
:cols="1"
|
||||||
@click="setAttendanceArea"
|
@click="setAttendanceArea"
|
||||||
>
|
>
|
||||||
<h1>出勤</h1>
|
<h1>出勤</h1>
|
||||||
@ -120,6 +142,22 @@
|
|||||||
>
|
>
|
||||||
{{ `${index + 1}. ${studentList[i]}` }}
|
{{ `${index + 1}. ${studentList[i]}` }}
|
||||||
</h3>
|
</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)"
|
||||||
|
>
|
||||||
|
{{ subject.name }}
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
@ -213,6 +251,88 @@
|
|||||||
</v-snackbar>
|
</v-snackbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.grid-masonry {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
padding: 8px;
|
||||||
|
grid-auto-flow: dense;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item {
|
||||||
|
width: 100%;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-card {
|
||||||
|
transform: scale(0.9);
|
||||||
|
opacity: 0.8;
|
||||||
|
grid-row-end: span 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-card:hover {
|
||||||
|
transform: scale(0.95);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-subjects-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-subject-btn {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1199px) {
|
||||||
|
.grid-masonry {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 799px) {
|
||||||
|
.grid-masonry {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-subject-btn {
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-card {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保容器高度不超过视口 */
|
||||||
|
.main-window {
|
||||||
|
max-height: calc(100vh - 180px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 优化滚动条样式 */
|
||||||
|
.main-window::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-window::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-window::-webkit-scrollbar-thumb {
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-window::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useDisplay } from "vuetify";
|
import { useDisplay } from "vuetify";
|
||||||
@ -246,6 +366,12 @@ export default {
|
|||||||
refreshInterval: null,
|
refreshInterval: null,
|
||||||
autoSave: false,
|
autoSave: false,
|
||||||
refreshBeforeEdit: false,
|
refreshBeforeEdit: false,
|
||||||
|
showEmptySubjects: localStorage.getItem('showEmptySubjects') === 'true',
|
||||||
|
emptySubjectDisplay: localStorage.getItem('emptySubjectDisplay') || 'card',
|
||||||
|
subjectOrder: [
|
||||||
|
"语文", "数学", "英语", "物理", "化学",
|
||||||
|
"生物", "政治", "历史", "地理", "其他"
|
||||||
|
],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -272,6 +398,43 @@ export default {
|
|||||||
return `${this.dateString}的作业`;
|
return `${this.dateString}的作业`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
sortedItems() {
|
||||||
|
const items = Object.entries(this.homeworkData)
|
||||||
|
.map(([key, value]) => ({
|
||||||
|
key,
|
||||||
|
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
|
||||||
|
}))
|
||||||
|
.filter(item => {
|
||||||
|
if (this.emptySubjectDisplay === 'button') {
|
||||||
|
return item.content;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 对项目进行排序和优化布局
|
||||||
|
return this.optimizeGridLayout(items);
|
||||||
|
},
|
||||||
|
attendanceVisible() {
|
||||||
|
return this.studentList.length > 0;
|
||||||
|
},
|
||||||
|
emptySubjects() {
|
||||||
|
if (this.emptySubjectDisplay !== 'button') return [];
|
||||||
|
|
||||||
|
return Object.entries(this.homeworkData)
|
||||||
|
.map(([key, value]) => ({
|
||||||
|
key,
|
||||||
|
name: value.name,
|
||||||
|
content: value.content,
|
||||||
|
order: this.subjectOrder.indexOf(key)
|
||||||
|
}))
|
||||||
|
.filter(subject => !subject.content)
|
||||||
|
.sort((a, b) => a.order - b.order);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
@ -563,6 +726,65 @@ export default {
|
|||||||
clearInterval(this.refreshInterval);
|
clearInterval(this.refreshInterval);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
optimizeGridLayout(items) {
|
||||||
|
// 首先按内容长度和科目顺序排序
|
||||||
|
const sortedItems = items.sort((a, b) => {
|
||||||
|
// 有内容的排在前面
|
||||||
|
if (a.content && !b.content) return -1;
|
||||||
|
if (!a.content && b.content) return 1;
|
||||||
|
|
||||||
|
// 内容较长的优先
|
||||||
|
if (a.content && b.content) {
|
||||||
|
const lengthDiff = b.rowSpan - a.rowSpan;
|
||||||
|
if (lengthDiff !== 0) return lengthDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最后按科目顺序
|
||||||
|
return a.order - b.order;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 计算每列的当前高度
|
||||||
|
const columnHeights = [0, 0, 0];
|
||||||
|
const columnItems = [[], [], []];
|
||||||
|
|
||||||
|
// 分配项目到最短的列
|
||||||
|
sortedItems.forEach(item => {
|
||||||
|
const shortestColumn = columnHeights.indexOf(Math.min(...columnHeights));
|
||||||
|
columnHeights[shortestColumn] += item.rowSpan;
|
||||||
|
columnItems[shortestColumn].push(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 将所有列的项目合并,并设置显示顺序
|
||||||
|
return columnItems.flat().map((item, index) => ({
|
||||||
|
...item,
|
||||||
|
order: index
|
||||||
|
}));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
homeworkData: {
|
||||||
|
handler() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.waterfall) {
|
||||||
|
this.$refs.waterfall.reflow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
// 监听窗口大小变化
|
||||||
|
'$vuetify.display.width': {
|
||||||
|
handler() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.gridContainer) {
|
||||||
|
// 触发重新布局
|
||||||
|
this.optimizeGridLayout(this.sortedItems);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -484,6 +484,86 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
|
<v-switch
|
||||||
|
v-model="showEmptySubjects"
|
||||||
|
label="显示空作业科目"
|
||||||
|
hint="是否在主界面显示没有作业内容的科目"
|
||||||
|
persistent-hint
|
||||||
|
@change="saveSettings"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-card elevation="2" class="rounded-lg">
|
||||||
|
<v-card-item>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon icon="mdi-card-outline" size="large" class="mr-2" />
|
||||||
|
</template>
|
||||||
|
<v-card-title class="text-h6">空作业显示设置</v-card-title>
|
||||||
|
</v-card-item>
|
||||||
|
|
||||||
|
<v-card-text>
|
||||||
|
<v-radio-group
|
||||||
|
v-model="emptySubjectDisplay"
|
||||||
|
label="空作业显示方式"
|
||||||
|
>
|
||||||
|
<v-radio
|
||||||
|
value="card"
|
||||||
|
label="显示为空卡片"
|
||||||
|
>
|
||||||
|
<template v-slot:label>
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
显示为空卡片
|
||||||
|
<v-tooltip location="right">
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-icon
|
||||||
|
v-bind="props"
|
||||||
|
icon="mdi-help-circle-outline"
|
||||||
|
size="small"
|
||||||
|
class="ml-2"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
在主界面中显示为可点击的空白卡片
|
||||||
|
</v-tooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</v-radio>
|
||||||
|
<v-radio
|
||||||
|
value="button"
|
||||||
|
label="显示为按钮组"
|
||||||
|
>
|
||||||
|
<template v-slot:label>
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
显示为按钮组
|
||||||
|
<v-tooltip location="right">
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-icon
|
||||||
|
v-bind="props"
|
||||||
|
icon="mdi-help-circle-outline"
|
||||||
|
size="small"
|
||||||
|
class="ml-2"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
在主界面底部显示为一组添加按钮
|
||||||
|
</v-tooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</v-radio>
|
||||||
|
</v-radio-group>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-card-actions class="px-4 pb-4">
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
prepend-icon="mdi-content-save"
|
||||||
|
block
|
||||||
|
@click="saveEmptySubjectSettings"
|
||||||
|
>
|
||||||
|
保存设置
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|
||||||
<v-snackbar v-model="snackbar">
|
<v-snackbar v-model="snackbar">
|
||||||
@ -575,6 +655,8 @@ export default {
|
|||||||
studentToMove: null,
|
studentToMove: null,
|
||||||
touchStartTime: 0,
|
touchStartTime: 0,
|
||||||
touchTimeout: null,
|
touchTimeout: null,
|
||||||
|
showEmptySubjects: localStorage.getItem('showEmptySubjects') === 'true',
|
||||||
|
emptySubjectDisplay: localStorage.getItem('emptySubjectDisplay') || 'card',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -824,6 +906,16 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
saveSettings() {
|
||||||
|
localStorage.setItem('showEmptySubjects', this.showEmptySubjects.toString());
|
||||||
|
localStorage.setItem('emptySubjectDisplay', this.emptySubjectDisplay);
|
||||||
|
},
|
||||||
|
|
||||||
|
saveEmptySubjectSettings() {
|
||||||
|
this.saveSettings();
|
||||||
|
this.showMessage('保存成功');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user