<template>
  <div class="clazz-page">
    <div class="view-toolbar" :class="{ 'view-toolbar--landscape': isLandscape }">
      <div class="view-toolbar__main">
        <div class="view-toolbar__nav" v-if="viewMode === 'matrix'">
          <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="view-toolbar__range" v-if="viewMode === 'matrix'">{{ matrixWeekRange }}</span>
        <span class="view-toolbar__range" v-else>日历周视图</span>
      </div>
      <div class="view-toolbar__actions">
        <div class="view-toolbar__orient">
          <van-button size="small" plain @click="isLandscape = !isLandscape">
            {{ isLandscape ? '退出横屏' : '横屏' }}
          </van-button>
        </div>
        <div class="view-toolbar__toggle">
          <van-button
            :type="viewMode === 'calendar' ? 'primary' : 'default'"
            size="small" plain
            @click="setViewMode('calendar')"
          >日历</van-button>
          <van-button
            :type="viewMode === 'matrix' ? 'primary' : 'default'"
            size="small" plain
            @click="setViewMode('matrix')"
          >矩阵</van-button>
        </div>
      </div>
    </div>

    <div v-if="isLandscape" class="landscape-shell">
      <div class="landscape-shell__toolbar">
        <div class="landscape-shell__left">
          <van-button size="small" plain @click="isLandscape = false">退出横屏</van-button>
          <van-button v-if="viewMode === 'matrix'" size="small" @click="matrixGoToday">本周</van-button>
        </div>
        <div class="landscape-shell__title">
          <template v-if="viewMode === 'matrix'">
            <van-button size="small" @click="matrixGoPrev">‹</van-button>
            <span>{{ matrixWeekRange }}</span>
            <van-button size="small" @click="matrixGoNext">›</van-button>
          </template>
          <template v-else>日历周视图</template>
        </div>
        <div class="landscape-shell__toggle">
          <van-button
            :type="viewMode === 'calendar' ? 'primary' : 'default'"
            size="small" plain
            @click="setViewMode('calendar')"
          >日历</van-button>
          <van-button
            :type="viewMode === 'matrix' ? 'primary' : 'default'"
            size="small" plain
            @click="setViewMode('matrix')"
          >矩阵</van-button>
        </div>
      </div>
      <div class="landscape-shell__body" :class="{ 'landscape-shell__body--matrix': viewMode === 'matrix' }">
        <template v-if="viewMode === 'calendar'">
          <div class="landscape-stage-viewport">
            <div class="landscape-stage">
              <div class="calendar-wrapper calendar-wrapper--landscape">
                <FullCalendar ref="calendar" :options="options" />
              </div>
            </div>
          </div>
        </template>
        <template v-else>
          <div class="landscape-matrix-header">
            <div class="lmh-corner">时段</div>
            <div
              v-for="day in matrixWeekDays"
              :key="day.dateKey"
              class="lmh-day"
              :class="{ 'lmh-day--today': day.isToday }"
            >
              <div class="day-name">{{ day.name }}</div>
              <div class="day-date">{{ day.date }}</div>
            </div>
          </div>
          <div class="landscape-stage-viewport landscape-stage-viewport--matrix">
            <div class="landscape-stage">
              <div class="matrix-container matrix-container--landscape">
                <div v-if="teacherList.length > 1" class="matrix-teacher-filter">
                  <van-tag
                    :color="selectedTeacherIds.length === 0 ? '#1989fa' : '#e8e8e8'"
                    :text-color="selectedTeacherIds.length === 0 ? '#fff' : '#666'"
                    @click="selectedTeacherIds = []"
                  >全部</van-tag>
                  <van-tag
                    v-for="t in teacherList" :key="t.id"
                    :color="selectedTeacherIds.length === 0 || selectedTeacherIds.includes(t.id) ? t.color : '#e8e8e8'"
                    :text-color="selectedTeacherIds.length === 0 || selectedTeacherIds.includes(t.id) ? '#fff' : '#999'"
                    @click="toggleTeacherFilter(t.id)"
                  >{{ t.name }}</van-tag>
                </div>
                <ClazzMatrixView
                  :events="filteredMatrixEvents"
                  :week-start="matrixWeekStart"
                  :week-end="matrixWeekEnd"
                  :landscape="true"
                  :hide-landscape-header="true"
                  @cell-click="onMatrixCellClick"
                  @event-click="onMatrixEventClick"
                />
              </div>
            </div>
          </div>
        </template>
      </div>
    </div>

    <template v-else>
      <div v-show="viewMode === 'calendar'" class="calendar-wrapper">
        <div class="calendar">
          <FullCalendar ref="calendar" :options="options" />
        </div>
      </div>
      <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'"
            :text-color="selectedTeacherIds.length === 0 ? '#fff' : '#666'"
            @click="selectedTeacherIds = []"
          >全部</van-tag>
          <van-tag
            v-for="t in teacherList" :key="t.id"
            :color="selectedTeacherIds.length === 0 || selectedTeacherIds.includes(t.id) ? t.color : '#e8e8e8'"
            :text-color="selectedTeacherIds.length === 0 || selectedTeacherIds.includes(t.id) ? '#fff' : '#999'"
            @click="toggleTeacherFilter(t.id)"
          >{{ t.name }}</van-tag>
        </div>
        <ClazzMatrixView
          :events="filteredMatrixEvents"
          :week-start="matrixWeekStart"
          :week-end="matrixWeekEnd"
          :landscape="false"
          @cell-click="onMatrixCellClick"
          @event-click="onMatrixEventClick"
        />
      </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>
    </template>
  </div><!-- /.clazz-page -->
  <van-overlay :show="state.editing" :lock-scroll="false">
    <div class="content-modal">
      <div class="content-head">
        <van-icon name="chat-o" size="20" v-if="comments_count || is_teacher" @click="replying = true" :badge="comments_count" :show-zero="false" max="99"/>
        <h1>{{state.title}}</h1>
        <van-icon name="cross" size="20" @click="cancel"/>
      </div>
      <van-form @submit="save">
        <div class="form-content">
          <van-field label="排课名称" required v-model="store.current.clazz_name" :readonly="state.readonly"/>
          <van-field v-model="store.current.clazz_desc" label="排课描述" autosize rows="2" type="textarea" :readonly="state.readonly"/>
          <template v-if="state.readonly">
            <van-field :model-value="dateTimeFormat(store.current.start_from)" readonly label="上课时间" required />
            <van-field label="下课时间" readonly required :model-value="dateTimeFormat(store.current.end_by)" />
          </template>
          <template v-else>
            <van-field :model-value="dateTimeFormat(store.current.start_from)" readonly clickable :right-icon="'arrow'"
                       @click="state.showTimePicker = 'start_from'" label="上课时间" required />
            <van-field label="下课时间" readonly clickable :right-icon="'arrow'"
                       @click="state.showTimePicker = 'end_by'" required :model-value="dateTimeFormat(store.current.end_by)" />
          </template>
          <van-field readonly :model-value="store.current.duration" label="课时(分钟)" />
          <template v-if="!state.readonly">
            <van-field label="课程" readonly :border="!store.current.course_sections?.vals?.length">
              <template #button>
                <div>
                  <van-button type="success" @click="pickQS" size="mini">选课程</van-button>
                </div>
              </template>
            </van-field>
            <div class="picked-items" v-if="store.current.course_sections?.vals?.length">
              <van-tag :closeable="true" type="primary" @close="removeQS(qs)" v-for="qs in store.current.course_sections?.vals">{{ qs.course_name }}({{ qs.section_name }})</van-tag>
            </div>
          </template>
          <template v-if="state.readonly && store.current.course_sections?.vals?.length > 0">
            <van-cell  title="课程" is-link :arrow-direction="state.show_courses ? 'up': 'down'" @click="state.show_courses = !state.show_courses">
              共 {{store.current.course_sections.vals.length}} 条课程
            </van-cell>
            <course-section-group :dataset="store.current.course_sections.vals" :show="state.show_courses" :can-modify="false"/>
          </template>

          <template v-if="(state.readonly && store.current.is_repeat) || state.is_edit_root || (!store.current.id && !store.current.has_root)">
            <van-cell title="重复排课">
              <template #right-icon>
                <van-checkbox v-model="store.current.is_repeat" :disabled="state.readonly"/>
              </template>
            </van-cell>
            <template v-if="store.current.is_repeat">
              <template v-if="!state.readonly">
                <van-field v-model="store.current.repeat_start" readonly right-icon="arrow"
                           @click="state.showCalendar = true" label="重复起始" required />
                <van-field readonly label="重复截止" required :model-value="store.current.repeat_end" />
              </template>
              <template v-else>
                <van-field v-model="store.current.repeat_start" readonly disabled right-icon="arrow"
                           label="重复起始" required :formatter="dateFormat"/>
                <van-field readonly label="重复截止" required disabled :model-value="store.current.repeat_end"
                           :formatter="dateFormat"/>
              </template>
            </template>
          </template>
          <van-field label="上课学生" required readonly :border="!store.current.students?.val?.users?.vals?.length">
            <template #button v-if="!state.readonly">
              <div>
                <van-button type="success" @click="pickUserGroup" size="mini">选小组</van-button>
                <van-button type="success" @click="pickStudent" size="mini">选学生</van-button>
              </div>
            </template>
          </van-field>
          <div class="picked-items" v-if="store.current.students?.val?.users?.vals?.length">
            <van-tag :closeable="!state.readonly" type="primary" @close="removeStudent(user)" v-for="user in store.current.students?.val?.users?.vals">{{user.real_name}}</van-tag>
          </div>
          <van-field label="助教老师" readonly :border="!store.current.teachers?.val?.users?.vals?.length">
            <template #button v-if="!state.readonly">
              <div>
                <van-button type="success" @click="pickTeacher" size="mini">选助教老师</van-button>
              </div>
            </template>
          </van-field>
          <div class="picked-items" v-if="store.current.teachers?.val?.users?.vals?.length">
            <van-tag :closeable="!state.readonly" type="primary" @close="removeTeacher(user)" v-for="user in store.current.teachers?.val?.users?.vals">{{user.real_name}}</van-tag>
          </div>
          <van-cell title="课后作业" :border="!store.current.dakas?.vals?.length" v-if="state.readonly && !store.current.is_repeat">
            <template #value v-if="is_creator">
              <div>
                <van-button type="success" @click="createDaka()" size="mini">创建打卡</van-button>
              </div>
            </template>
          </van-cell>
          <div class="picked-items" v-if="store.current.dakas?.vals?.length">
            <van-tag :closeable="false" type="primary" @click="gotoDaka(daka.id)" v-for="daka in store.current.dakas.vals">{{daka.name}}</van-tag>
          </div>
          <van-calendar v-model:show="state.showCalendar" :min-date="repeatMinDate" :default-date="repeatDefaultDate" @confirm="onChangeDate" type="range" color="#1989fa" />
          <van-cell title="操作记录" is-link v-if="state.readonly && store.current.id" @click="showAuditLogPopup" style="margin-bottom: 0.2rem;" />
        </div>
        <div class="footer" v-if="is_creator || !store.current.id ">
          <template v-if="state.readonly">
            <van-button v-if="is_creator && store.current.id && !store.current.is_repeat" size="small" type="primary" plain block @click="openAttendance">点名（消课）</van-button>
            <div class="footer-actions">
              <van-button size="mini" type="primary" @click="edit(true)" v-if="is_creator && (store.current.instance || store.current.has_root)">编辑重复排课</van-button>
              <van-button size="mini" type="primary" @click="edit(false)">编辑本次排课</van-button>
              <van-button size="mini" type="danger" @click="remove(true)" v-if="is_creator && (store.current.instance || store.current.has_root)">取消重复排课</van-button>
              <van-button size="mini" type="danger" @click="remove(false)">取消本次排课</van-button>
            </div>
          </template>
          <template v-else>
            <van-button size="mini" type="default" @click="cancel">取消</van-button>
            <van-button size="mini" type="primary" native-type="submit">保存</van-button>
          </template>
        </div>
      </van-form>
    </div>
  </van-overlay>
  <van-action-sheet v-model:show="state.showTimePicker">
    <van-time-picker @cancel="state.showTimePicker = false" min-time="06:00:00" max-time="22:00:00" title="选择时间" @confirm="onChangeTime"
                     :columns-type="['hour', 'minute']" :filter="timePickerFilter" />
  </van-action-sheet>

  <van-popup v-model:show="state.showAttendance" position="bottom" round :style="{ padding: '1rem' }">
    <h3 style="margin: 0 0 0.75rem;">点名 — 勾选已到学员</h3>
    <div v-for="u in attendanceStudents" :key="u.user_id || ''" style="margin: 0.5rem 0;">
      <van-checkbox v-model="attendanceMap[u.user_id || '']" shape="square">{{ u.real_name || u.user_id }}</van-checkbox>
    </div>
    <div style="margin-top: 1rem; display: flex; gap: 0.5rem; justify-content: flex-end;">
      <van-button size="small" @click="state.showAttendance = false">取消</van-button>
      <van-button size="small" type="primary" @click="submitAttendance">保存</van-button>
    </div>
  </van-popup>

  <van-action-sheet :lock-scroll="false" v-model:show="replying" title="留言回复" @close="removeComment" :close-on-click-overlay="false">
    <comments-sheet :disabled="!is_teacher" :ref_id="store.current.id" :comment="commenting" @reply="replyComment" @submit="saveComment" @remove="removeComment"></comments-sheet>
  </van-action-sheet>

  <van-popup v-model:show="state.showAuditLog" position="bottom" round :style="{ padding: '1rem', maxHeight: '60vh', overflowY: 'auto' }">
    <h3 style="margin: 0 0 0.75rem;">操作记录</h3>
    <div v-if="auditLogs.length === 0" style="text-align: center; color: #999; padding: 1rem 0;">暂无操作记录</div>
    <div v-for="log in auditLogs" :key="log.id" style="padding: 0.5rem 0; border-bottom: 1px solid #f0f0f0;">
      <div style="display: flex; justify-content: space-between;">
        <van-tag :type="auditActionTagType(log.action)" size="small">{{ log.action }}</van-tag>
        <span style="font-size: 0.24rem; color: #999;">{{ log.created_at }}</span>
      </div>
      <div style="font-size: 0.26rem; color: #666; margin-top: 0.2rem;">操作人：{{ log.operator_name || log.operator_hty_id }}</div>
      <div v-if="log.changes" style="font-size: 0.24rem; color: #999; margin-top: 0.1rem; word-break: break-all;">{{ JSON.stringify(log.changes) }}</div>
    </div>
  </van-popup>
