<template>
  <v-app-bar class="no-select">
    <template #prepend>
      <v-app-bar-nav-icon icon="mdi-home" />
    </template>

    <v-app-bar-title>
      {{ state.classNumber }} - {{ titleText }}
    </v-app-bar-title>

    <v-spacer />

    <template #append>
      <v-btn icon="mdi-format-font-size-decrease" variant="text" @click="zoom('out')" />
      <v-btn icon="mdi-format-font-size-increase" variant="text" @click="zoom('up')" />
      <v-menu v-model="state.datePickerDialog" :close-on-content-click="false">
        <template #activator="{ props }">
          <v-btn icon="mdi-calendar" variant="text" v-bind="props" />
        </template>
        <v-card border>
          <v-date-picker v-model="state.selectedDateObj" :model-value="state.selectedDateObj" color="primary"
            @update:model-value="handleDateSelect" />
        </v-card>
      </v-menu>
      <v-btn icon="mdi-refresh" variant="text" :loading="loading.download" @click="downloadData" /> <v-btn
        icon="mdi-bell" variant="text" :badge="unreadCount || undefined"
        :badge-color="unreadCount ? 'error' : undefined" @click="$refs.messageLog.drawer = true" />
      <v-btn icon="mdi-cog" variant="text" @click="$router.push('/settings')" />

    </template>
  </v-app-bar>
  <div class="d-flex">
    <!-- 主要内容区域 -->
    <v-container class="main-window flex-grow-1 no-select" fluid>
      <!-- 有内容的科目卡片 -->
      <div ref="gridContainer" class="grid-masonry">
        <TransitionGroup name="grid">
          <div v-for="item in sortedItems" :key="item.key" class="grid-item" :style="{
            'grid-row-end': `span ${item.rowSpan}`,
            order: item.order,
          }">
            <v-card border height="100%" class="glow-track" @click="!isEditingDisabled && openDialog(item.key)"
              @mousemove="handleMouseMove" @touchmove="handleTouchMove">
              <v-card-title>{{ item.name }}</v-card-title>
              <v-card-text :style="state.contentStyle">
                <v-list>
                  <v-list-item v-for="text in splitPoint(item.content)" :key="text">
                    {{ text }}
                  </v-list-item>
                </v-list>
              </v-card-text>
            </v-card>
          </div>
        </TransitionGroup>
      </div>

      <!-- 单独显示空科目 -->
      <div class="empty-subjects mt-4">
        <template v-if="emptySubjectDisplay === 'button'">
          <v-btn-group divided variant="outlined">
            <v-btn v-for="subject in unusedSubjects" :key="subject.key" :disabled="isEditingDisabled"
              @click="openDialog(subject.key)">
              <v-icon start> mdi-plus </v-icon>
              {{ subject.name }}
            </v-btn>
          </v-btn-group>
        </template>
        <div v-else class="empty-subjects-grid">
          <TransitionGroup name="v-list">
            <v-card v-for="subject in unusedSubjects" :key="subject.key" border class="empty-subject-card"
              :disabled="isEditingDisabled" @click="openDialog(subject.key)">
              <v-card-title class="text-subtitle-1">
                {{ subject.name }}
              </v-card-title>
              <v-card-text class="text-center">
                <v-icon size="small" color="grey"> mdi-plus </v-icon>
                <div class="text-caption text-grey">点击添加作业</div>
              </v-card-text>
            </v-card>
          </TransitionGroup>
        </div>
      </div>
      <v-btn v-if="!state.synced" color="error" size="large" :loading="loading.upload" class="ml-2"
        @click="manualUpload">
        上传
      </v-btn>
      <v-btn v-else color="success" size="large" @click="showSyncMessage">
        同步完成 </v-btn><v-btn v-if="showRandomButton" color="yellow" prepend-icon="mdi-account-question"
        append-icon="mdi-dice-multiple" size="large" class="ml-2" href="classisland://plugins/IslandCaller/Run">
        随机点名
      </v-btn>
      <v-btn v-if="showFullscreenButton" :color="state.isFullscreen ? 'blue-grey' : 'blue'"
        :prepend-icon="state.isFullscreen ? 'mdi-fullscreen-exit' : 'mdi-fullscreen'" size="large" class="ml-2"
        @click="toggleFullscreen">
        {{ state.isFullscreen ? '退出全屏' : '全屏显示' }}
      </v-btn><!-- 修改防烧屏提示卡片，使用 tonal 样式减少信息密度 -->
      <v-card v-if="showAntiScreenBurnCard" border class="mt-4 anti-burn-card" color="primary" variant="tonal">
        <v-card-title class="text-subtitle-1">
          <v-icon start icon="mdi-shield-check" size="small" />
          屏幕保护技术已启用
        </v-card-title>
        <v-card-text class="text-body-2">
          <p>本应用采用独立自研的动态像素偏移技术(DPO™)，有效防止LCD屏幕烧屏现象。</p>
          <p class="text-caption text-grey">*研究显示动态像素偏移技术可以修复屏幕坏点，起到保护屏幕的作用，数据来自实验室。<a
              href="https://patentscope.wipo.int/search/zh/detail.jsf?docId=CN232281523&_cid=P20-M8L0YX-67061-1"
              target="_blank">专利号CN108648692 </a></p>
          <p class="text-caption text-grey">*技术已自动适配您的设备，无需手动调整</p>

        </v-card-text>
      </v-card>
    </v-container>

    <!-- 出勤统计区域 -->
    <v-col v-if="state.studentList && state.studentList.length" class="attendance-area no-select" cols="1"
      @click="setAttendanceArea()">
      <h1>出勤</h1>
      <h2>
        <snap style="white-space: nowrap"> 应到 </snap>:
        <snap style="white-space: nowrap">
          {{
            state.studentList.length -
            state.boardData.attendance.exclude.length
          }}人
        </snap>
      </h2>
      <h2>
        <snap style="white-space: nowrap"> 实到 </snap>:
        <snap style="white-space: nowrap">
          {{
            state.studentList.length -
            state.boardData.attendance.absent.length -
            state.boardData.attendance.late.length -
            state.boardData.attendance.exclude.length
          }}人
        </snap>
      </h2>
      <h2>
        <snap style="white-space: nowrap"> 请假 </snap>:
        <snap style="white-space: nowrap">
          {{ state.boardData.attendance.absent.length }}人
        </snap>
      </h2>
      <h3 class="gray-text" v-for="(name, index) in state.boardData.attendance.absent" :key="'absent-' + index">
        <span v-if="useDisplay().lgAndUp.value">{{ `${index + 1}. ` }}</span><span style="white-space: nowrap">{{ name
          }}</span>
      </h3>
      <h2>
        <snap style="white-space: nowrap">迟到</snap>:
        <snap style="white-space: nowrap">
          {{ state.boardData.attendance.late.length }}人
        </snap>
      </h2>
      <h3 class="gray-text" v-for="(name, index) in state.boardData.attendance.late" :key="'late-' + index">
        <span v-if="useDisplay().lgAndUp.value">{{ `${index + 1}. ` }}</span><span style="white-space: nowrap">{{ name
          }}</span>
      </h3>
      <h2>
        <snap style="white-space: nowrap">不参与</snap>:
        <snap style="white-space: nowrap">
          {{ state.boardData.attendance.exclude.length }}人
        </snap>
      </h2>
      <h3 class="gray-text" v-for="(name, index) in state.boardData.attendance.exclude" :key="'exclude-' + index">
        <span v-if="useDisplay().lgAndUp.value">{{ `${index + 1}. ` }}</span><span style="white-space: nowrap">{{ name
          }}</span>
      </h3>
    </v-col>
  </div>

  <v-dialog v-model="state.dialogVisible" width="500" @click:outside="handleClose">
    <v-card border>
      <v-card-title>{{ state.dialogTitle }}</v-card-title>
      <v-card-subtitle>
        {{ autoSave ? "喵？喵呜！" : "写完后点击上传谢谢喵" }}
      </v-card-subtitle>
      <v-card-text>
        <v-textarea ref="inputRef" v-model="state.textarea" auto-grow placeholder="使用换行表示分条" rows="5" />
      </v-card-text>
    </v-card>
  </v-dialog>

  <v-snackbar v-model="state.snackbar" :timeout="2000">
    {{ state.snackbarText }}
  </v-snackbar>

  <v-dialog v-model="state.attendanceDialog" max-width="900" fullscreen-breakpoint="sm" @update:model-value="handleAttendanceDialogClose">
    <v-card>
      <v-card-title class="d-flex align-center">
        <v-icon icon="mdi-account-group" class="mr-2" />
        出勤状态管理
        <v-spacer />
        <v-chip color="primary" size="small" class="ml-2">
          {{ state.dateString }}
        </v-chip>
      </v-card-title>

      <v-card-text>
      

        <!-- 批量操作和搜索 -->
        <v-row class="mb-4">
         
          <v-col cols="12" md="12">
            <v-text-field
              v-model="attendanceSearch"
              prepend-inner-icon="mdi-magnify"
              label="搜索学生"
              hide-details
              variant="outlined"
              density="compact"
              clearable
              @update:model-value="handleSearchChange"
            />
            <div class="text-caption mt-1">支持筛选姓氏，如输入"张"可筛选所有姓张的学生</div>
            
            <!-- 智能姓氏筛选 -->
            <div class="d-flex flex-wrap mt-2 gap-1">
              <v-btn 
                v-for="surname in extractedSurnames" 
                :key="surname.name" 
                size="small" 
                :variant="attendanceSearch === surname.name ? 'elevated' : 'text'" 
                :color="attendanceSearch === surname.name ? 'primary' : ''" 
                @click="attendanceSearch = attendanceSearch === surname.name ? '' : surname.name"
                class="surname-btn"
              >
                {{ surname.name }}
                <span class="text-caption ml-1">({{ surname.count }})</span>
              </v-btn>
            </div>
            
            <!-- 搜索建议 -->
            <div v-if="searchSuggestions.length > 0" class="mt-2">
              <div class="text-caption text-grey">搜索建议:</div>
              <div class="d-flex flex-wrap gap-1 mt-1">
                <v-btn 
                  v-for="suggestion in searchSuggestions" 
                  :key="suggestion" 
                  size="x-small" 
                  variant="text" 
                  color="secondary"
                  @click="attendanceSearch = suggestion"
                  class="suggestion-btn"
                  density="compact"
                >
                  {{ suggestion }}
                </v-btn>
              </div>
            </div>
          </v-col>
        </v-row>

        <!-- 过滤器 -->
        <div class="d-flex flex-wrap mb-4 gap-2">
          <div>
            <v-chip 
              value="present" 
              :color="attendanceFilter.includes('present') ? 'success' : ''" 
              :variant="attendanceFilter.includes('present') ? 'elevated' : 'tonal'" 
              class="px-2 filter-chip"
              @click="toggleFilter('present')"
              prepend-icon="mdi-account-check"
              :append-icon="attendanceFilter.includes('present') ? 'mdi-check' : ''"
            >
              到课
            </v-chip>
            
            <v-chip 
              value="absent" 
              :color="attendanceFilter.includes('absent') ? 'error' : ''" 
              :variant="attendanceFilter.includes('absent') ? 'elevated' : 'tonal'" 
              class="px-2 filter-chip"
              @click="toggleFilter('absent')"
              prepend-icon="mdi-account-off"
              :append-icon="attendanceFilter.includes('absent') ? 'mdi-check' : ''"
            >
              请假
            </v-chip>
            <v-chip 
              value="late" 
              :color="attendanceFilter.includes('late') ? 'warning' : ''" 
              :variant="attendanceFilter.includes('late') ? 'elevated' : 'tonal'" 
              class="px-2 filter-chip"
              @click="toggleFilter('late')"
              prepend-icon="mdi-clock-alert"
              :append-icon="attendanceFilter.includes('late') ? 'mdi-check' : ''"
            >
              迟到
            </v-chip>
            <v-chip 
              value="exclude" 
              :color="attendanceFilter.includes('exclude') ? 'grey' : ''" 
              :variant="attendanceFilter.includes('exclude') ? 'elevated' : 'tonal'" 
              class="px-2 filter-chip"
              @click="toggleFilter('exclude')"
              prepend-icon="mdi-account-cancel"
              :append-icon="attendanceFilter.includes('exclude') ? 'mdi-check' : ''"
            >
              不参与
            </v-chip>
          </div>
        </div>

        <!-- 学生列表 -->
        <v-row>
          <v-col 
            v-for="student in filteredStudents" 
            :key="student" 
            cols="12" sm="6" md="6" lg="4"
          >
            <v-card 
              class="student-card"
              border
            >
              <v-card-text class="d-flex align-center pa-2">
                <div class="flex-grow-1">
                  <div class="d-flex align-center">
                    <v-avatar :color="getStudentStatusColor(state.studentList.indexOf(student))" size="24" class="mr-2">
                      <v-icon size="small">{{ getStudentStatusIcon(state.studentList.indexOf(student)) }}</v-icon>
                    </v-avatar>
                    <div class="text-subtitle-1">{{ student }}</div>
                  </div>
                </div>
                <div class="attendance-actions">
                  <v-btn 
                    :color="isPresent(state.studentList.indexOf(student)) ? 'success' : ''" 
                    icon="mdi-account-check" 
                    size="small"
                    variant="text"
                    @click="setPresent(state.studentList.indexOf(student))" 
                    :title="'设为到课'"
                  />
                  <v-btn 
                    :color="isAbsent(state.studentList.indexOf(student)) ? 'error' : ''" 
                    icon="mdi-account-off" 
                    size="small"
                    variant="text"
                    @click="setAbsent(state.studentList.indexOf(student))" 
                    :title="'设为请假'"
                  />
                  <v-btn 
                    :color="isLate(state.studentList.indexOf(student)) ? 'warning' : ''" 
                    icon="mdi-clock-alert" 
                    size="small"
                    variant="text"
                    @click="setLate(state.studentList.indexOf(student))" 
                    :title="'设为迟到'"
                  />
                  <v-btn 
                    :color="isExclude(state.studentList.indexOf(student)) ? 'grey' : ''" 
                    icon="mdi-account-cancel" 
                    size="small"
                    variant="text"
                    @click="setExclude(state.studentList.indexOf(student))" 
                    :title="'设为不参与'"
                  />
                </div>
              </v-card-text>
            </v-card>
          </v-col>
        </v-row>
        <v-row> <v-col cols="12" md="12">
            <v-card variant="tonal" color="primary" class="mb-4">
              <v-card-text>
                <div class="text-subtitle-2 mb-2">批量操作</div>
                <v-btn-group>
                  <v-btn color="success" prepend-icon="mdi-account-check" @click="setAllPresent">
                    全部到齐
                  </v-btn>
                  <v-btn color="error" prepend-icon="mdi-account-off" @click="setAllAbsent">
                    全部请假
                  </v-btn>              </v-btn-group>  <v-btn-group>

                  <v-btn color="warning" prepend-icon="mdi-clock-alert" @click="setAllLate">
                    全部迟到
                  </v-btn>
                  <v-btn color="grey" prepend-icon="mdi-account-cancel" @click="setAllExclude">
                    全部不参与
                  </v-btn>
                </v-btn-group>
              </v-card-text>
            </v-card>
          </v-col></v-row>
      </v-card-text>

      <v-divider />

      <v-card-actions>
        <v-spacer />
        <v-btn color="grey" variant="text" @click="state.attendanceDialog = false">
          取消
        </v-btn>
        <v-btn color="primary" @click="saveAttendance">
          <v-icon start>mdi-content-save</v-icon>
          保存
        </v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>

  <message-log ref="messageLog" />

  <!-- 添加确认对话框 -->
  <v-dialog v-model="confirmDialog.show" max-width="400">
    <v-card>
      <v-card-title class="text-h6"> 确认保存 </v-card-title>
      <v-card-text>
        您正在修改 {{ state.dateString }} 的数据，确定要保存吗？
      </v-card-text>
      <v-card-actions>
        <v-spacer />
        <v-btn color="grey" variant="text" @click="confirmDialog.reject">
          取消
        </v-btn>
        <v-btn color="primary" @click="confirmDialog.resolve"> 确认保存 </v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>


