1
0
mirror of https://github.com/ZeroCatDev/Classworks.git synced 2025-12-07 21:13:11 +00:00

feat: 添加作业内容复制到今天的功能,优化浮动工具栏

This commit is contained in:
Sunwuyuan 2025-11-30 13:06:36 +08:00
parent 3182699a78
commit 8f7b3db552
No known key found for this signature in database
GPG Key ID: A6A54CF66F56BB64
2 changed files with 207 additions and 81 deletions

View File

@ -1,81 +1,96 @@
<template>
<v-slide-y-transition>
<v-card
:class="{ 'toolbar-expanded': isExpanded }"
class="floating-toolbar"
elevation="4"
rounded="xl"
>
<div class="floating-toolbar-container">
<v-slide-y-transition>
<v-card
:class="{ 'toolbar-expanded': isExpanded }"
class="floating-toolbar"
elevation="4"
rounded="xl"
>
<v-btn-group class="toolbar-buttons" variant="text">
<v-btn
v-ripple
:title="'查看昨天'"
class="toolbar-btn"
icon="mdi-chevron-left"
variant="text"
@click="$emit('prev-day')"
/>
<v-btn
v-ripple
:title="'缩小字体'"
class="toolbar-btn"
icon="mdi-format-font-size-decrease"
variant="text"
@click="$emit('zoom', 'out')"
/>
<v-btn
v-ripple
:title="'放大字体'"
class="toolbar-btn"
icon="mdi-format-font-size-increase"
variant="text"
@click="$emit('zoom', 'up')"
/>
<v-menu :close-on-content-click="false" location="top">
<template #activator="{ props }">
<v-btn
v-ripple
:title="'选择日期'"
class="toolbar-btn"
icon="mdi-calendar"
v-bind="props"
variant="text"
/>
</template>
<v-card border class="date-picker-card">
<v-date-picker
:model-value="selectedDate"
color="primary"
@update:model-value="handleDateSelect"
/>
</v-card>
</v-menu>
<v-btn
v-ripple
:loading="loading"
:title="'刷新数据'"
class="toolbar-btn"
icon="mdi-refresh"
variant="text"
@click="$emit('refresh')"
/>
<v-btn
v-if="!isToday"
v-ripple
:title="'查看明天'"
class="toolbar-btn"
icon="mdi-chevron-right"
variant="text"
@click="$emit('next-day')"
/>
</v-btn-group>
</v-card>
</v-slide-y-transition>
<v-btn-group class="toolbar-buttons" variant="text">
<v-btn
v-ripple
:title="'查看昨天'"
class="toolbar-btn"
icon="mdi-chevron-left"
variant="text"
@click="$emit('prev-day')"
/>
<v-btn
v-ripple
:title="'缩小字体'"
class="toolbar-btn"
icon="mdi-format-font-size-decrease"
variant="text"
@click="$emit('zoom', 'out')"
/>
<v-btn
v-ripple
:title="'放大字体'"
class="toolbar-btn"
icon="mdi-format-font-size-increase"
variant="text"
@click="$emit('zoom', 'up')"
/>
<v-menu :close-on-content-click="false" location="top">
<template #activator="{ props }">
<v-btn
v-ripple
:title="'选择日期'"
class="toolbar-btn"
icon="mdi-calendar"
v-bind="props"
variant="text"
/>
</template>
<v-card border class="date-picker-card">
<v-date-picker
:model-value="selectedDate"
color="primary"
@update:model-value="handleDateSelect"
/>
</v-card>
</v-menu>
<v-btn
v-ripple
:loading="loading"
:title="'刷新数据'"
class="toolbar-btn"
icon="mdi-refresh"
variant="text"
@click="$emit('refresh')"
/>
<v-btn
v-if="!isToday"
v-ripple
:title="'查看明天'"
class="toolbar-btn"
icon="mdi-chevron-right"
variant="text"
@click="$emit('next-day')"
/>
</v-btn-group>
</v-card>
</v-slide-y-transition>
<!-- Side Action Button -->
<v-slide-x-reverse-transition>
<v-btn
v-if="!isToday"
:loading="copyToTodayLoading"
:disabled="copyToTodayLoading"
class="side-action-btn"
color="primary"
elevation="4"
prepend-icon="mdi-content-copy"
rounded="xl"
size="large"
text="复制作业内容到今天"
@click="$emit('copy-to-today')"
>复制到今天</v-btn>
</v-slide-x-reverse-transition>
</div>
</template>
<script>
@ -98,6 +113,10 @@ export default {
type: Boolean,
required: true,
},
copyToTodayLoading: {
type: Boolean,
default: false,
},
},
data() {
return {
@ -113,12 +132,24 @@ export default {
</script>
<style scoped>
.floating-toolbar {
.floating-toolbar-container {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 0;
z-index: 100;
display: flex;
justify-content: center;
pointer-events: none;
}
.floating-toolbar {
position: absolute;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
z-index: 100;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
background: rgba(255, 255, 255, 0.7) !important;
backdrop-filter: blur(12px);
@ -132,7 +163,9 @@ export default {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 0px;
padding: 0 4px;
pointer-events: auto;
will-change: transform;
}
.floating-toolbar:hover {
@ -140,6 +173,15 @@ export default {
background: rgba(255, 255, 255, 0.8) !important;
}
.toolbar-buttons {
display: flex;
align-items: center;
}
.toolbar-btn {
margin: 0 2px;
}
.toolbar-btn:hover {
background: rgba(255, 255, 255, 0.3) !important;
transform: scale(1.05);
@ -149,6 +191,17 @@ export default {
transform: scale(0.95);
}
.side-action-btn {
position: absolute;
bottom: 24px;
right: 24px;
pointer-events: auto;
z-index: 101;
background: rgba(255, 255, 255, 0.9) !important;
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.date-picker-card {
border-radius: 16px;
overflow: hidden;
@ -161,7 +214,8 @@ export default {
@media (max-width: 600px) {
.floating-toolbar {
bottom: 16px;
width: 95%;
width: auto;
max-width: 95%;
padding: 2px;
}
@ -173,10 +227,12 @@ export default {
.toolbar-btn {
margin: 0;
min-width: 40px; /* Ensure touch target */
}
.nav-btn {
margin: 0 2px;
.side-action-btn {
bottom: 80px; /* Move above toolbar on mobile */
right: 16px;
}
}
@ -199,5 +255,11 @@ export default {
background: rgba(30, 30, 30, 0.9) !important;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.side-action-btn {
background: rgba(30, 30, 30, 0.9) !important;
border: 1px solid rgba(255, 255, 255, 0.1);
color: white !important;
}
}
</style>

View File

@ -207,6 +207,7 @@
<floating-toolbar
:is-today="isToday"
:loading="loading.download"
:copy-to-today-loading="loading.copyToToday"
:selected-date="state.selectedDateObj"
:unread-count="unreadCount"
@refresh="downloadData"
@ -216,6 +217,7 @@
@date-select="handleDateSelect"
@prev-day="navigateDay(-1)"
@next-day="navigateDay(1)"
@copy-to-today="copyHomeworkToToday"
/>
<!-- 添加ICP备案悬浮组件 -->
@ -433,6 +435,7 @@ export default {
download: false,
upload: false,
students: false,
copyToToday: false,
},
debouncedUpload: null,
debouncedAttendanceSave: null,
@ -1914,6 +1917,67 @@ export default {
this.handleDateSelect(currentDate);
},
async copyHomeworkToToday() {
if (this.loading.copyToToday) return;
try {
this.loading.copyToToday = true;
// 1.
const sourceDate = this.state.dateString;
const sourceHomework = JSON.parse(JSON.stringify(this.state.boardData.homework));
// 2.
const today = this.getToday();
const todayString = this.formatDate(today);
//
this.state.dateString = todayString;
await this.downloadData();
// 3. 使
//
const newHomework = {};
for (const key in sourceHomework) {
if (sourceHomework[key] && sourceHomework[key].content) {
//
if (sourceHomework[key].type === 'custom') {
newHomework[key] = JSON.parse(JSON.stringify(sourceHomework[key]));
} else {
//
newHomework[key] = {
content: sourceHomework[key].content
};
}
}
}
//
this.state.boardData.homework = newHomework;
this.state.synced = false;
// 4.
await this.uploadData();
// 5.
this.state.selectedDate = todayString;
this.state.selectedDateObj = today;
this.state.isToday = true;
// 6. URL
const url = new URL(window.location);
url.searchParams.delete('date');
window.history.pushState({}, '', url);
this.$message.success("复制成功", `已将 ${sourceDate} 的作业内容复制到今天(已替换原有作业)`);
} catch (error) {
console.error("复制作业失败:", error);
this.$message.error("复制失败", error.message || "请重试");
} finally {
this.loading.copyToToday = false;
}
},
//
parsePreconfigData() {
try {