</template>

<script lang="ts">
import {reactive, ref, defineComponent, computed, nextTick, watch} from 'vue';
import {CalendarOptions, DateSelectArg, EventClickArg} from "@fullcalendar/core"
import FullCalendar from '@fullcalendar/vue3'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin from '@fullcalendar/interaction'
import zhLocale from '@fullcalendar/core/locales/zh-cn'
import bootstrap5Plugin from '@fullcalendar/bootstrap5'
import CourseGroup from "~/components/qumu-section-group.vue";
import CommentsSheet from '~/components/comments-sheet.vue'
import {Field, Cell, Checkbox, Calendar, showConfirmDialog, TimePicker, Button, Tag, Badge, ActionSheet, Overlay, Form, Icon, showFailToast, Popup, showSuccessToast} from 'vant'
import {DateFormatter, formatDate, hexToRgb} from "~/utils";
import useClazz from "../../store/clazz";
import {useRouter} from "vue-router";
import {
  Comment,
  CommentContent,
  CommentRefTypes,
  GroupUser,
  HtyBaseRoles,
  HtySuperRoles,
  Clazz,
  NotifyParam,
  NotifyTypes,
  PickTargets,
  CourseSection
} from "~/types";
import useUser from "~/store/user";
import usePool from "~/store/pool";
import useComment from "~/store/comment";
import useSupervisor from "~/store/supervisor";
import ClazzMatrixView from './components/ClazzMatrixView.vue';
import {useClazzViewModel} from './useClazzViewModel';

