fix: merge nav into single toolbar for both views, hide FC headerToolbar

- Remove FC headerToolbar and its customButtons (prev/today/next/createClazz)
- Add calendar navigation (navGoPrev/Today/Next) reading FC api
- Unified .view-toolbar with nav + range for both calendar and matrix
- calendarDateRange ref updated in datesSet, weekRange computed dispatches per view
- Remove dead FC button CSS

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-03 09:14:27 +08:00
parent e93f844a61
commit df66e768f3
+78 -117
View File
@@ -1,6 +1,14 @@
<template>
<div class="clazz-page">
<div class="view-toolbar" :class="{ 'view-toolbar--landscape': isLandscape }">
<div class="view-toolbar__main">
<div class="view-toolbar__nav">
<van-button size="small" @click="navGoPrev"></van-button>
<van-button size="small" @click="navGoToday">本周</van-button>
<van-button size="small" @click="navGoNext"></van-button>
</div>
<span class="view-toolbar__range">{{ weekRange }}</span>
</div>
<div class="view-toolbar__actions">
<div v-if="viewMode === 'matrix'" class="view-toolbar__orient">
<van-button size="small" plain @click="isLandscape = !isLandscape">
@@ -80,16 +88,7 @@
<FullCalendar ref="calendar" :options="options" />
</div>
</div>
<div v-show="viewMode === 'matrix'" class="matrix-page">
<div class="matrix-toolbar">
<div class="matrix-toolbar__nav">
<van-button size="small" @click="matrixGoPrev"></van-button>
<van-button size="small" @click="matrixGoToday">本周</van-button>
<van-button size="small" @click="matrixGoNext"></van-button>
</div>
<span class="matrix-toolbar__range">{{ matrixWeekRange }}</span>
</div>
<div class="matrix-container">
<div v-show="viewMode === 'matrix'" class="matrix-container">
<div v-if="teacherList.length > 1" class="matrix-teacher-filter">
<van-tag
:color="selectedTeacherIds.length === 0 ? '#1989fa' : '#e8e8e8'"
@@ -112,7 +111,6 @@
@event-click="onMatrixEventClick"
/>
</div>
</div>
<div class="footer-subsidiary" ref="footer" v-if="subsidiaries.length > 0">
<van-tag type="primary" :color="isTagPlain(item) ? 'rgba(204, 204, 204, 0.5)' : item.color" :text-color="isTagPlain(item) ? item.color : '#333'" @click="toggleTeacherView(item.to_user_id)" v-for="item in subsidiaries">{{ item.to_user_realname }}</van-tag>
</div>
@@ -425,6 +423,31 @@ export default defineComponent({
});
const matrixWeekRange = computed(() => `${matrixWeekStart.value} ~ ${matrixWeekEnd.value}`);
// 日历视图日期范围(由 datesSet 更新)
const calendarDateRange = ref('');
// 统一切换:矩阵用 matrixWeekRange,日历时用 calendarDateRange
const weekRange = computed(() =>
viewMode.value === 'matrix' ? matrixWeekRange.value : calendarDateRange.value
);
// 导航按钮分发(日历 / 矩阵)
const navGoPrev = () => {
if (viewMode.value === 'matrix') return matrixGoPrev();
const api = calendar.value?.getApi?.();
api?.prev();
// datesSet 会自动更新 calendarDateRange
};
const navGoToday = () => {
if (viewMode.value === 'matrix') return matrixGoToday();
calendar.value?.getApi?.().gotoDate(new Date());
};
const navGoNext = () => {
if (viewMode.value === 'matrix') return matrixGoNext();
const api = calendar.value?.getApi?.();
api?.next();
};
// 标准化事件模型(供矩阵视图消费)
const {normalizedEvents} = useClazzViewModel({
list: computed(() => store.list),
@@ -749,32 +772,7 @@ export default defineComponent({
const options: CalendarOptions = {
locale: zhLocale,
// themeSystem: 'bootstrap5',
customButtons: {
current: {
text: '本周',
click: function() {
calendar.value.getApi().gotoDate(new Date())
}
},
createClazz: {
text: '创建排课',
click: function() {
if (!is_teacher.value) return;
const now = new Date();
store.current.start_from = formatDate(now, DateFormatter.DateTimeSave);
now.setMinutes(now.getMinutes() + 45);
store.current.end_by = formatDate(now, DateFormatter.DateTimeSave);
state.editing = true;
state.readonly = false;
state.title = "新增排课"
}
}
},
headerToolbar: {
left: 'prev,current,next',
center: 'title',
right: 'createClazz'
},
headerToolbar: false,
plugins: [ dayGridPlugin, bootstrap5Plugin, timeGridPlugin, interactionPlugin ],
initialView: 'timeGridWeek',
initialDate: initialDate,
@@ -817,6 +815,10 @@ export default defineComponent({
datesSet: function({start, end}) {
// 矩阵视图有自己的日期范围和数据加载逻辑
if (viewMode.value === 'matrix') return;
// 更新日历日期范围显示
const endDate = new Date(end);
endDate.setDate(endDate.getDate() - 1);
calendarDateRange.value = `${formatDate(start, DateFormatter.Date)} ~ ${formatDate(endDate, DateFormatter.Date)}`;
if (store.hanging) {
store.hanging = false;
let {state: cachedState} = getKey('clazz_state');
@@ -1088,6 +1090,7 @@ export default defineComponent({
isLandscape, matrixWeekStart, matrixWeekEnd, matrixWeekRange, matrixWeekDays,
matrixGoPrev, matrixGoNext, matrixGoToday,
onMatrixCellClick, onMatrixEventClick,
weekRange, calendarDateRange, navGoPrev, navGoToday, navGoNext,
}
}
})
@@ -1103,10 +1106,6 @@ export default defineComponent({
height: 100%;
min-height: 0;
:deep(.fc-toolbar-title) {
font-size: 1.25em;
}
:deep(.fc) {
height: 100%;
}
@@ -1116,35 +1115,6 @@ export default defineComponent({
-webkit-overflow-scrolling: touch;
}
// FullCalendar 按钮统一为白底描线,与矩阵视图一致
:deep(.fc .fc-button-primary) {
background: #fff;
border: 1px solid #c8c9cc;
color: #333;
font-size: 0.24rem;
height: 0.5rem;
padding: 0 0.15rem;
border-radius: 0.06rem;
box-shadow: none;
text-shadow: none;
line-height: 1;
white-space: nowrap;
&:hover { background: #f7f8fa; }
&:active { background: #e8e8e8; }
&:focus { box-shadow: none; }
}
:deep(.fc .fc-button-primary:disabled) {
opacity: 0.5;
cursor: not-allowed;
}
:deep(.fc .fc-button-primary.fc-button-active) {
background: #1989fa;
border-color: #1989fa;
color: #fff;
}
}
.calendar-wrapper {
@@ -1364,7 +1334,9 @@ export default defineComponent({
.view-toolbar {
flex-shrink: 0;
display: flex;
justify-content: center;
align-items: center;
justify-content: space-between;
gap: 0.08rem;
padding: 0.08rem 0.12rem;
background: #fff;
border-bottom: 1px solid #f0f0f0;
@@ -1373,12 +1345,46 @@ export default defineComponent({
display: none;
}
&__actions {
&__main {
min-width: 0;
display: flex;
align-items: center;
gap: 0.08rem;
}
&__actions {
flex-shrink: 0;
display: flex;
align-items: center;
gap: 0.08rem;
}
&__range {
min-width: 0;
font-size: 0.2rem;
color: #666;
line-height: 1.3;
white-space: normal;
overflow: visible;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
&__nav {
display: flex;
align-items: center;
gap: 0.08rem;
.van-button--small {
height: 0.5rem;
min-width: 0.62rem;
padding: 0 0.15rem;
font-size: 0.24rem;
white-space: nowrap;
}
}
&__orient {
.van-button--small {
height: 0.5rem;
@@ -1408,51 +1414,6 @@ export default defineComponent({
}
}
/* ═══ 矩阵视图内置工具栏(与日历 FC headerToolbar 对齐) ═══ */
.matrix-page {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
.matrix-toolbar {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 0.08rem;
padding: 0.08rem 0.12rem;
background: #fff;
border-bottom: 1px solid #f0f0f0;
&__nav {
display: flex;
align-items: center;
gap: 0.08rem;
.van-button--small {
height: 0.5rem;
min-width: 0.62rem;
padding: 0 0.15rem;
font-size: 0.24rem;
white-space: nowrap;
}
}
&__range {
min-width: 0;
font-size: 0.2rem;
color: #666;
line-height: 1.3;
white-space: normal;
overflow: visible;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
.landscape-shell {
--landscape-toolbar-height: 0.68rem;
--clazz-landscape-body-height: calc(100dvh - var(--landscape-toolbar-height));