Skip to content

Commit 8f7b3db

Browse files
committed
feat: 添加作业内容复制到今天的功能,优化浮动工具栏
1 parent 3182699 commit 8f7b3db

File tree

2 files changed

+209
-83
lines changed

2 files changed

+209
-83
lines changed

src/components/FloatingToolbar.vue

Lines changed: 145 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,96 @@
11
<template>
2-
<v-slide-y-transition>
3-
<v-card
4-
:class="{ 'toolbar-expanded': isExpanded }"
5-
class="floating-toolbar"
6-
elevation="4"
7-
rounded="xl"
8-
>
9-
10-
11-
<v-btn-group class="toolbar-buttons" variant="text">
12-
<v-btn
13-
v-ripple
14-
:title="'查看昨天'"
15-
class="toolbar-btn"
16-
icon="mdi-chevron-left"
17-
variant="text"
18-
@click="$emit('prev-day')"
19-
/>
20-
<v-btn
21-
v-ripple
22-
:title="'缩小字体'"
23-
class="toolbar-btn"
24-
icon="mdi-format-font-size-decrease"
25-
variant="text"
26-
@click="$emit('zoom', 'out')"
27-
/>
28-
<v-btn
29-
v-ripple
30-
:title="'放大字体'"
31-
class="toolbar-btn"
32-
icon="mdi-format-font-size-increase"
33-
variant="text"
34-
@click="$emit('zoom', 'up')"
35-
/>
36-
<v-menu :close-on-content-click="false" location="top">
37-
<template #activator="{ props }">
38-
<v-btn
39-
v-ripple
40-
:title="'选择日期'"
41-
class="toolbar-btn"
42-
icon="mdi-calendar"
43-
v-bind="props"
44-
variant="text"
45-
/>
46-
</template>
47-
<v-card border class="date-picker-card">
48-
<v-date-picker
49-
:model-value="selectedDate"
50-
color="primary"
51-
@update:model-value="handleDateSelect"
52-
/>
53-
</v-card>
54-
</v-menu>
55-
<v-btn
56-
v-ripple
57-
:loading="loading"
58-
:title="'刷新数据'"
59-
class="toolbar-btn"
60-
icon="mdi-refresh"
61-
variant="text"
62-
@click="$emit('refresh')"
63-
/>
64-
65-
<v-btn
66-
v-if="!isToday"
67-
v-ripple
68-
:title="'查看明天'"
69-
class="toolbar-btn"
70-
icon="mdi-chevron-right"
71-
variant="text"
72-
@click="$emit('next-day')"
73-
/>
74-
</v-btn-group>
75-
76-
77-
</v-card>
78-
</v-slide-y-transition>
2+
<div class="floating-toolbar-container">
3+
<v-slide-y-transition>
4+
<v-card
5+
:class="{ 'toolbar-expanded': isExpanded }"
6+
class="floating-toolbar"
7+
elevation="4"
8+
rounded="xl"
9+
>
10+
<v-btn-group class="toolbar-buttons" variant="text">
11+
<v-btn
12+
v-ripple
13+
:title="'查看昨天'"
14+
class="toolbar-btn"
15+
icon="mdi-chevron-left"
16+
variant="text"
17+
@click="$emit('prev-day')"
18+
/>
19+
<v-btn
20+
v-ripple
21+
:title="'缩小字体'"
22+
class="toolbar-btn"
23+
icon="mdi-format-font-size-decrease"
24+
variant="text"
25+
@click="$emit('zoom', 'out')"
26+
/>
27+
<v-btn
28+
v-ripple
29+
:title="'放大字体'"
30+
class="toolbar-btn"
31+
icon="mdi-format-font-size-increase"
32+
variant="text"
33+
@click="$emit('zoom', 'up')"
34+
/>
35+
<v-menu :close-on-content-click="false" location="top">
36+
<template #activator="{ props }">
37+
<v-btn
38+
v-ripple
39+
:title="'选择日期'"
40+
class="toolbar-btn"
41+
icon="mdi-calendar"
42+
v-bind="props"
43+
variant="text"
44+
/>
45+
</template>
46+
<v-card border class="date-picker-card">
47+
<v-date-picker
48+
:model-value="selectedDate"
49+
color="primary"
50+
@update:model-value="handleDateSelect"
51+
/>
52+
</v-card>
53+
</v-menu>
54+
<v-btn
55+
v-ripple
56+
:loading="loading"
57+
:title="'刷新数据'"
58+
class="toolbar-btn"
59+
icon="mdi-refresh"
60+
variant="text"
61+
@click="$emit('refresh')"
62+
/>
63+
64+
<v-btn
65+
v-if="!isToday"
66+
v-ripple
67+
:title="'查看明天'"
68+
class="toolbar-btn"
69+
icon="mdi-chevron-right"
70+
variant="text"
71+
@click="$emit('next-day')"
72+
/>
73+
</v-btn-group>
74+
</v-card>
75+
</v-slide-y-transition>
76+
77+
<!-- Side Action Button -->
78+
<v-slide-x-reverse-transition>
79+
<v-btn
80+
v-if="!isToday"
81+
:loading="copyToTodayLoading"
82+
:disabled="copyToTodayLoading"
83+
class="side-action-btn"
84+
color="primary"
85+
elevation="4"
86+
prepend-icon="mdi-content-copy"
87+
rounded="xl"
88+
size="large"
89+
text="复制作业内容到今天"
90+
@click="$emit('copy-to-today')"
91+
>复制到今天</v-btn>
92+
</v-slide-x-reverse-transition>
93+
</div>
7994
</template>
8095