export default defineComponent({
  name: "clazz",
  components: {
    FullCalendar,
    [Icon.name]: Icon,
    [Field.name]: Field,
    [Cell.name]: Cell,
    [Badge.name]: Badge,
    [Checkbox.name]: Checkbox,
    [Calendar.name]: Calendar,
    [TimePicker.name]: TimePicker,
    [ActionSheet.name]: ActionSheet,
    [CommentsSheet.name]: CommentsSheet,
    [Tag.name]: Tag,
    [Button.name]: Button,
    [Overlay.name]: Overlay,
    [Form.name]: Form,
    [CourseGroup.name]: CourseGroup,
    [Popup.name]: Popup,
    ClazzMatrixView,
  },
  props: {
    params: {}
  },
  setup({params}: any) {
    const router = useRouter();
    const {store, query_repeats, query, query_for_subsidiaries, query_repeats_for_subsidiaries, createOrUpdate, createInstance, removeCurrent, notify, find_clazz_attendance_by_clazz_id, batch_save_clazz_attendance, getAuditLog} = useClazz();
    const {set: setPool, setKey, getKey} = usePool();
    const usingSupervisor = useSupervisor();
    const usingUser = useUser();
    const {count_comments, create_comment, load_comments, check_comments_task} = useComment();
    const state = reactive({
      start_date: "",
      end_date: "",
      title: "排课详情",
      is_edit_root: false,
      initial: true,
      editing: false,
      readonly: false,
      showCalendar: false,
      showTimePicker: false,
      show_courses: false,
      showAttendance: false,
      showAuditLog: false,
    })

    const auditLogs = ref<any[]>([])

    const attendanceMap = reactive<Record<string, boolean>>({})

    const attendanceStudents = computed(() => store.current.students?.val?.users?.vals || [])

    const calendar = ref(null)
    const footer = ref(null)

    const Colors = ["#F4A98C", "#F4C08C", "#ECE68C", "#A8D4A8", "#8CD4D4", "#8CB4E8", "#BC9CE8", "#E89CBC"]

    // ═══ 双视图模式 ═══
    const viewMode = ref<'calendar' | 'matrix'>('calendar');
    // 恢复上次的视图模式
    const cachedViewMode = getKey('clazz_view_mode') as string;
    if (cachedViewMode === 'matrix' || cachedViewMode === 'calendar') {
      viewMode.value = cachedViewMode;
    }

    const isLandscape = ref(false);

    const updateCalendarSize = () => {
      nextTick(() => {
        requestAnimationFrame(() => {
          calendar.value?.getApi?.().updateSize();
        });
      });
    };

    watch([isLandscape, viewMode], updateCalendarSize);

    // 矩阵视图导航
    const WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];

    function isSameDay(a: Date, b: Date): boolean {
      return a.getFullYear() === b.getFullYear()
        && a.getMonth() === b.getMonth()
        && a.getDate() === b.getDate();
    }

    const today = computed(() => new Date());

    const matrixWeekDays = computed(() => {
      const days: { dateKey: string; name: string; date: string; isToday: boolean }[] = [];
      const start = new Date(matrixWeekStart.value);
      for (let i = 0; i < 7; i++) {
        const d = new Date(start);
        d.setDate(d.getDate() + i);
        days.push({
          dateKey: formatDate(d, DateFormatter.Date),
          name: WEEKDAYS[d.getDay()],
          date: formatDate(d, 'MM-DD'),
          isToday: isSameDay(d, today.value),
        });
      }
      return days;
    });

    const matrixWeekCursor = ref(new Date());
    const matrixWeekStart = computed(() => {
      const d = new Date(matrixWeekCursor.value);
      const day = d.getDay();
      d.setDate(d.getDate() - day);
      return formatDate(d, DateFormatter.Date);
    });
    const matrixWeekEnd = computed(() => {
      const d = new Date(matrixWeekCursor.value);
      const day = d.getDay();
      d.setDate(d.getDate() + (6 - day));
      return formatDate(d, DateFormatter.Date);
    });
    const matrixWeekRange = computed(() => `${matrixWeekStart.value} ~ ${matrixWeekEnd.value}`);

    // 标准化事件模型（供矩阵视图消费）
    const {normalizedEvents} = useClazzViewModel({
      list: computed(() => store.list),
      repeatList: computed(() => store.repeatList),
      subsidiaryClazzByHtyId: computed(() => store.subsidiaryClazzByHtyId),
      getViewingSubsidiaries: () => viewingSubsidiaries.value,
      getSubsidiaryColor: (htyId) => {
        const idx = subsidiaries.value.findIndex(x => x.to_user_id === htyId);
        return idx >= 0 ? Colors[idx] : undefined;
      },
    });

    // ═══ 老师过滤（矩阵视图用） ═══
    const teacherList = computed(() => {
      const list: { id: string; name: string; color: string }[] = [];
      const myId = usingUser.store.current.hty_id;
      const myName = usingUser.store.current.real_name;
      if (myId && myName) {
        list.push({ id: myId, name: myName, color: '#4096ff' });
      }
      subsidiaries.value.forEach((s, i) => {
        list.push({
          id: s.to_user_id,
          name: s.to_user_realname,
          color: Colors[i % Colors.length],
        });
      });
      return list;
    });
    const selectedTeacherIds = ref<string[]>([]);
    const filteredMatrixEvents = computed(() => {
      if (selectedTeacherIds.value.length === 0) return normalizedEvents.value;
      return normalizedEvents.value.filter(ev => {
        const id = ev.isSubsidiary ? ev.subsidiaryTeacherId : ev.teacherId;
        return id ? selectedTeacherIds.value.includes(id) : true;
      });
    });
    const toggleTeacherFilter = (id: string) => {
      const idx = selectedTeacherIds.value.indexOf(id);
      if (idx >= 0) selectedTeacherIds.value.splice(idx, 1);
      else selectedTeacherIds.value.push(id);
    };

    // 切换视图时缓存
    const setViewMode = (mode: 'calendar' | 'matrix') => {
      viewMode.value = mode;
      setKey('clazz_view_mode', mode);
      updateCalendarSize();
    };

    const timePickerFilter = (type, options) => {
      if (type === 'minute') {
        return options.filter((option) => Number(option.value) % 5 === 0);
      }
      return options;
    };

    // ═══ 矩阵视图导航 ═══
    const matrixGoPrev = () => {
      const d = new Date(matrixWeekCursor.value);
      d.setDate(d.getDate() - 7);
      matrixWeekCursor.value = d;
      // 触发查询
      triggerMatrixSearch();
    };
    const matrixGoNext = () => {
      const d = new Date(matrixWeekCursor.value);
      d.setDate(d.getDate() + 7);
      matrixWeekCursor.value = d;
      triggerMatrixSearch();
    };
    const matrixGoToday = () => {
      matrixWeekCursor.value = new Date();
      triggerMatrixSearch();
    };

    const triggerMatrixSearch = () => {
      const start = matrixWeekStart.value;
      const end = matrixWeekEnd.value;
      state.start_date = start;
      state.end_date = end;
      search();
    };

    // 点击空槽 → 创建排课
    const onMatrixCellClick = (dateKey: string, slotKey: string) => {
      if (!is_teacher.value) return;
      const start = new Date(`${dateKey}T${slotKey}:00`);
      const end = new Date(start);
      end.setMinutes(end.getMinutes() + 45);
      store.current.start_from = formatDate(start, DateFormatter.DateTimeSave);
      store.current.end_by = formatDate(end, DateFormatter.DateTimeSave);
      state.editing = true;
      state.readonly = false;
      state.title = "新增排课";
    };

    // 点击课块 → 查看详情
    const onMatrixEventClick = (ev: any) => {
      view(ev.id);
    };

    const draw = () => {
      let api = calendar.value.getApi()
      api.removeAllEvents();
      store.list.forEach(item => {
        if (item.is_delete) return;
        api.addEvent({
          id: item.id,
          title: item.clazz_name,
          start: item.start_from,
          end: item.end_by,
        })
      })

      store.repeatList.forEach(item => {
        if (!item.instance.id) {
          api.addEvent({
            id: item.id,
            title: item.instance.clazz_name,
            start: item.instance.start_from,
            end: item.instance.end_by,
            color: "rgba(55, 136, 216, 0.6)",
            borderColor: "rgba(55, 136, 216, 0.6)"
          })
        }
      })

      Object.entries(store.subsidiaryClazzByHtyId).forEach(([key, {list, repeatList}]) => {
        let color = Colors[subsidiaries.value.findIndex(x => x.to_user_id === key)];
        let {r, g, b} = hexToRgb(color);
        let hidden = !viewingSubsidiaries.value.includes(key)
        list.forEach(item => {
          if (item.is_delete) return;
          api.addEvent({
            id: item.id,
            title: item.clazz_name,
            start: item.start_from,
            end: item.end_by,
            subsidiary_id: key,
            display: hidden ? 'none' : 'auto',
            color,
          })
        })
        repeatList.forEach(item => {
          if (!item.instance.id) {
            api.addEvent({
              id: item.id,
              title: item.instance.clazz_name,
              start: item.instance.start_from,
              end: item.instance.end_by,
              color: `rgba(${r}, ${g}, ${b}, 0.6)`,
              borderColor: `rgba(${r}, ${g}, ${b}, 0.6)`,
              subsidiary_id: key,
              display: hidden ? 'none' : 'auto',
            })
          }
        })
      })


    }

    const redraw = () => {
      let events = calendar.value.getApi().getEvents();
      events.forEach((event, i) => {
        let subsidiary_id = event.extendedProps.subsidiary_id;
        if (subsidiary_id) {
          if (viewingSubsidiaries.value.includes(subsidiary_id)) {
            console.log('set to auto')
            event.setProp("display", 'auto')
          } else {
            console.log('set to none')
            event.setProp('display', 'none')
          }
        }
      })
    }

    const commenting = ref<Comment | null>(null)
    const replying = ref(false)

    const subsidiaries = ref([])
    const viewingSubsidiaries = ref([])

    const notify_comment = (comment: Comment) => {
      let {clazz_name, start_from, end_by} = store.current;
      let comment_msg = "新的排课留言（" + clazz_name + " " + usingUser.store.current.real_name + "）"
      let payload: NotifyParam = {
        clazz_name: clazz_name, start_from, end_by,
        notify_type: NotifyTypes.TeacherCommentClazz,
        clazz_id: store.current.id, comment_id: comment.id,
        comment_time: formatDate(new Date(), DateFormatter.DateTime),
        comment_msg, teacher_name: usingUser.store.current.real_name
      }
      let teachers = (store.current.teachers?.val?.users?.vals || []).map(t => t.user_id);
      teachers.forEach(t => {
        if (t === usingUser.store.current.hty_id) return;
        notify({...payload, hty_id: t}, HtyBaseRoles.TEACHER)
      })
      let students = (store.current.students?.val.users.vals || []).map(x => x.user_id);
      students.forEach(s => {
        notify({...payload, hty_id: s}, HtyBaseRoles.STUDENT)
      })
    }

    const replyComment = (parent_id?: string) => {
      commenting.value = { parent_id, ref_type: CommentRefTypes.Clazz, content: {} as CommentContent} as Comment
    }

    const saveComment = async () => {
      let comment = commenting.value as Comment;
      comment.ref_id = store.current.id;
      let created = await create_comment(comment);
      if (created) {
        commenting.value = null;
        notify_comment(created)
      }
    }

    const removeComment = () => {
      commenting.value = null;
      replying.value = false;
    }

    const comments_count = computed(() => count_comments(store.current.id))

    const searchForSubsidiaries = async () => {
      // 主管老师角色下才加载下属老师的排课
      if (usingUser.store.currentRole !== HtyBaseRoles.TEACHER && usingUser.store.current.roles.some(r => r.role_key === HtySuperRoles.SUPERVISOR)) {
        subsidiaries.value = usingSupervisor.store.subsidiaries;
        if (!subsidiaries.value.length) {
          await usingSupervisor.getSubsidiaries();
          subsidiaries.value = usingSupervisor.store.subsidiaries;
        }
        if (state.initial) {
          viewingSubsidiaries.value = [];
          subsidiaries.value.forEach((t, i) => {
            viewingSubsidiaries.value.push(t.to_user_id);
            t.color = Colors[i]
          })
        }

        if (subsidiaries.value.length) {
          let { start_date, end_date } = state;
          await query_for_subsidiaries(start_date, end_date, subsidiaries.value.map(x => x.to_user_id))
          await query_repeats_for_subsidiaries(start_date, end_date, subsidiaries.value.map(x => x.to_user_id))
        }
      }
    }

    const search = async () => {
      let { start_date, end_date } = state;
      await query(start_date, end_date)
      await query_repeats(start_date, end_date)

      await searchForSubsidiaries();
      draw();
    }

    const find = (id: string) => {
      // find in own list
      let data = store.list.find(x => x.id === id)
      if (data) return data;
      let root = store.repeatList.find(x => x.id === id)
      if (root) {
        return root.instance;
      }
      // find in subsidiaries' list
      let subsidiaries = Object.values(store.subsidiaryClazzByHtyId);
      for (let i = 0; i < subsidiaries.length; i++) {
        let {list, repeatList} = subsidiaries[i]
        data = list.find(x => x.id === id)
        if (data) return data;
        root = repeatList.find(x => x.id === id)
        if (root) {
          return root.instance;
        }
      }
      return null;
    }

    const view = (id: string) => {
      store.current = find(id);
      if (!store.current) {
        showFailToast("找不到对应的排课！")
        return;
      }
      state.editing = true;
      state.readonly = true;
      state.title = "排课信息"
      // load comments and check comments task
      load_comments(id).then(() => check_comments_task(id));
    }

    const is_teacher = computed(() => usingUser.store.currentRole === HtyBaseRoles.TEACHER);
    const is_creator = computed(() => store.current.created_by === usingUser.store.current.hty_id)

    let initialDate = new Date();
    if (params.start_from) {
      initialDate = new Date(params.start_from)
    }
    if (store.hanging) {
      let { date } = getKey('clazz_state')
      initialDate = date;
    }

    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'
      },
      plugins: [ dayGridPlugin, bootstrap5Plugin, timeGridPlugin, interactionPlugin ],
      initialView: 'timeGridWeek',
      initialDate: initialDate,
      slotMinTime: "06:00:00",
      slotMaxTime: "22:00:00",
      nowIndicator: true,
      droppable: true,
      editable: true,
      dayMaxEvents: true,
      navLinks: true, // can click day/week names to navigate views
      selectable: is_teacher.value,
      selectMirror: true,
      height: '100%',
      select: function({start, end}: DateSelectArg) {
        if (!is_teacher.value) {
          return;
        }
        store.current.start_from = formatDate(start, DateFormatter.DateTimeSave);
        store.current.end_by = formatDate(end, DateFormatter.DateTimeSave)
        state.editing = true;
        state.readonly = false;
        state.title = "新增排课"
      },
      dateClick({date}: any) {
        if (!is_teacher.value) {
          return;
        }
        store.current.start_from = formatDate(date, DateFormatter.DateTimeSave);
        date.setMinutes(date.getMinutes() + 30);
        store.current.end_by = formatDate(date, DateFormatter.DateTimeSave)
        state.editing = true;
        state.readonly = false;
        state.title = "新增排课"
      },
      eventClick: function({event}: EventClickArg) {
        view(event.id)
      },
      datesSet: function({start, end}) {
        if (store.hanging) {
          store.hanging = false;
          let {state: cachedState} = getKey('clazz_state');
          Object.entries(cachedState || {}).forEach(([k, v]) => {
            state[k] = v;
          })
          search();
        } else {
          state.start_date = formatDate(start, DateFormatter.Date);
          state.end_date = formatDate(end, DateFormatter.Date);
          search();
        }
      },
      eventDidMount({event}) {
        if (!store.hanging && state.initial && event.id === params.clazz_id) {
          view(event.id)
          if (params.comment_id) {
            replying.value = true;
          }
        }
        state.initial = false;
      },
      eventContent: function ({event}) {
        let html = `
            <div class="fc-event-main-frame">
                <div class="fc-event-title-container">
                    <div class="fc-event-title fc-sticky">${event.title}</div>
                </div>
            </div>
        `
        return { html }
      }
    }

    const cancel = () => {
      store.current = {};
      state.editing = false;
      state.readonly = false;
    }

    const save = async (e: SubmitEvent) => {
      if (!state.is_edit_root) {
        if (store.current.instance) {
          if (await createInstance(store.current.instance)) {
            state.editing = false;
            store.current = {} as Clazz;
            await search()
            return;
          }
        }
      }
      if (await createOrUpdate()) {
        state.editing = false;
        store.current = {} as Clazz;
        await search()
      }
    }

    const freeze = () => {
      store.hanging = true;
      let date = calendar.value.getApi().getDate();
      setKey('clazz_state', {state, date})
    }

    const pickUserGroup = () => {
      freeze();
      router.push('/user-group/pick?target=' + PickTargets.CLAZZ)
    }

    const pickStudent = () => {
      store.hanging = true;
      freeze();
      router.push('/student?multiple=1&target=' + PickTargets.CLAZZ)
    }

    const pickTeacher = () => {
      freeze();
      router.push("/teacher/subsidiaries?multiple=1&target=" + PickTargets.CLAZZ)
    }

    const createDaka = async () => {
      freeze();
      setPool({
        course_sections: store.current.course_sections?.vals,
        teachers: store.current.teachers,
        students: store.current.students,
      })
      // create clazz-linked daka if it's root
      if (!store.current.id) {
        if (await createInstance(store.current)) {
          await router.push('/daka/add?clazz_id=' + store.current.id + '&clazz_name=' + encodeURIComponent(store.current.clazz_name))
        } else {
          showFailToast("排课创建失败！")
        }
      } else {
        await router.push('/daka/add?clazz_id=' + store.current.id + '&clazz_name=' + encodeURIComponent(store.current.clazz_name))
      }

    }

    const gotoDaka = (daka_id: string) => {
      freeze();
      router.push(`/daka/detail?id=${daka_id}`)
    }


    const pickQS = () => {
      freeze();
      router.push('/course/mix-pick?target=' + PickTargets.CLAZZ)
    }

    const removeTeacher = (user: GroupUser) => {
      store.current.teachers.val.users.vals = store.current.teachers.val.users.vals.filter(x => x.user_id !== user.user_id)
    }

    const removeStudent = (user: GroupUser) => {
      store.current.students.val.users.vals = store.current.students.val.users.vals.filter(x => x.user_id !== user.user_id)
    }

    const removeQS = (qs: CourseSection) => {
      store.current.course_sections.vals = store.current.course_sections.vals.filter(x => x.id !== qs.id)
    }

    const onChangeDate = (values: string[]) => {
      let [start, end] = values;
      store.current.repeat_start = formatDate(start, DateFormatter.Date);
      store.current.repeat_end = formatDate(end, DateFormatter.Date);
      state.showCalendar = false;
    };

    const onChangeTime = (value) => {
      let {selectedValues} = value;
      selectedValues.push("00"); // add second part
      let [d, _] = store.current[state.showTimePicker].split("T")
      store.current[state.showTimePicker] = [d, selectedValues.join(":")].join("T");
      state.showTimePicker = false
    }

    const dateTimeFormat = value => {
      if (!value) return "";
      let [d, t] = value.split("T");
      let [h, m, _] = t.split(":");
      return [d, [h, m].join(":")].join(" ");
    }

    const dateFormat = value => {
      if (!value) return "";
      return value.split("T")[0]
    }

    const edit = (is_edit_root: boolean) => {
      state.editing = true;
      state.readonly = false;
      state.title = is_edit_root ? "编辑重复排课" : "编辑本次排课"
      state.is_edit_root = is_edit_root;
      if (is_edit_root) {
        // 如果当前不是root课程，则找到对应的root课程
        let {has_root, root_id} = store.current;

        if (has_root) {
          // 实例课程，找对应的root课程
          store.current = store.repeatList.find(x => x.id === root_id)
        }
      }
    }

    const remove = (is_root: boolean) => {
        showConfirmDialog({
          title: `取消${is_root ? '重复' : '本次'}排课`,
          message: is_root ? "该重复排课的所有未开始记录都会被取消，确认取消？" : "排课取消后无法恢复，确认取消？",
        }).then(async () => {
          if (await removeCurrent(is_root)) {
            cancel();
            await search();
          }
        })
    }

    const toggleTeacherView = (hty_id) => {
      let index = viewingSubsidiaries.value.indexOf(hty_id)
      if (index >= 0) {
        viewingSubsidiaries.value.splice(index, 1)
      } else {
        viewingSubsidiaries.value.push(hty_id)
      }
      redraw();
    }


    const repeatMinDate = computed(() => {
      let {start_from} = store.current || {};
      if (start_from) return new Date(start_from)
      return new Date();
    })

    const repeatDefaultDate = computed(() => {
      let {repeat_start, repeat_end} = store.current || {};
      if (repeat_start && repeat_end) {
        return [new Date(repeat_start), new Date(repeat_end)]
      }
      return null
    })

    const footerHeight = computed(() => {
      let div = footer.value as HTMLDivElement;
      return div ? div.offsetHeight + 10: 0;
    })

    const isTagPlain = (item) => !viewingSubsidiaries.value.includes(item.to_user_id)

    const openAttendance = async () => {
      if (!store.current.id) {
        showFailToast('排课 ID 不存在');
        return;
      }
      state.showAttendance = true;
      const list = await find_clazz_attendance_by_clazz_id(store.current.id);
      attendanceStudents.value.forEach((u) => {
        const uid = u.user_id || '';
        const row = list?.find((a) => a.student_id === uid);
        attendanceMap[uid] = row ? row.status === 'NORMAL' : false;
      });
    };

    const submitAttendance = async () => {
      if (!store.current.id) return;
      const hours = (store.current.duration || 60) / 60;
      const items = attendanceStudents.value.map((u) => {
        const uid = u.user_id || '';
        const present = !!attendanceMap[uid];
        return {
          student_id: uid,
          status: present ? 'NORMAL' : 'ABSENT',
          deducted_hours: present ? hours : 0,
          sign_method: 'TEACHER_MANUAL',
        };
      });
      const ok = await batch_save_clazz_attendance({ clazz_id: store.current.id, items });
      if (ok) {
        showSuccessToast('已保存点名');
        state.showAttendance = false;
      }
    };

    const auditActionTagType = (action: string) => {
      if (action === 'CREATE') return 'primary';
      if (action === 'UPDATE') return 'warning';
      if (action === 'DELETE') return 'danger';
      return 'default';
    };

    const showAuditLogPopup = async () => {
      if (!store.current.id) return;
      state.showAuditLog = true;
      const logs = await getAuditLog(store.current.id);
      auditLogs.value = logs || [];
    };

    return {
      options, cancel, save, state, store, removeQS, gotoDaka, subsidiaries, toggleTeacherView,
      pickTeacher, removeTeacher, calendar, edit, remove, dateFormat, pickQS, timePickerFilter,
      onChangeDate, pickUserGroup, pickStudent, onChangeTime, createDaka, repeatMinDate, isTagPlain,
      removeStudent, dateTimeFormat, is_teacher, is_creator, repeatDefaultDate, footer, footerHeight,
      replyComment, removeComment, saveComment, replying, commenting, comments_count, viewingSubsidiaries,
      openAttendance, submitAttendance, attendanceMap, attendanceStudents,
      showAuditLogPopup, auditActionTagType, auditLogs,
      viewMode, setViewMode, normalizedEvents, filteredMatrixEvents,
      teacherList, selectedTeacherIds, toggleTeacherFilter,
      isLandscape, matrixWeekStart, matrixWeekEnd, matrixWeekRange, matrixWeekDays,
      matrixGoPrev, matrixGoNext, matrixGoToday,
      onMatrixCellClick, onMatrixEventClick,
    }
  }
})
</script>

