diff --git a/src/App.vue b/src/App.vue index c16a24d..f0e549b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -63,9 +63,9 @@ export default defineComponent({ const is_tester = computed(() => store.currentRole === HtySuperRoles.TESTER); const is_supervisor = computed(() => store.currentRole === HtySuperRoles.SUPERVISOR); const current_role = computed(() => store.currentRole?.toLowerCase()) - const is_guest = computed(() => !user.value.is_registered || !user.value.enabled) - - console.log(user.value, is_guest.value) + const is_guest = computed(() => { + return !user.value.is_registered || !user.value.enabled; + }) const badge_props: Partial = { showZero: false, max: 99 } @@ -110,7 +110,7 @@ export default defineComponent({ return '/' }) - return {user, is_student, is_teacher, is_admin, is_tester, is_guest, current_role, loading, badge_props, tab_change_check, hide_bottom_tab, home_tab_path} + return {user, is_student, is_teacher, is_supervisor, is_admin, is_tester, is_guest, current_role, loading, badge_props, tab_change_check, hide_bottom_tab, home_tab_path} } }); diff --git a/src/pages/clazz/components/ClazzMatrixView.vue b/src/pages/clazz/components/ClazzMatrixView.vue index 0194c73..4c84a5f 100644 --- a/src/pages/clazz/components/ClazzMatrixView.vue +++ b/src/pages/clazz/components/ClazzMatrixView.vue @@ -1,11 +1,11 @@ @@ -268,14 +344,14 @@ export default defineComponent({ /* ═══ 右侧可滚动区域 ═══ */ .matrix-scroll { overflow-x: auto; - overflow-y: hidden; + overflow-y: auto; height: 100%; } .scroll-inner { display: flex; flex-direction: column; - height: 100%; + min-height: 100%; min-width: fit-content; } @@ -396,4 +472,146 @@ export default defineComponent({ color: #3788d8; } } + +/* ═══ 横屏布局 ═══ */ +.matrix-wrapper--landscape { + width: 100%; + height: 100%; + overflow: hidden; +} + +.ml-wrap { + display: flex; + flex-direction: column; + height: 100%; +} + +.ml-header { + display: flex; + flex-shrink: 0; + background: #f7f8fa; + border-bottom: 1px solid #e8e8e8; +} + +.ml-corner { + width: @sidebar-width; + flex-shrink: 0; + text-align: center; + padding: 0.08rem 0.04rem; + font-size: 0.2rem; + color: #888; + border-right: 1px solid #e8e8e8; +} + +.ml-day-header { + flex: 1; + min-width: 0; + text-align: center; + padding: 0.08rem 0.04rem; + border-left: 1px solid #f0f0f0; + + .day-name { font-weight: 600; font-size: 0.22rem; line-height: 1.4; } + .day-date { font-size: 0.18rem; color: #888; line-height: 1.3; } + + &--today { + background: #e6f7ff; + .day-name { color: #1890ff; } + } +} + +.ml-body { + flex: 1; + overflow-y: auto; + overflow-x: hidden; + padding-bottom: 0.08rem; +} + +.ml-row { + display: flex; + border-bottom: 1px solid #f0f0f0; +} + +.ml-label { + width: @sidebar-width; + flex-shrink: 0; + text-align: center; + padding: 0.08rem 0.04rem; + background: #fafafa; + border-right: 1px solid #f0f0f0; + + .header-label { font-weight: 600; font-size: 0.2rem; line-height: 1.4; } + .header-time { font-size: 0.16rem; color: #888; line-height: 1.3; } +} + +.ml-cell { + flex: 1; + min-width: 0; + min-height: 0.6rem; + display: flex; + flex-direction: row; + gap: 0.02rem; + align-items: stretch; + padding: 0.03rem; + border-left: 1px solid #f5f5f5; + overflow: hidden; + + .event-block { + flex: 1; + min-width: 0; + padding: 0.04rem 0.06rem; + border-radius: 0.04rem; + cursor: pointer; + overflow: hidden; + + .ev-title { + font-weight: 600; + font-size: 0.2rem; + line-height: 1.4; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .ev-meta { + font-size: 0.16rem; + color: #888; + line-height: 1.3; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .ev-teacher { + font-size: 0.16rem; + color: #555; + line-height: 1.3; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .ev-students { + font-size: 0.16rem; + color: #777; + line-height: 1.3; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + + .cell-empty { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + min-height: 0.5rem; + color: #ccc; + font-size: 0.28rem; + cursor: pointer; + border-radius: 0.04rem; + + &:active { + background: #f0f5ff; + color: #3788d8; + } + } +} diff --git a/src/pages/clazz/index.vue b/src/pages/clazz/index.vue index 2a2ab49..a6a0ed6 100644 --- a/src/pages/clazz/index.vue +++ b/src/pages/clazz/index.vue @@ -1,42 +1,151 @@ diff --git a/src/pages/clazz/useClazzViewModel.ts b/src/pages/clazz/useClazzViewModel.ts index 7bc7143..5c5f195 100644 --- a/src/pages/clazz/useClazzViewModel.ts +++ b/src/pages/clazz/useClazzViewModel.ts @@ -1,6 +1,5 @@ import { computed, ComputedRef } from 'vue'; import { Clazz, ClazzRepeatRow } from '~/types'; -import { DEFAULT_TIME_SLOTS } from './constants'; export interface NormalizedClazzEvent { id: string; @@ -23,7 +22,7 @@ export interface NormalizedClazzEvent { __raw: Clazz | ClazzRepeatRow; /** 日期键 YYYY-MM-DD */ dateKey: string; - /** 时段键 HH:mm — 匹配最近的固定时段 */ + /** 时段键 HH:mm,按课程真实开始时间生成 */ timeSlotKey: string; } @@ -37,16 +36,8 @@ function dateKey(d: string | Date): string { return `${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, '0')}-${String(dt.getDate()).padStart(2, '0')}`; } -/** 将时间(分)对齐到最近的固定时段 key */ -function nearestSlotKey(d: Date): string { - const minutes = d.getHours() * 60 + d.getMinutes(); - const slots = DEFAULT_TIME_SLOTS.map((s) => { - const [h, m] = s.split(':').map(Number); - return { key: s, minutes: h * 60 + m }; - }); - // Sort by proximity to the event start time - slots.sort((a, b) => Math.abs(a.minutes - minutes) - Math.abs(b.minutes - minutes)); - return slots[0]?.key ?? DEFAULT_TIME_SLOTS[0]; +function timeSlotKey(d: Date): string { + return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`; } function pickNames(item: Clazz) { @@ -88,7 +79,7 @@ function makeEvent( borderColor: extra?.borderColor, __raw: item, dateKey: dateKey(startAt), - timeSlotKey: nearestSlotKey(startAt), + timeSlotKey: timeSlotKey(startAt), }; }