</template>

<script>
import MessageLog from "@/components/MessageLog.vue";
import dataProvider from "@/utils/dataProvider";
import { getSetting, watchSettings, setSetting } from "@/utils/settings";
import { useDisplay } from "vuetify";
import "../styles/index.scss";
import "../styles/transitions.scss"; // 添加新的样式导入
import { debounce, throttle } from "@/utils/debounce";
import '../styles/global.scss';

export default {
  name: "Classworks 作业板",
  components: {
    MessageLog,
  },
  data() {
    return {
      dataKey: "",
      provider: "",
      useDisplay: useDisplay,
      state: {
        classNumber: "",
        studentList: [],
        boardData: {
          homework: {},
          attendance: {
            absent: [],
            late: [],
            exclude: [],
          },
        },
        dialogVisible: false,
        dialogTitle: "",
        textarea: "",
        dateString: "", // 从 state 内统一管理日期
        synced: false,
        attendDialogVisible: false,
        contentStyle: { "font-size": `${getSetting("font.size")}px` },
        uploadLoading: false,
        downloadLoading: false,
        snackbar: false,
        snackbarText: "",
        fontSize: getSetting("font.size"),
        datePickerDialog: false,
        selectedDate: new Date().toISOString().split("T")[0],
        selectedDateObj: new Date(this.selectedDate),
        refreshInterval: null,
        subjectOrder: [
          "语文",
          "数学",
          "英语",
          "物理",
          "化学",
          "生物",
          "政治",
          "历史",
          "地理",
          "其他",
        ],
        showNoDataMessage: false,
        noDataMessage: "",
        isToday: false,
        attendanceDialog: false,
        availableSubjects: [
          { key: "语文", name: "语文" },
          { key: "数学", name: "数学" },
          { key: "英语", name: "英语" },
          { key: "物理", name: "物理" },
          { key: "化学", name: "化学" },
          { key: "生物", name: "生物" },
          { key: "政治", name: "政治" },
          { key: "历史", name: "历史" },
          { key: "地理", name: "地理" },
          { key: "其他", name: "其他" },
        ],
        isFullscreen: false,
      },
      loading: {
        download: false,
        upload: false,
        students: false,
      },
      debouncedUpload: null,
      throttledReflow: null,
      sortedItemsCache: {
        key: "",
        value: [],
      },
      confirmDialog: {
        show: false,
        resolve: null,
        reject: null,
      },
      attendanceSearch: "",
      attendanceFilter: [],
      searchSuggestions: [],
    };
  },

  computed: {
    isMobile() {
      return useDisplay().mobile.value;
    },
    titleText() {
      const today = this.getToday();
      const yesterday = new Date(today);
      yesterday.setDate(yesterday.getDate() - 1);

      const currentDateStr = this.state.dateString;
      const todayStr = this.formatDate(today);
      const yesterdayStr = this.formatDate(yesterday);

      if (currentDateStr === todayStr) {
        return "今天的作业";
      } else if (currentDateStr === yesterdayStr) {
        return "昨天的作业";
      } else {
        return `${currentDateStr}的作业`;
      }
    },
    sortedItems() {
      const key = `${JSON.stringify(
        this.state.boardData.homework
      )}_${this.state.subjectOrder.join()}_${this.dynamicSort}`;
      if (this.sortedItemsCache.key === key) {
        return this.sortedItemsCache.value;
      }

      const items = Object.entries(this.state.boardData.homework)
        .filter(([, value]) => value.content?.trim())
        .map(([key, value]) => ({
          key,
          name:
            this.state.availableSubjects.find((s) => s.key === key)?.name ||
            key,
          content: value.content,
          order: this.state.subjectOrder.indexOf(key),
          rowSpan: Math.ceil(
            (value.content.split("\n").filter((line) => line.trim()).length +
              1) *
            0.8
          ),
        }));

      const result = this.dynamicSort
        ? this.optimizeGridLayout(items)
        : items.sort((a, b) => a.order - b.order);

      this.updateSortedItemsCache(key, result);

      return result;
    },
    unusedSubjects() {
      const usedKeys = Object.keys(this.state.boardData.homework).filter(
        key => this.state.boardData.homework[key].content?.trim()
      );
      return this.state.availableSubjects.filter(
        (subject) => !usedKeys.includes(subject.key)
      );
    },
    emptySubjects() {
      if (this.emptySubjectDisplay !== "button") return [];
      return this.unusedSubjects;
    },
    autoSave() {
      return getSetting("edit.autoSave");
    },
    blockNonTodayAutoSave() {
      return getSetting("edit.blockNonTodayAutoSave");
    },
    isToday() {
      const today = new Date().toISOString().split("T")[0];
      return this.state.dateString === today;
    },
    canAutoSave() {
      // 只考虑自动保存开关和非当天限制
      return this.autoSave && (!this.blockNonTodayAutoSave || this.isToday);
    },
    needConfirmSave() {
      // 只在非今天且开启了确认选项时需要确认
      return !this.isToday && this.confirmNonTodaySave;
    },
    shouldShowBlockedMessage() {
      // 只在非今天且开启了自动保存和禁止非当天自动保存时提示
      return !this.isToday && this.autoSave && this.blockNonTodayAutoSave;
    },
    refreshBeforeEdit() {
      return getSetting("edit.refreshBeforeEdit");
    },
    emptySubjectDisplay() {
      return getSetting("display.emptySubjectDisplay");
    },
    dynamicSort() {
      return getSetting("display.dynamicSort");
    },
    isEditingDisabled() {
      return this.state.uploadLoading || this.state.downloadLoading;
    },
    unreadCount() {
      return this.$refs.messageLog?.unreadCount || 0;
    },
    showRandomButton() {
      return getSetting("display.showRandomButton");
    },
    confirmNonTodaySave() {
      return getSetting("edit.confirmNonTodaySave");
    },
    shouldShowSaveConfirm() {
      return !this.isToday && this.confirmNonTodaySave;
    },
    shouldBlockAutoSave() {
      return !this.isToday && this.autoSave && this.blockNonTodayAutoSave;
    },
    showFullscreenButton() {
      return getSetting("display.showFullscreenButton");
    },
    showAntiScreenBurnCard() {
      return getSetting("display.showAntiScreenBurnCard");
    },
    filteredStudents() {
      let students = [...this.state.studentList];
      
      // 应用搜索过滤
      if (this.attendanceSearch) {
        const searchTerm = this.attendanceSearch.toLowerCase();
        students = students.filter(student => 
          student.toLowerCase().includes(searchTerm)
        );
      }
      
      // 应用状态过滤
      if (this.attendanceFilter && this.attendanceFilter.length > 0) {
        students = students.filter(student => {
          const index = this.state.studentList.indexOf(student);
          if (this.attendanceFilter.includes('present') && this.isPresent(index)) return true;
          if (this.attendanceFilter.includes('absent') && this.isAbsent(index)) return true;
          if (this.attendanceFilter.includes('late') && this.isLate(index)) return true;
          if (this.attendanceFilter.includes('exclude') && this.isExclude(index)) return true;
          return false;
        });
      }
      
      return students;
    },
    extractedSurnames() {
      // 从学生名单中提取姓氏并统计数量
      if (!this.state.studentList || this.state.studentList.length === 0) {
        return [];
      }
      
      const surnameMap = new Map();
      
      this.state.studentList.forEach(student => {
        if (student && student.length > 0) {
          // 中文姓名通常姓在前，取第一个字作为姓氏
          const surname = student.charAt(0);
          if (surnameMap.has(surname)) {
            surnameMap.set(surname, surnameMap.get(surname) + 1);
          } else {
            surnameMap.set(surname, 1);
          }
        }
      });
      
      // 转换为数组并按数量排序
      return Array.from(surnameMap.entries())
        .map(([name, count]) => ({ name, count }))
        .sort((a, b) => b.count - a.count);
    },
  },

  watch: {
    homeworkData: {
      handler() {
        this.$nextTick(() => {
          if (this.$refs.waterfall) {
            this.$refs.waterfall.reflow();
          }
        });
      },
      deep: true,
    },
    "$vuetify.display.width": {
      handler() {
        this.throttledReflow();
      },
      deep: true,
    },
  },

  created() {
    // 创建防抖的上传函数
    this.debouncedUpload = debounce(this.uploadData, 2000);
    // 创建节流的重排函数
    this.throttledReflow = throttle(() => {
      if (this.$refs.gridContainer) {
        this.optimizeGridLayout(this.sortedItems);
      }
    }, 200);
  },

  async mounted() {
    try {
      this.updateBackendUrl();
      await this.initializeData();
      this.setupAutoRefresh();
      this.unwatchSettings = watchSettings(() => {
        this.updateSettings();
      });

      // 监听全屏变化事件
      document.addEventListener('fullscreenchange', this.fullscreenChangeHandler);
      document.addEventListener('webkitfullscreenchange', this.fullscreenChangeHandler);
      document.addEventListener('mozfullscreenchange', this.fullscreenChangeHandler);
      document.addEventListener('MSFullscreenChange', this.fullscreenChangeHandler);
    } catch (err) {
      console.error("初始化失败:", err);
      this.showError("初始化失败，请刷新页面重试");
    }
  },

  beforeUnmount() {
    if (this.unwatchSettings) {
      this.unwatchSettings();
    }
    if (this.state.refreshInterval) {
      // 注意刷新间隔存放在 state 内
      clearInterval(this.state.refreshInterval);
    }

    // 移除全屏变化事件监听
    document.removeEventListener('fullscreenchange', this.fullscreenChangeHandler);
    document.removeEventListener('webkitfullscreenchange', this.fullscreenChangeHandler);
    document.removeEventListener('mozfullscreenchange', this.fullscreenChangeHandler);
    document.removeEventListener('MSFullscreenChange', this.fullscreenChangeHandler);
  },

  methods: {
    // 添加新的日期辅助方法
    ensureDate(dateInput) {
      if (dateInput instanceof Date) {
        return dateInput;
      }
      if (typeof dateInput === "string") {
        const date = new Date(dateInput);
        if (!isNaN(date.getTime())) {
          return date;
        }
      }
      return new Date(); // 如果无法解析，返回当前日期
    },

    formatDate(dateInput) {
      const date = this.ensureDate(dateInput);
      const year = date.getFullYear();
      const month = String(date.getMonth() + 1).padStart(2, "0");
      const day = String(date.getDate()).padStart(2, "0");
      return `${year}-${month}-${day}`;
    },

    getToday() {
      return new Date();
    },

    async initializeData() {
      this.provider = getSetting("server.provider");
      const domain = getSetting("server.domain");
      const classNum = getSetting("server.classNumber");

      this.dataKey =
        this.provider === "server" ? `${domain}/${classNum}` : classNum;
      this.state.classNumber = classNum;

      // 从 URL 获取日期，如果没有则使用今天的日期
      const urlParams = new URLSearchParams(window.location.search);
      const dateFromUrl = urlParams.get("date");
      const today = this.getToday();

      // 确保日期格式正确
      const currentDate = dateFromUrl ? new Date(dateFromUrl) : today;
      this.state.dateString = this.formatDate(currentDate);
      this.state.selectedDate = this.state.dateString;
      this.state.isToday =
        this.formatDate(currentDate) === this.formatDate(today);

      await Promise.all([this.downloadData(), this.loadConfig()]);
    },

    async downloadData() {
      if (this.loading.download) return;

      try {
        this.loading.download = true;
        const response = await dataProvider.loadData(
          this.provider,
          this.dataKey,
          this.state.dateString
        );

        if (!response.success) {
          if (response.error.code === "NOT_FOUND") {
            this.state.showNoDataMessage = true;
            this.state.noDataMessage = response.error.message;
            // 确保数据结构完整
            this.state.boardData = {
              homework: {},
              attendance: { absent: [], late: [], exclude: [] },
            };
          } else {
            throw new Error(response.error.message);
          }
        } else {
          // 确保数据结构完整
          this.state.boardData = {
            homework: response.data.homework || {},
            attendance: {
              absent: response.data.attendance?.absent || [],
              late: response.data.attendance?.late || [],
              exclude: response.data.attendance?.exclude || [],
            },
          };
          this.state.synced = true;
          this.state.showNoDataMessage = false;
          this.$message.success("下载成功", "数据已更新");
        }
      } catch (error) {
        // 发生错误时也要确保数据结构完整
        this.state.boardData = {
          homework: {},
          attendance: { absent: [], late: [], exclude: [] },
        };
        this.$message.error("下载失败", error.message);
      } finally {
        this.loading.download = false;
      }
    },

    async trySave(isAutoSave = false) {
      // 如果是自动保存但不满足自动保存条件
      if (isAutoSave && !this.canAutoSave) {
        if (this.shouldShowBlockedMessage) {
          this.showMessage(
            "需要手动保存",
            "已禁止自动保存非当天数据",
            "warning"
          );
        }
        return false;
      }

      // 如果需要确认且不是自动保存
      if (!isAutoSave && this.needConfirmSave) {
        try {
          await this.showConfirmDialog();
        } catch {
          return false;
        }
      }

      // 尝试保存
      try {
        await this.uploadData();
        return true;
      } catch (error) {
        this.$message.error("保存失败", error.message || "请重试");
        return false;
      }
    },

    async handleClose() {
      if (!this.currentEditSubject) return;

      const content = this.state.textarea.trim();
      const originalContent =
        this.state.boardData.homework[this.currentEditSubject]?.content || "";

      // 如果内容发生变化(包括清空)，就视为修改
      if (content !== originalContent.trim()) {
        // 无论内容是否为空，都保留科目结构
        this.state.boardData.homework[this.currentEditSubject] = {
          content: content,
        };

        this.state.synced = false;

        // 处理自动保存
        if (this.autoSave) {
          await this.trySave(true);
        }
      }

      this.state.dialogVisible = false;
    },

    async uploadData() {
      if (this.loading.upload) return;

      try {
        this.loading.upload = true;
        const response = await dataProvider.saveData(
          this.provider,
          this.dataKey,
          this.state.boardData,
          this.state.dateString // 添加dateString参数
        );

        if (!response.success) {
          throw new Error(response.error.message);
        }

        this.state.synced = true;
        this.$message.success(response.message || "保存成功");
      } finally {
        this.loading.upload = false;
      }
    },

    async loadConfig() {
      try {
        const response = await dataProvider.loadConfig(
          this.provider,
          this.dataKey
        );

        if (!response.success) {
          throw new Error(response.error.message);
        }

        this.state.studentList = response.data.studentList || [];
      } catch (error) {
        console.error("加载配置失败:", error);
        this.$message.error("加载配置失败", error.message);
      }
    },

    showSyncMessage() {
      this.$message.success("数据已同步", "数据已完成与服务器同步");
    },

    async openDialog(subject) {
      if (this.refreshBeforeEdit) {
        try {
          await this.downloadData();
        } catch (err) {
          console.error("刷新数据失败:", err);
          this.$message.error("刷新数据失败，可能显示的不是最新数据");
        }
      }

      this.currentEditSubject = subject;
      // 如果是新科目，需要创建对应的精简数据结构
      if (!this.state.boardData.homework[subject]) {
        this.state.boardData.homework[subject] = {
          content: "",
        };
      }
      this.state.dialogTitle =
        this.state.availableSubjects.find((s) => s.key === subject)?.name ||
        subject;
      this.state.textarea = this.state.boardData.homework[subject].content;
      this.state.dialogVisible = true;
      this.$nextTick(() => {
        if (this.$refs.inputRef) {
          this.$refs.inputRef.focus();
        }
      });
    },

    splitPoint(content) {
      return content.split("\n").filter((text) => text.trim());
    },

    setAttendanceArea() {
      this.state.attendanceDialog = true;
    },

    toggleStudentStatus(index) {
      const student = this.state.studentList[index];
      if (this.state.boardData.attendance.absent.includes(student)) {
        this.state.boardData.attendance.absent =
          this.state.boardData.attendance.absent.filter(
            (name) => name !== student
          );
        this.state.boardData.attendance.late.push(student);
      } else if (this.state.boardData.attendance.late.includes(student)) {
        this.state.boardData.attendance.late =
          this.state.boardData.attendance.late.filter(
            (name) => name !== student
          );
        this.state.boardData.attendance.exclude.push(student);
      } else if (this.state.boardData.attendance.exclude.includes(student)) {
        this.state.boardData.attendance.exclude =
          this.state.boardData.attendance.exclude.filter(
            (name) => name !== student
          );
      } else {
        this.state.boardData.attendance.absent.push(student);
      }
      this.state.synced = false;
      if (this.canAutoSave) {
        this.uploadData();
      }
    },

    cleanstudentslist() {
      this.state.boardData.attendance.absent = [];
      this.state.boardData.attendance.late = [];
      this.state.boardData.attendance.exclude = [];
      this.state.synced = false;
      if (this.canAutoSave) {
        this.uploadData();
      }
    },

    zoom(direction) {
      const step = 2;
      if (direction === "up" && this.state.fontSize < 100) {
        this.state.fontSize += step;
      } else if (direction === "out" && this.state.fontSize > 16) {
        this.state.fontSize -= step;
      }
      this.state.contentStyle = {
        "font-size": `${this.state.fontSize}px`,
      };
      setSetting("font.size", this.state.fontSize);
    },

    updateBackendUrl() {
      const provider = getSetting("server.provider");
      const domain = getSetting("server.domain");
      const classNum = getSetting("server.classNumber");

      this.provider = provider;
      this.dataKey = provider === "server" ? `${domain}/${classNum}` : classNum;
      this.state.classNumber = classNum;
    },

    setupAutoRefresh() {
      const autoRefresh = getSetting("refresh.auto");
      const interval = getSetting("refresh.interval");
      if (this.state.refreshInterval) {
        clearInterval(this.state.refreshInterval);
      }
      if (autoRefresh) {
        this.state.refreshInterval = setInterval(() => {
          this.downloadData();
        }, interval * 1000);
      }
    },

    updateSettings() {
      this.state.fontSize = getSetting("font.size");
      this.state.contentStyle = { "font-size": `${this.state.fontSize}px` };
      this.setupAutoRefresh();
      this.updateBackendUrl();
    },

    handleDateSelect(newDate) {
      if (!newDate) return;

      try {
        const selectedDate = this.ensureDate(newDate);
        const formattedDate = this.formatDate(selectedDate);

        // 只有当日期真正改变时才更新
        if (this.state.dateString !== formattedDate) {
          this.state.dateString = formattedDate;
          this.state.selectedDate = formattedDate;
          this.state.isToday =
            formattedDate === this.formatDate(this.getToday());

          // 使用 replace 而不是 push 来避免创建新的历史记录
          this.$router
            .replace({
              query: { date: formattedDate },
            })
            .catch(() => { });
          this.downloadData();
        }
      } catch (error) {
        console.error("Date processing error:", error);
        this.$message.error("日期处理错误", "请重新选择日期");
      }
    },

    optimizeGridLayout(items) {
      // 设置最大列数
      const maxColumns = Math.min(3, Math.floor(window.innerWidth / 300));
      if (maxColumns <= 1) return items;

      // 使用贪心算法分配
      const columns = Array.from({ length: maxColumns }, () => ({
        height: 0,
        items: [],
      }));

      items.forEach((item) => {
        const shortestColumn = columns.reduce(
          (min, col, i) => (col.height < columns[min].height ? i : min),
          0
        );
        columns[shortestColumn].items.push(item);
        columns[shortestColumn].height += item.rowSpan;
      });

      // 展平结果并添加顺序
      return columns
        .flatMap((col) => col.items)
        .map((item, index) => ({
          ...item,
          order: index,
        }));
    },

    fixedGridLayout(items) {
      const rowSubjects = [
        ["语文", "数学", "英语"],
        ["物理", "化学", "生物"],
        ["政治", "历史", "地理", "其他"],
      ];
      return items
        .sort((a, b) => {
          const getRowIndex = (subject) => {
            for (let i = 0; i < rowSubjects.length; i++) {
              if (rowSubjects[i].includes(subject)) {
                return i;
              }
            }
            return rowSubjects.length;
          };
          const getColumnIndex = (subject) => {
            for (const row of rowSubjects) {
              const index = row.indexOf(subject);
              if (index !== -1) return index;
            }
            return 999;
          };
          const rowA = getRowIndex(a.key);
          const rowB = getRowIndex(b.key);
          if (rowA !== rowB) {
            return rowA - rowB;
          }
          const colA = getColumnIndex(a.key);
          const colB = getColumnIndex(b.key);
          return colA - colB;
        })
        .map((item, index) => ({
          ...item,
          order: index,
          rowSpan: item.content ? 2 : 1,
        }));
    },

    setAllPresent() {
      this.state.boardData.attendance = {
        absent: [],
        late: [],
        exclude: [],
      };
      this.state.synced = false;
    },

    setAllAbsent() {
      this.state.boardData.attendance.absent = [...this.state.studentList];
      this.state.boardData.attendance.late = [];
      this.state.boardData.attendance.exclude = [];
      this.state.synced = false;
    },

    setAllLate() {
      this.state.boardData.attendance.absent = [];
      this.state.boardData.attendance.late = [...this.state.studentList];
      this.state.boardData.attendance.exclude = [];
      this.state.synced = false;
    },
    setAllExclude() {
      this.state.boardData.attendance.absent = [];
      this.state.boardData.attendance.late = [];
      this.state.boardData.attendance.exclude = [...this.state.studentList];
      this.state.synced = false;
    },  

    isPresent(index) {
      const student = this.state.studentList[index];
      const { absent, late, exclude } = this.state.boardData.attendance;
      return (
        !absent.includes(student) &&
        !late.includes(student) &&
        !exclude.includes(student)
      );
    },

    isAbsent(index) {
      return this.state.boardData.attendance.absent.includes(
        this.state.studentList[index]
      );
    },

    isLate(index) {
      return this.state.boardData.attendance.late.includes(
        this.state.studentList[index]
      );
    },

    isExclude(index) {
      return this.state.boardData.attendance.exclude.includes(
        this.state.studentList[index]
      );
    },

    setPresent(index) {
      const student = this.state.studentList[index];
      // 从所有状态列表中移除该学生
      this.state.boardData.attendance.absent = this.state.boardData.attendance.absent.filter(
        (name) => name !== student
      );
      this.state.boardData.attendance.late = this.state.boardData.attendance.late.filter(
        (name) => name !== student
      );
      this.state.boardData.attendance.exclude = this.state.boardData.attendance.exclude.filter(
        (name) => name !== student
      );
      this.state.synced = false;
    },

    setAbsent(index) {
      const student = this.state.studentList[index];
      // 先从所有状态列表中移除该学生
      this.setPresent(index);
      // 然后添加到请假列表
      this.state.boardData.attendance.absent.push(student);
      this.state.synced = false;
    },

    setLate(index) {
      const student = this.state.studentList[index];
      // 先从所有状态列表中移除该学生
      this.setPresent(index);
      // 然后添加到迟到列表
      this.state.boardData.attendance.late.push(student);
      this.state.synced = false;
    },

    setExclude(index) {
      const student = this.state.studentList[index];
      // 先从所有状态列表中移除该学生
      this.setPresent(index);
      // 然后添加到不参与列表
      this.state.boardData.attendance.exclude.push(student);
      this.state.synced = false;
    },

    async saveAttendance() {
      try {
        await this.trySave(true);
        this.state.attendanceDialog = false;
      } catch (error) {
        console.error("保存出勤状态失败:", error);
        this.$message.error("保存失败", "请重试");
      }
    },

    showMessage(title, content = "", type = "success") {
      this.$message[type](title, content);
    },

    updateSortedItemsCache(key, value) {
      this._sortedItemsCache = {
        key,
        value,
      };
    },

    handleMouseMove(e) {
      const card = e.currentTarget;
      const rect = card.getBoundingClientRect();
      const x = ((e.clientX - rect.left) / rect.width) * 100;
      const y = ((e.clientY - rect.top) / rect.height) * 100;
      card.style.setProperty('--x', `${x}%`);
      card.style.setProperty('--y', `${y}%`);
    },

    handleTouchMove(e) {
      if (e.touches.length === 1) {
        const touch = e.touches[0];
        const card = e.currentTarget;
        const rect = card.getBoundingClientRect();
        const x = ((touch.clientX - rect.left) / rect.width) * 100;
        const y = ((touch.clientY - rect.top) / rect.height) * 100;
        card.style.setProperty('--x', `${x}%`);
        card.style.setProperty('--y', `${y}%`);
      }
    },

    showConfirmDialog() {
      return new Promise((resolve, reject) => {
        this.confirmDialog = {
          show: true,
          resolve: () => {
            this.confirmDialog.show = false;
            resolve();
          },
          reject: () => {
            this.confirmDialog.show = false;
            reject(new Error("用户取消保存"));
          },
        };
      });
    },

    confirmSave() {
      this.confirmDialog.show = false;
      if (this.confirmDialog.resolve) {
        this.confirmDialog.resolve(true);
      }
    },

    cancelSave() {
      this.confirmDialog.show = false;
      if (this.confirmDialog.reject) {
        this.confirmDialog.reject(new Error("用户取消保存"));
      }
    },

    // 点击上传按钮时调用
    async manualUpload() {
      return this.trySave(false);
    },

    async handleAttendanceDialogClose(newValue) {
      if (!newValue && !this.state.synced) {
        // 对话框关闭且数据未同步时尝试保存
        await this.trySave(true);
      }
    },

    // 全屏相关方法
    toggleFullscreen() {
      if (!this.state.isFullscreen) {
        this.enterFullscreen();
      } else {
        this.exitFullscreen();
      }
    },

    enterFullscreen() {
      const docElm = document.documentElement;

      if (docElm.requestFullscreen) {
        docElm.requestFullscreen();
      } else if (docElm.webkitRequestFullScreen) {
        docElm.webkitRequestFullScreen();
      } else if (docElm.mozRequestFullScreen) {
        docElm.mozRequestFullScreen();
      } else if (docElm.msRequestFullscreen) {
        docElm.msRequestFullscreen();
      }
    },

    exitFullscreen() {
      if (document.exitFullscreen) {
        document.exitFullscreen();
      } else if (document.webkitExitFullscreen) {
        document.webkitExitFullscreen();
      } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
      } else if (document.msExitFullscreen) {
        document.msExitFullscreen();
      }
    },

    fullscreenChangeHandler() {
      this.state.isFullscreen = !!(
        document.fullscreenElement ||
        document.webkitFullscreenElement ||
        document.mozFullScreenElement ||
        document.msFullscreenElement
      );
    },

    getStudentStatusColor(index) {
      const studentName = this.state.studentList[index];
      if (this.state.boardData.attendance.absent.includes(studentName)) return 'error';
      if (this.state.boardData.attendance.late.includes(studentName)) return 'warning';
      if (this.state.boardData.attendance.exclude.includes(studentName)) return 'grey';
      return 'success';
    },
    
    getStudentStatusVariant(index) {
      const studentName = this.state.studentList[index];
      if (this.state.boardData.attendance.absent.includes(studentName) ||
          this.state.boardData.attendance.late.includes(studentName) ||
          this.state.boardData.attendance.exclude.includes(studentName)) {
        return 'tonal';
      }
      return 'outlined';
    },
    
    getStudentStatusIcon(index) {
      const studentName = this.state.studentList[index];
      if (this.state.boardData.attendance.absent.includes(studentName)) return 'mdi-account-off';
      if (this.state.boardData.attendance.late.includes(studentName)) return 'mdi-clock-alert';
      if (this.state.boardData.attendance.exclude.includes(studentName)) return 'mdi-account-cancel';
      return 'mdi-account-check';
    },
    
    getStudentStatusText(index) {
      const studentName = this.state.studentList[index];
      if (this.state.boardData.attendance.absent.includes(studentName)) return '请假';
      if (this.state.boardData.attendance.late.includes(studentName)) return '迟到';
      if (this.state.boardData.attendance.exclude.includes(studentName)) return '不参与';
      return '到课';
    },

    handleSearchChange(value) {
      // 生成搜索建议
      this.generateSearchSuggestions(value);
    },
    
    generateSearchSuggestions(searchTerm) {
      if (!searchTerm || searchTerm.length < 1) {
        this.searchSuggestions = [];
        return;
      }
      
      // 查找匹配的学生名字
      const matchingStudents = this.state.studentList.filter(student => 
        student.toLowerCase().includes(searchTerm.toLowerCase())
      );
      
      // 如果有精确匹配，不显示建议
      if (matchingStudents.some(student => student === searchTerm)) {
        this.searchSuggestions = [];
        return;
      }
      
      // 提取匹配的部分作为建议
      const suggestions = new Set();
      
      // 如果是单个字符，可能是在搜索姓氏
      if (searchTerm.length === 1) {
        // 添加所有以该字符开头的学生的完整姓名作为建议
        matchingStudents.forEach(student => {
          if (student.startsWith(searchTerm)) {
            suggestions.add(student);
          }
        });
      } else {
        // 对于多字符搜索，添加包含该字符串的学生名字
        matchingStudents.forEach(student => {
          suggestions.add(student);
        });
      }
      
      // 限制建议数量
      this.searchSuggestions = Array.from(suggestions).slice(0, 5);
    },

    toggleFilter(filter) {
      const index = this.attendanceFilter.indexOf(filter);
      if (index === -1) {
        this.attendanceFilter.push(filter);
      } else {
        this.attendanceFilter.splice(index, 1);
      }
    },
  },
};
</script>
<style lang="scss">
// 添加卡片发光效果
.glow-track {
  position: relative;
  overflow: hidden;
  transition: all 0.3s ease;

  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: radial-gradient(circle at var(--x, 50%) var(--y, 50%),
        rgba(255, 255, 255, 0.15) 0%,
        rgba(255, 255, 255, 0) 70%);
    opacity: 0;
    transition: opacity 0.3s;
    pointer-events: none;
    z-index: 1;
  }

  &:hover::before {
    opacity: 1;
  }
}