<style scoped lang="less">
@sidebar-width: 1.2rem;
@cell-width: 1.8rem;
.calendar {
  font-size: 10px;
  padding: 8px;
  box-sizing: border-box;
  height: 100%;
  min-height: 0;

  :deep(.fc-toolbar-title) {
    font-size: 1.25em;
  }

  :deep(.fc) {
    height: 100%;
  }
}

.calendar-wrapper {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.calendar-wrapper--landscape {
  width: 100%;
  height: 100%;
  box-sizing: border-box;

  :deep(.fc) {
    width: 100%;
    height: 100%;
    min-height: 100%;
  }

  :deep(.fc-header-toolbar) {
    flex-shrink: 0;
  }

  :deep(.fc-view-harness) {
    height: 100% !important;
    min-height: 0;
  }

  :deep(.fc-scroller) {
    overflow: auto !important;
  }
}

.footer-subsidiary {
  padding: 2px 3px;
  margin: 5px 8px;
  white-space: break-spaces;
  //box-shadow: inset 0 0 5px 3px #d2d4d9;
  border: 1px solid #eeeeee;

  :deep(.van-tag) {
    margin: 3px;
    cursor: pointer;
  }

}

.content-modal {
  position: relative;
  box-sizing: border-box;
  margin: 32px 24px;
  height: calc(100% - 64px);
  border-radius: 5px;
  background: #FFFFFF;

  .content-head {
    display: flex;
    align-items: center;
    justify-content: space-around;
    border-bottom: 1px solid #dddddd;
    position: relative;

    h1 {
      text-align: center;
      padding: 0.2rem 0;
      font-size: 0.4rem;
      height: 1rem;
      margin: 0;
    }

    i {
      position: absolute;

      &:first-child {
        left: 0.25rem
      }

      &:last-child {
        right: 0.25rem;
      }
    }

  }


  :deep(.van-form) {
    height: calc(100% - 1rem);
    position: relative;

    .footer {
      position: absolute;
      bottom: 0;
      padding: 0.2rem 5%;
      min-height: 1.08rem;
      width: 100%;
      background: #FFFFFF;
      display: flex;
      flex-direction: column;
      gap: 0.12rem;
      border-top: 1px solid #dddddd;

      .footer-actions {
        display: flex;
        flex-wrap: wrap;
        gap: 0.1rem;

        .van-button--mini {
          flex: 1;
          min-width: 1.4rem;
        }
      }

      .delete-warning {
        color: red;
      }
    }

    .form-content {
      position: relative;
      height: calc(100% - 1.28rem);
      overflow-y: auto;
      box-sizing: border-box;
      padding: 0.1rem 0;
    }
  }
}

.picked-items {
  margin: 0 var(--van-cell-horizontal-padding);
  padding: 0 0 5px 0;
  border-bottom: 1px solid var(--van-cell-border-color);

  &:empty {
    padding: 0;
  }

  :deep(.van-tag) {
    margin: 0.04rem 0.06rem;
  }
}

/* ═══ 双视图布局容器 ═══ */
.clazz-page {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.matrix-container {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #fff;

  :deep(.matrix-wrapper) {
    flex: 1;
    min-height: 0;
  }

  :deep(.matrix-scroll) {
    padding-bottom: calc(0.72rem + env(safe-area-inset-bottom));
    box-sizing: border-box;
  }
}

.matrix-container--landscape {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  overflow: hidden;

  :deep(.matrix-scroll) {
    padding-bottom: 0;
  }

  :deep(.ml-body) {
    padding-bottom: calc(0.2rem + env(safe-area-inset-bottom));
  }
}

.matrix-teacher-filter {
  flex-shrink: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.06rem;
  padding: 0.08rem 0.12rem;
  border-bottom: 1px solid #f0f0f0;

  :deep(.van-tag) {
    cursor: pointer;
  }
}

/* ═══ 双视图工具栏 ═══ */
.view-toolbar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.08rem;
  padding: 0.08rem 0.12rem;
  background: #fff;
  border-bottom: 1px solid #f0f0f0;

  &--landscape {
    display: none;
  }

  &__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.22rem;
    color: #666;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  &__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;
      padding: 0 0.15rem;
      font-size: 0.24rem;
      border-color: #c8c9cc;
      color: #666;
    }
  }

  &__toggle {
    display: flex;
    gap: 0;

    .van-button {
      height: 0.5rem;
      font-size: 0.24rem;
      border-radius: 0;

      &:first-child {
        border-radius: 0.06rem 0 0 0.06rem;
      }
      &:last-child {
        border-radius: 0 0.06rem 0.06rem 0;
      }
    }
  }
}