8196
<script>
@@ -98,6 +113,10 @@ export default {
98113
type: Boolean,
99114
required: true,
100115
},
116+
copyToTodayLoading: {
117+
type: Boolean,
118+
default: false,
119+
},
101120
},
102121
data() {
103122
return {
@@ -113,12 +132,24 @@ export default {
113132
</script>
114133

115134
<style scoped>
116-
.floating-toolbar {
135+
.floating-toolbar-container {
117136
position: fixed;
137+
bottom: 0;
138+
left: 0;
139+
width: 100%;
140+
height: 0;
141+
z-index: 100;
142+
display: flex;
143+
justify-content: center;
144+
pointer-events: none;
145+
}
146+
147+
.floating-toolbar {
148+
position: absolute;
118149
bottom: 24px;
119150
left: 50%;
120151
transform: translateX(-50%);
121-
z-index: 100;
152+
122153
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
123154
background: rgba(255, 255, 255, 0.7) !important;
124155
backdrop-filter: blur(12px);
@@ -132,14 +163,25 @@ export default {
132163
display: flex;
133164
align-items: center;
134165
justify-content: space-between;
135-
padding: 0 0px;
166+
padding: 0 4px;
167+
pointer-events: auto;
168+
will-change: transform;
136169
}
137170
138171
.floating-toolbar:hover {
139172
transform: translateX(-50%) translateY(-4px);
140173
background: rgba(255, 255, 255, 0.8) !important;
141174
}
142175
176+
.toolbar-buttons {
177+
display: flex;
178+
align-items: center;
179+
}
180+
181+
.toolbar-btn {
182+
margin: 0 2px;
183+
}
184+
143185
.toolbar-btn:hover {
144186
background: rgba(255, 255, 255, 0.3) !important;
145187
transform: scale(1.05);
@@ -149,6 +191,17 @@ export default {
149191
transform: scale(0.95);
150192
}
151193
194+
.side-action-btn {
195+
position: absolute;
196+
bottom: 24px;
197+
right: 24px;
198+
pointer-events: auto;
199+
z-index: 101;
200+
background: rgba(255, 255, 255, 0.9) !important;
201+
backdrop-filter: blur(12px);
202+
border: 1px solid rgba(255, 255, 255, 0.2);
203+
}
204+
152205
.date-picker-card {
153206
border-radius: 16px;
154207
overflow: hidden;
@@ -161,7 +214,8 @@ export default {
161214
@media (max-width: 600px) {
162215
.floating-toolbar {
163216
bottom: 16px;
164-
width: 95%;
217+
width: auto;
218+
max-width: 95%;
165219
padding: 2px;
166220
}
167221
@@ -173,10 +227,12 @@ export default {
173227
174228
.toolbar-btn {
175229
margin: 0;
230+
min-width: 40px; /* Ensure touch target */
176231
}
177232
178-
.nav-btn {
179-
margin: 0 2px;
233+
.side-action-btn {
234+
bottom: 80px; /* Move above toolbar on mobile */
235+
right: 16px;
180236
}
181237
}
182238
@@ -199,5 +255,11 @@ export default {
199255
background: rgba(30, 30, 30, 0.9) !important;
200256
border: 1px solid rgba(255, 255, 255, 0.1);
201257
}
258+
259+
.side-action-btn {
260+
background: rgba(30, 30, 30, 0.9) !important;
261+
border: 1px solid rgba(255, 255, 255, 0.1);
262+
color: white !important;
263+
}
202264
}
203265
</style>

src/pages/index.vue

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@
207207
<floating-toolbar
208208
:is-today="isToday"
209209
:loading="loading.download"
210+
:copy-to-today-loading="loading.copyToToday"
210211
:selected-date="state.selectedDateObj"
211212
:unread-count="unreadCount"
212213
@refresh="downloadData"
@@ -216,6 +217,7 @@
216217
@date-select="handleDateSelect"
217218
@prev-day="navigateDay(-1)"
218219
@next-day="navigateDay(1)"
220+
@copy-to-today="copyHomeworkToToday"
219221
/>
220222

221223
<!-- 添加ICP备案悬浮组件 -->
@@ -433,6 +435,7 @@ export default {
433435
download: false,
434436
upload: false,
435437
students: false,
438+
copyToToday: false,
436439
},
437440
debouncedUpload: null,
438441
debouncedAttendanceSave: null,
@@ -1914,6 +1917,67 @@ export default {
19141917
this.handleDateSelect(currentDate);
19151918
},
19161919
1920+
async copyHomeworkToToday() {
1921+
if (this.loading.copyToToday) return;
1922+
1923+
try {
1924+
this.loading.copyToToday = true;
1925+
1926+
// 1. 保存当前选中日期的作业数据
1927+
const sourceDate = this.state.dateString;
1928+
const sourceHomework = JSON.parse(JSON.stringify(this.state.boardData.homework));
1929+
1930+
// 2. 切换到今天并加载今天的数据(主要是为了获取考勤等其他数据)
1931+
const today = this.getToday();
1932+
const todayString = this.formatDate(today);
1933+
1934+
// 临时切换到今天以加载数据
1935+
this.state.dateString = todayString;
1936+
await this.downloadData();
1937+
1938+
// 3. 直接替换今天的作业数据(删除原有作业,使用源日期的作业)
1939+
// 深拷贝源日期的作业数据
1940+
const newHomework = {};
1941+
for (const key in sourceHomework) {
1942+
if (sourceHomework[key] && sourceHomework[key].content) {
1943+
// 如果是自定义卡片,保留完整结构
1944+
if (sourceHomework[key].type === 'custom') {
1945+
newHomework[key] = JSON.parse(JSON.stringify(sourceHomework[key]));
1946+
} else {
1947+
// 普通作业,只复制内容
1948+
newHomework[key] = {
1949+
content: sourceHomework[key].content
1950+
};
1951+
}
1952+
}
1953+
}
1954+
1955+
// 直接替换作业数据
1956+
this.state.boardData.homework = newHomework;
1957+
this.state.synced = false;
1958+
1959+
// 4. 保存到今天
1960+
await this.uploadData();
1961+
1962+
// 5. 更新视图状态为今天
1963+
this.state.selectedDate = todayString;
1964+
this.state.selectedDateObj = today;
1965+
this.state.isToday = true;
1966+
1967+
// 6. 更新URL
1968+
const url = new URL(window.location);
1969+
url.searchParams.delete('date');
1970+
window.history.pushState({}, '', url);
1971+
1972+
this.$message.success("复制成功", `已将 ${sourceDate} 的作业内容复制到今天(已替换原有作业)`);
1973+
} catch (error) {
1974+
console.error("复制作业失败:", error);
1975+
this.$message.error("复制失败", error.message || "请重试");
1976+
} finally {
1977+
this.loading.copyToToday = false;
1978+
}
1979+
},
1980+
19171981
// 解析预配数据
19181982
parsePreconfigData() {
19191983
try {

0 commit comments

Comments
 (0)