// 添加卡片悬浮效果
.grid-item .v-card {
  transition: transform 0.3s ease, box-shadow 0.3s ease;

  &:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15) !important;
  }

  &:active {
    transform: translateY(-2px);
  }
}

// 添加空科目卡片样式
.empty-subject-card {
  transition: all 0.3s ease;
  opacity: 0.8;

  &:hover {
    opacity: 1;
    transform: translateY(-4px);
  }
}

// 修改防烧屏提示卡片，使用 tonal 样式减少信息密度
.anti-burn-card {
  animation: subtle-glow 4s infinite alternate;
  transition: all 0.3s ease;

  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
  }
}

@keyframes subtle-glow {
  0% {
    box-shadow: 0 0 5px rgba(33, 150, 243, 0.1);
  }

  100% {
    box-shadow: 0 0 15px rgba(33, 150, 243, 0.3);
  }
}

// 出勤管理对话框样式
.attendance-stat {
  height: 100%;
}

// 姓氏筛选按钮
.surname-btn {
  margin: 2px;
  min-width: 0;
  padding: 0 8px;
  
  &:active {
    transform: scale(0.95);
  }
}

// 搜索建议按钮
.suggestion-btn {
  margin: 2px;
  min-width: 0;
  padding: 0 6px;
  
  &:active {
    transform: scale(0.95);
  }
}

// 适配触摸屏
@media (hover: none) {
  .student-card .attendance-actions {
    opacity: 1;
  }
}

// 小屏幕适配
@media (max-width: 600px) {
  .student-card {
    .attendance-actions .v-btn {
      margin: 0 1px;
      min-width: 28px;
      width: 28px;
      height: 28px;
    }
  }
}

// 过滤器芯片
.filter-chip {
  cursor: pointer;
  margin: 2px;
  
  &:active {
    transform: scale(0.95);
  }
}
</style>