.landscape-shell {
  --landscape-toolbar-height: 0.68rem;
  --clazz-landscape-body-height: calc(100dvh - var(--landscape-toolbar-height));
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  flex-direction: column;
  background: #fff;
}

.landscape-shell__toolbar {
  flex-shrink: 0;
  min-height: var(--landscape-toolbar-height);
  box-sizing: border-box;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.08rem;
  padding: 0.08rem 0.12rem;
  border-bottom: 1px solid #f0f0f0;
  background: #fff;
}

.landscape-shell__left {
  display: flex;
  align-items: center;
  gap: 0.08rem;
}

.landscape-shell__title {
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.08rem;
  color: #333;
  font-size: 0.24rem;
  font-weight: 600;

  span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

.landscape-shell__toggle {
  display: flex;
  flex-shrink: 0;
  gap: 0;

  .van-button {
    height: 0.5rem;
    font-size: 0.24rem;
    border-radius: 0;

    &:first-child {
      border-radius: 0.06rem 0 0 0.06rem;
    }

    &:last-child {
      border-radius: 0 0.06rem 0.06rem 0;
    }
  }
}

.landscape-shell__body {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  height: var(--clazz-landscape-body-height);

  &--matrix {
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
}

.landscape-stage-viewport {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #fff;
}

.landscape-stage-viewport--matrix {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

.landscape-stage {
  width: var(--clazz-landscape-body-height);
  height: 100dvw;
  overflow: hidden;
  transform: rotate(90deg) translateY(-100%);
  transform-origin: top left;
}

/* ═══ 横屏矩阵表头（固定在旋转容器外部）═══ */
.landscape-matrix-header {
  flex-shrink: 0;
  display: flex;
  background: #f7f8fa;
  border-bottom: 1px solid #e8e8e8;
}

.landscape-matrix-header .lmh-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;
}

.landscape-matrix-header .lmh-day {
  flex: 1;
  min-width: 0;
  text-align: center;
  padding: 0.08rem 0.04rem;
  border-left: 1px solid #f0f0f0;
}

.landscape-matrix-header .lmh-day .day-name {
  font-weight: 600;
  font-size: 0.22rem;
  line-height: 1.4;
}

.landscape-matrix-header .lmh-day .day-date {
  font-size: 0.18rem;
  color: #888;
  line-height: 1.3;
}

.landscape-matrix-header .lmh-day--today {
  background: #e6f7ff;
}

.landscape-matrix-header .lmh-day--today .day-name {
  color: #1890ff;
}
</style>
