const labCatalog = [
  {
    id: "lab-1",
    college: "资源环境学院",
    name: "植物养分实验室",
    room: "A201",
    building: "农科楼2楼",
    manager: "王*二",
    level: 3,
    category: "化学类",
    type: "教学科研型实验室"
  },
  {
    id: "lab-2",
    college: "动物科技学院",
    name: "细胞培养实验室",
    room: "B305",
    building: "生命楼3楼",
    manager: "李*华",
    level: 2,
    category: "生物类",
    type: "科研平台实验室"
  },
  {
    id: "lab-3",
    college: "机械与电子工程学院",
    name: "电气控制实验室",
    room: "C110",
    building: "机电楼1楼",
    manager: "周*明",
    level: 1,
    category: "机电类",
    type: "教学型实验室"
  },
  {
    id: "lab-4",
    college: "林学院",
    name: "辐照分析实验室",
    room: "D402",
    building: "综合实验楼4楼",
    manager: "陈*宁",
    level: 4,
    category: "辐射类",
    type: "重点风险实验室"
  }
];

const roleProfiles = {
  newGraduate: {
    key: "newGraduate",
    label: "新入学研究生",
    subtitle: "首次进入系统，需完成实验室绑定后获取学时与考试路径",
    name: "刘子衡",
    code: "2026003489",
    type: "研究生",
    org: "资源环境学院",
    term: "2026-2027 学年",
    isFreshGraduate: true,
    bindingStatus: "unbound",
    labChoiceMode: null,
    lab: null,
    requiredHours: 24,
    completedHours: 8,
    examStatus: "待绑定后确认考试类型",
    certificateStatus: "未生成",
    certificateTag: "locked",
    yearlyRecords: [
      { year: "2026", score: "未考试", status: "待启动" },
      { year: "2025", score: "新入学", status: "首次学年" }
    ],
    tasks: [
      { title: "危化品识别与存储规范", progress: "2 / 6 章节", note: "已学习 85 分钟" },
      { title: "实验室准入前通识学习包", progress: "1 / 4 章节", note: "待完成签收测验" }
    ],
    resourceSummary: {
      title: "待绑定实验室后推荐分级资源",
      desc: "当前先展示通识资料，完成绑定后将按实验室分类切换到对应资源库。"
    },
    practice: {
      done: 46,
      total: 180,
      correctRate: "81%"
    },
    examCard: {
      title: "分级考试",
      status: "未解锁",
      desc: "绑定实验室并完成 24 学时后开放，若选择不进入实验室则切换为应知应会考试。",
      points: [
        { title: "实验室绑定", detail: "当前未提交", status: "pending" },
        { title: "学时完成", detail: "8 / 24 学时", status: "locked" },
        { title: "考试开放", detail: "待满足前置条件", status: "locked" }
      ]
    }
  },
  graduateSenior: {
    key: "graduateSenior",
    label: "研二/研三/研四",
    subtitle: "高年级研究生按学年执行 24 学时与应知应会考试",
    name: "宋若宁",
    code: "2024001721",
    type: "研究生",
    org: "动物科技学院",
    term: "2026-2027 学年",
    isFreshGraduate: false,
    bindingStatus: "approved",
    labChoiceMode: "lab",
    lab: {
      title: "细胞培养实验室（B305）",
      manager: "李*华",
      level: 2,
      category: "生物类",
      type: "科研平台实验室"
    },
    requiredHours: 24,
    completedHours: 24,
    examStatus: "应知应会考试已通过",
    certificateStatus: "2026 学年证书已签发",
    certificateTag: "success",
    yearlyRecords: [
      { year: "2026", score: "92 分", status: "已通过" },
      { year: "2025", score: "88 分", status: "已通过" },
      { year: "2024", score: "90 分", status: "已通过" }
    ],
    tasks: [
      { title: "生物安全基础与样本管理", progress: "5 / 5 章节", note: "已完成" },
      { title: "实验废弃物分类处置", progress: "4 / 4 章节", note: "已完成" }
    ],
    resourceSummary: {
      title: "生物类专项资源",
      desc: "根据绑定实验室分类推荐资料与题库，并保留通用安全素养入口。"
    },
    practice: {
      done: 180,
      total: 180,
      correctRate: "94%"
    },
    examCard: {
      title: "应知应会考试",
      status: "已通过",
      desc: "本学年已完成 24 学时学习并通过考试，可直接查看证书与历年记录。",
      points: [
        { title: "学时完成", detail: "24 / 24 学时", status: "success" },
        { title: "考试成绩", detail: "92 分", status: "success" },
        { title: "证书状态", detail: "已生成", status: "success" }
      ]
    }
  },
  newUndergraduate: {
    key: "newUndergraduate",
    label: "新入学本科生",
    subtitle: "新生执行 4 学时学习与新生入学考试",
    name: "赵晴川",
    code: "2026010432",
    type: "本科生",
    org: "信息工程学院",
    term: "2026-2027 学年",
    isFreshGraduate: false,
    bindingStatus: "not_required",
    labChoiceMode: "no_lab",
    lab: null,
    requiredHours: 4,
    completedHours: 3,
    examStatus: "新生入学考试待开放",
    certificateStatus: "未生成",
    certificateTag: "locked",
    yearlyRecords: [
      { year: "2026", score: "未考试", status: "学习中" }
    ],
    tasks: [
      { title: "实验室安全基本行为规范", progress: "3 / 4 章节", note: "已学习 126 分钟" },
      { title: "消防逃生与应急疏散", progress: "2 / 2 章节", note: "已完成" }
    ],
    resourceSummary: {
      title: "应知应会知识资源",
      desc: "本科新生优先完成通识资源学习，达成 4 学时后开放入学考试。"
    },
    practice: {
      done: 28,
      total: 80,
      correctRate: "76%"
    },
    examCard: {
      title: "新生入学考试",
      status: "待解锁",
      desc: "还差 1 学时，完成后可立即参加在线考试并发放证书。",
      points: [
        { title: "学时完成", detail: "3 / 4 学时", status: "pending" },
        { title: "考试开放", detail: "达标后自动开放", status: "locked" },
        { title: "证书状态", detail: "通过后生成", status: "locked" }
      ]
    }
  },
  staff: {
    key: "staff",
    label: "教职工",
    subtitle: "教职工按学年完成 4 学时和应知应会考试",
    name: "谢文卓",
    code: "T2021086",
    type: "教职工",
    org: "实验室安全与条件保障处",
    term: "2026-2027 学年",
    isFreshGraduate: false,
    bindingStatus: "not_required",
    labChoiceMode: "no_lab",
    lab: {
      title: "公共实验教学中心（E101）",
      manager: "谢*卓",
      level: 1,
      category: "基础类",
      type: "公共服务型实验室"
    },
    requiredHours: 4,
    completedHours: 4,
    examStatus: "应知应会考试已通过",
    certificateStatus: "年度证书已签发",
    certificateTag: "success",
    yearlyRecords: [
      { year: "2026", score: "95 分", status: "已通过" },
      { year: "2025", score: "93 分", status: "已通过" },
      { year: "2024", score: "89 分", status: "已通过" }
    ],
    tasks: [
      { title: "教职工安全责任制学习包", progress: "3 / 3 章节", note: "已完成" },
      { title: "实验室事故警示案例", progress: "2 / 2 章节", note: "已完成" }
    ],
    resourceSummary: {
      title: "教职工应知应会资源",
      desc: "重点覆盖责任体系、风险识别、隐患处置和应急组织机制。"
    },
    practice: {
      done: 66,
      total: 66,
      correctRate: "97%"
    },
    examCard: {
      title: "应知应会考试",
      status: "已通过",
      desc: "本学年要求已全部完成，可查看证书与考试明细。",
      points: [
        { title: "学时完成", detail: "4 / 4 学时", status: "success" },
        { title: "考试成绩", detail: "95 分", status: "success" },
        { title: "证书状态", detail: "已生成", status: "success" }
      ]
    }
  }
};

const resourceCatalog = {
  "化学类": {
    docs: [
      { title: "危化品分级储存与双人双锁规范", desc: "聚焦危化品库房、领用、留样与废弃流转节点。", meta: "学习时长 45 分钟" },
      { title: "易燃易爆实验风险点清单", desc: "适用于化学类和高风险混合实验场景。", meta: "图文资料" },
      { title: "酸碱腐蚀伤害应急处置卡", desc: "面向个人防护、冲洗、上报和现场隔离。", meta: "应急 SOP" }
    ],
    banks: [
      { title: "化学类应知应会题库", desc: "共 220 题，覆盖危化品、废液、通风与个体防护。", meta: "最近更新 2026-04" },
      { title: "分级考试强化练习包", desc: "按四级分类题目自动组卷，适合研一分级考试前冲刺。", meta: "模拟试卷 8 套" }
    ]
  },
  "生物类": {
    docs: [
      { title: "细胞与病原微生物操作规范", desc: "涵盖样本保存、台面消杀和暴露后处置。", meta: "学习时长 38 分钟" },
      { title: "生物废弃物分类与暂存", desc: "面向实验员与研究生的高频作业清单。", meta: "图文资料" }
    ],
    banks: [
      { title: "生物类专项题库", desc: "共 180 题，支持随机练习和错题复盘。", meta: "更新于本学年" }
    ]
  },
  "辐射类": {
    docs: [
      { title: "辐射实验室通行管理要求", desc: "介绍放射源台账、巡检、剂量监测要求。", meta: "学习时长 40 分钟" },
      { title: "个人剂量计佩戴说明", desc: "结合典型误区做重点提醒。", meta: "图文资料" }
    ],
    banks: [
      { title: "辐射类专项题库", desc: "含基础规则和事故处置题目。", meta: "共 96 题" }
    ]
  },
  "机电类": {
    docs: [
      { title: "机加设备断电挂牌操作卡", desc: "用于加工中心、车床、电控系统实验。", meta: "学习时长 32 分钟" },
      { title: "高压电实验防护须知", desc: "覆盖授权上机、隔离防护和应急停机。", meta: "图文资料" }
    ],
    banks: [
      { title: "机电类安全练习库", desc: "聚焦电气、动设备、机械夹伤风险。", meta: "共 126 题" }
    ]
  },
  "基础类": {
    docs: [
      { title: "实验室通用行为红线", desc: "适合本科生、教职工和跨专业学习。", meta: "学习时长 20 分钟" },
      { title: "个体防护用品正确佩戴", desc: "围绕眼面防护、实验服、手套展开。", meta: "图文资料" }
    ],
    banks: [
      { title: "基础类通识题库", desc: "适合应知应会考试与入学考试前练习。", meta: "共 140 题" }
    ]
  },
  "安全操作及应急处置": {
    docs: [
      { title: "事故上报与现场处置流程图", desc: "适合实验室负责人和一线师生快速参考。", meta: "流程卡" },
      { title: "灭火器与洗眼器使用演示", desc: "结合视频和图解说明使用步骤。", meta: "学习时长 26 分钟" }
    ],
    banks: [
      { title: "应急处置专项练习", desc: "共 90 题，覆盖火灾、中毒、泄漏、暴露。", meta: "专项练习" }
    ]
  },
  "科研伦理安全": {
    docs: [
      { title: "科研伦理底线与数据安全", desc: "适用于全员年度学习。", meta: "学习时长 35 分钟" },
      { title: "科研活动合规与保密要求", desc: "聚焦项目资料、样本、数据外发风险。", meta: "图文资料" }
    ],
    banks: [
      { title: "伦理安全题库", desc: "共 60 题，适合年度通识测验。", meta: "最近更新 2026-03" }
    ]
  }
};

const videoCatalog = {
  "化学类": [
    { title: "危化品存储全流程演示", duration: "18:24", desc: "从入库到废弃流转的标准示范。", meta: "1.2k 次学习", color: "linear-gradient(135deg, #6078ea, #17ead9)" },
    { title: "通风橱规范操作", duration: "12:30", desc: "面向化学类实验基本动作训练。", meta: "834 次学习", color: "linear-gradient(135deg, #3366ff, #88ccff)" },
    { title: "腐蚀品应急处置", duration: "09:42", desc: "典型场景复现与错误动作警示。", meta: "902 次学习", color: "linear-gradient(135deg, #4b6cb7, #182848)" },
    { title: "实验废液标签填写", duration: "07:18", desc: "适合本科生和研一快速上手。", meta: "695 次学习", color: "linear-gradient(135deg, #30cfd0, #330867)" },
    { title: "危险源辨识案例", duration: "15:10", desc: "结合真实实验过程讲解。", meta: "1.1k 次学习", color: "linear-gradient(135deg, #89f7fe, #66a6ff)" }
  ],
  "生物类": [
    { title: "超净台标准操作", duration: "13:20", desc: "以细胞实验为主线展示规范动作。", meta: "711 次学习", color: "linear-gradient(135deg, #00c6ff, #0072ff)" },
    { title: "样本运输与消杀", duration: "11:05", desc: "强调链路合规和暴露后处置。", meta: "530 次学习", color: "linear-gradient(135deg, #43e97b, #38f9d7)" },
    { title: "生物废弃物封装示范", duration: "08:54", desc: "覆盖黄袋封装与暂存交接。", meta: "483 次学习", color: "linear-gradient(135deg, #11998e, #38ef7d)" }
  ],
  "辐射类": [
    { title: "辐射剂量监测基础", duration: "10:18", desc: "剂量计使用与记录要求。", meta: "294 次学习", color: "linear-gradient(135deg, #f7971e, #ffd200)" },
    { title: "辐照实验区巡检", duration: "14:40", desc: "高风险实验区日常巡检示范。", meta: "211 次学习", color: "linear-gradient(135deg, #f857a6, #ff5858)" }
  ],
  "机电类": [
    { title: "加工设备上机前检查", duration: "16:25", desc: "聚焦断电挂牌、工装确认。", meta: "645 次学习", color: "linear-gradient(135deg, #5f72bd, #9b23ea)" },
    { title: "高压电实验安全边界", duration: "12:11", desc: "讲清授权、隔离、观察员机制。", meta: "427 次学习", color: "linear-gradient(135deg, #355c7d, #6c5b7b)" }
  ],
  "其他类": [
    { title: "实验室火灾逃生案例", duration: "08:45", desc: "适合全员年度学习。", meta: "1.9k 次学习", color: "linear-gradient(135deg, #ff9a9e, #fad0c4)" },
    { title: "科研伦理与数据保密", duration: "17:50", desc: "围绕论文、项目、样本与数据。", meta: "1.1k 次学习", color: "linear-gradient(135deg, #a18cd1, #fbc2eb)" },
    { title: "实验室负责人安全职责", duration: "19:12", desc: "面向教职工和管理员。", meta: "820 次学习", color: "linear-gradient(135deg, #fad961, #f76b1c)" }
  ]
};

const statsData = {
  year: "2026-2027 学年",
  examOverview: {
    undergrad: [
      { college: "资源环境学院", should: 420, pass: 356, fail: 28, absent: 36 },
      { college: "动物科技学院", should: 388, pass: 331, fail: 24, absent: 33 },
      { college: "信息工程学院", should: 462, pass: 401, fail: 21, absent: 40 },
      { college: "机械与电子工程学院", should: 315, pass: 268, fail: 19, absent: 28 },
      { college: "林学院", should: 276, pass: 229, fail: 17, absent: 30 }
    ],
    graduate: [
      { college: "资源环境学院", should: 206, pass: 168, fail: 14, absent: 24 },
      { college: "动物科技学院", should: 184, pass: 151, fail: 11, absent: 22 },
      { college: "信息工程学院", should: 118, pass: 95, fail: 8, absent: 15 },
      { college: "机械与电子工程学院", should: 146, pass: 121, fail: 9, absent: 16 },
      { college: "林学院", should: 132, pass: 109, fail: 7, absent: 16 }
    ]
  },
  labLevelSummary: [
    { level: "一级", count: 182, students: 524 },
    { level: "二级", count: 126, students: 411 },
    { level: "三级", count: 84, students: 289 },
    { level: "四级", count: 31, students: 108 }
  ],
  labStudentRows: [
    { student: "刘子衡", identity: "研究生", college: "资源环境学院", lab: "植物养分实验室（A201）", level: "三级", status: "审批通过" },
    { student: "宋若宁", identity: "研究生", college: "动物科技学院", lab: "细胞培养实验室（B305）", level: "二级", status: "已考试通过" },
    { student: "赵晴川", identity: "本科生", college: "信息工程学院", lab: "无需进入实验室", level: "-", status: "应知应会学习中" },
    { student: "周承宇", identity: "研究生", college: "机械与电子工程学院", lab: "电气控制实验室（C110）", level: "一级", status: "待考试" },
    { student: "方以宁", identity: "研究生", college: "林学院", lab: "辐照分析实验室（D402）", level: "四级", status: "审批中" }
  ],
  labRosterRows: [
    { college: "资源环境学院", lab: "植物养分实验室（A201）", level: "三级", category: "化学类", manager: "王*二", students: 42 },
    { college: "动物科技学院", lab: "细胞培养实验室（B305）", level: "二级", category: "生物类", manager: "李*华", students: 35 },
    { college: "机械与电子工程学院", lab: "电气控制实验室（C110）", level: "一级", category: "机电类", manager: "周*明", students: 27 },
    { college: "林学院", lab: "辐照分析实验室（D402）", level: "四级", category: "辐射类", manager: "陈*宁", students: 18 }
  ],
  averageStudyHours: [
    { college: "资源环境学院", nonFresh: 5.3, tutor: 4.6, userCount: 236 },
    { college: "动物科技学院", nonFresh: 5.1, tutor: 4.4, userCount: 208 },
    { college: "信息工程学院", nonFresh: 4.7, tutor: 4.1, userCount: 244 },
    { college: "机械与电子工程学院", nonFresh: 4.9, tutor: 4.3, userCount: 191 },
    { college: "林学院", nonFresh: 4.4, tutor: 4.0, userCount: 166 }
  ],
  collegeDetailRows: [
    { name: "张哲", college: "资源环境学院", role: "非新生本科生", hours: 5.5, exam: "应知应会", status: "已完成" },
    { name: "李宛青", college: "动物科技学院", role: "导师", hours: 4.8, exam: "应知应会", status: "已完成" },
    { name: "王承安", college: "信息工程学院", role: "非新生本科生", hours: 4.2, exam: "应知应会", status: "学习中" },
    { name: "陈若希", college: "机械与电子工程学院", role: "导师", hours: 4.5, exam: "应知应会", status: "已完成" },
    { name: "周以棠", college: "林学院", role: "非新生本科生", hours: 3.9, exam: "应知应会", status: "未达标" }
  ]
};

const state = {
  activePage: "workbench",
  activeRole: "newGraduate",
  activeResourceTab: "化学类",
  activeVideoTab: "化学类",
  videoSearch: "",
  videoPage: 1,
  modalOpen: true,
  labSearch: "",
  selectedLabId: "",
  noLabMode: false,
  noticeChecked: false,
  pendingApproval: false,
  statsExamType: "undergrad"
};

const chartRegistry = [];

function cloneProfile(profile) {
  return JSON.parse(JSON.stringify(profile));
}

const roleState = Object.fromEntries(
  Object.entries(roleProfiles).map(([key, value]) => [key, cloneProfile(value)])
);

function getCurrentRole() {
  return roleState[state.activeRole];
}

function hoursPercent(role) {
  return Math.min(100, Math.round((role.completedHours / role.requiredHours) * 100));
}

function levelClass(level) {
  return `level-${Math.max(1, Math.min(4, level || 1))}`;
}

function examStatusClass(status) {
  if (status === "success") return "success";
  if (status === "pending") return "pending";
  return "locked";
}

function resolveResourceTab(role) {
  if (role.type === "研究生" && role.lab && role.lab.category) {
    return role.lab.category;
  }
  if (role.type === "教职工" || role.type === "本科生" || role.labChoiceMode === "no_lab") {
    return "基础类";
  }
  return state.activeResourceTab;
}

function filteredLabs() {
  const keyword = state.labSearch.trim();
  if (!keyword) return [];
  return labCatalog.filter((lab) => {
    const raw = `${lab.college}${lab.name}${lab.room}${lab.building}${lab.category}`;
    return raw.includes(keyword);
  });
}

function visibleVideos() {
  const list = videoCatalog[state.activeVideoTab] || [];
  const keyword = state.videoSearch.trim();
  const filtered = keyword
    ? list.filter((item) => `${item.title}${item.desc}`.includes(keyword))
    : list;
  const pageSize = 4;
  const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize));
  state.videoPage = Math.min(state.videoPage, totalPages);
  const start = (state.videoPage - 1) * pageSize;
  return {
    items: filtered.slice(start, start + pageSize),
    totalPages,
    total: filtered.length
  };
}

function setRole(roleKey) {
  state.activeRole = roleKey;
  const role = getCurrentRole();
  state.activeResourceTab = resolveResourceTab(role);
  state.activeVideoTab = state.activeVideoTab in videoCatalog ? state.activeVideoTab : "化学类";
  state.videoSearch = "";
  state.videoPage = 1;
  state.labSearch = "";
  state.selectedLabId = "";
  state.noLabMode = false;
  state.noticeChecked = false;
  state.pendingApproval = role.bindingStatus === "pending";
  state.modalOpen = role.key === "newGraduate" && role.bindingStatus === "unbound";
  render();
}

function setPage(pageKey) {
  state.activePage = pageKey;
  if (pageKey === "stats") {
    state.modalOpen = false;
  } else {
    const role = getCurrentRole();
    state.modalOpen = role.key === "newGraduate" && role.bindingStatus === "unbound";
  }
  render();
}

function selectLab(labId) {
  state.selectedLabId = labId;
  state.noLabMode = false;
  render();
}

function toggleNoLabMode() {
  state.noLabMode = !state.noLabMode;
  if (state.noLabMode) {
    state.selectedLabId = "";
  }
  render();
}

function closeModal() {
  state.modalOpen = false;
  render();
}

function submitBinding() {
  if (!state.noticeChecked) {
    window.alert("请先勾选《新生绑定实验室须知及责任说明》。");
    return;
  }

  const role = getCurrentRole();
  if (!state.noLabMode && !state.selectedLabId) {
    window.alert("请选择实验室，或选择“无需进入实验室”。");
    return;
  }

  if (state.noLabMode) {
    role.bindingStatus = "approved";
    role.labChoiceMode = "no_lab";
    role.lab = null;
    role.requiredHours = 4;
    role.completedHours = Math.min(role.completedHours, 4);
    role.examStatus = role.completedHours >= 4 ? "应知应会考试可参加" : "应知应会考试待开放";
    role.resourceSummary = {
      title: "应知应会知识资源",
      desc: "已选择无需进入实验室，当前按通识学习 4 学时与应知应会考试路径执行。"
    };
    role.examCard = {
      title: "应知应会考试",
      status: role.completedHours >= 4 ? "可参加" : "待解锁",
      desc: "无需进入实验室的研究生新生按 4 学时通识学习后参加应知应会考试。",
      points: [
        { title: "绑定结果", detail: "无需进入实验室", status: "success" },
        { title: "学时完成", detail: `${role.completedHours} / 4 学时`, status: role.completedHours >= 4 ? "success" : "pending" },
        { title: "考试开放", detail: role.completedHours >= 4 ? "已开放" : "达标后开放", status: role.completedHours >= 4 ? "success" : "locked" }
      ]
    };
  } else {
    const lab = labCatalog.find((item) => item.id === state.selectedLabId);
    role.bindingStatus = "pending";
    role.labChoiceMode = "lab";
    role.lab = {
      title: `${lab.name}（${lab.room}）`,
      manager: lab.manager,
      level: lab.level,
      category: lab.category,
      type: lab.type
    };
    role.requiredHours = 24;
    role.completedHours = Math.max(role.completedHours, 8);
    role.examStatus = "实验室负责人审批中";
    role.resourceSummary = {
      title: `${lab.category}分级资源`,
      desc: "已提交绑定申请，审批通过后按实验室分级分类匹配学习资料和考试内容。"
    };
    role.examCard = {
      title: "分级考试",
      status: "审批中",
      desc: "已提交实验室绑定申请。系统支持 7 天未处理自动通过，审批后继续完成 24 学时。",
      points: [
        { title: "绑定结果", detail: "待负责人审批", status: "pending" },
        { title: "学时完成", detail: `${role.completedHours} / 24 学时`, status: "pending" },
        { title: "考试开放", detail: "审批通过且学时达标后开放", status: "locked" }
      ]
    };
    state.pendingApproval = true;
  }

  state.modalOpen = false;
  state.activeResourceTab = resolveResourceTab(role);
  render();
}

function fastApproveBinding() {
  const role = getCurrentRole();
  if (role.bindingStatus !== "pending") return;
  role.bindingStatus = "approved";
  role.examStatus = "分级考试待开放";
  role.examCard.status = "学习中";
  role.examCard.desc = "实验室绑定已通过，请继续完成 24 学时后参加分级考试。";
  role.examCard.points[0] = { title: "绑定结果", detail: "负责人已通过", status: "success" };
  state.pendingApproval = false;
  render();
}

function autoApproveBinding() {
  const role = getCurrentRole();
  if (role.bindingStatus !== "pending") return;
  role.bindingStatus = "approved";
  role.examStatus = "分级考试待开放";
  role.examCard.status = "学习中";
  role.examCard.desc = "已触发 7 天自动审批演示，请继续完成 24 学时后参加分级考试。";
  role.examCard.points[0] = { title: "绑定结果", detail: "7 天未处理自动通过", status: "success" };
  state.pendingApproval = false;
  render();
}

function renderSidebar() {
  return `
    <aside class="sidebar">
      <div class="brand">
        <div class="brand__seal"></div>
        <div class="brand__title">实验室安全智慧化管控系统</div>
      </div>
      <div class="nav-group">
        <div class="nav-group__title">导航</div>
        <div class="nav-item ${state.activePage === "workbench" ? "is-active" : ""}" data-page="workbench"><div class="nav-item__dot"></div><span>工作台</span></div>
        <div class="nav-item ${state.activePage === "stats" ? "is-active" : ""}" data-page="stats"><div class="nav-item__dot"></div><span>数据统计</span></div>
      </div>
      <div class="nav-group">
        <div class="nav-group__title">模块</div>
        <div class="nav-item"><div class="nav-item__dot"></div><span>安全教育与考试</span></div>
        <div class="nav-item"><div class="nav-item__dot"></div><span>基础信息管理</span></div>
        <div class="nav-item"><div class="nav-item__dot"></div><span>配置项</span></div>
      </div>
    </aside>
  `;
}

function renderTopbar(role) {
  const pageTitle = state.activePage === "stats" ? "数据统计" : "工作台";
  return `
    <div class="topbar">
      <div class="crumbs">
        <span>首页</span>
        <span>/</span>
        <span>后台首页</span>
        <span>/</span>
        <strong>${pageTitle}</strong>
      </div>
      <div class="topbar__right">
        <a class="system-link" href="javascript:void(0)">系统首页</a>
        <div class="user-badge">
          <span>欢迎您，${role.name}</span>
          <div class="avatar"></div>
        </div>
      </div>
    </div>
  `;
}

function renderToolbar(role) {
  if (state.activePage === "stats") {
    return `
      <div class="page-tag">统计分析 Demo</div>
      <div class="toolbar">
        <div class="toolbar__title">
          <h1>安全教育与考试系统数据统计</h1>
          <p>基于报表需求文档生成 mock 数据统计页面，包含考试统计、实验室与人员匹配、应知应会学习时长分析。</p>
        </div>
        <div class="role-switcher">
          <span class="role-switcher__label">统计对象</span>
          <button class="role-button ${state.statsExamType === "undergrad" ? "is-active" : ""}" data-exam-type="undergrad">本科生考试</button>
          <button class="role-button ${state.statsExamType === "graduate" ? "is-active" : ""}" data-exam-type="graduate">研究生考试</button>
        </div>
      </div>
    `;
  }

  return `
    <div class="page-tag">工作台 Demo</div>
    <div class="toolbar">
      <div class="toolbar__title">
        <h1>安全教育与考试系统工作台</h1>
        <p>${role.subtitle}</p>
      </div>
      <div class="role-switcher">
        <span class="role-switcher__label">角色切换</span>
        ${Object.values(roleProfiles).map((item) => `
          <button class="role-button ${item.key === state.activeRole ? "is-active" : ""}" data-role="${item.key}">
            ${item.label}
          </button>
        `).join("")}
      </div>
    </div>
  `;
}

function renderStatsPage() {
  const examRows = statsData.examOverview[state.statsExamType];
  const totals = examRows.reduce((acc, item) => {
    acc.should += item.should;
    acc.pass += item.pass;
    acc.fail += item.fail;
    acc.absent += item.absent;
    return acc;
  }, { should: 0, pass: 0, fail: 0, absent: 0 });
  const passRate = Math.round((totals.pass / totals.should) * 100);
  const avgStudy = (statsData.averageStudyHours.reduce((sum, item) => sum + item.nonFresh, 0) / statsData.averageStudyHours.length).toFixed(1);
  const matchedStudents = statsData.labLevelSummary.reduce((sum, item) => sum + item.students, 0);

  return `
    <div class="layout-stack">
      <section class="panel">
        <div class="panel__head">
          <div class="panel__title"><h2>统计概览</h2></div>
          <div class="panel__desc">${statsData.year} · 研究生与本科生考试情况分开统计</div>
        </div>
        <div class="stats-kpi-grid">
          <div class="stats-kpi-card">
            <span>应考人数</span>
            <strong>${totals.should}</strong>
            <em>${state.statsExamType === "undergrad" ? "本科生" : "研究生"}口径</em>
          </div>
          <div class="stats-kpi-card">
            <span>考试通过率</span>
            <strong>${passRate}%</strong>
            <em>通过 ${totals.pass} 人</em>
          </div>
          <div class="stats-kpi-card">
            <span>实验室匹配学生数</span>
            <strong>${matchedStudents}</strong>
            <em>支持按分级/实验室导出</em>
          </div>
          <div class="stats-kpi-card">
            <span>应知应会平均学时</span>
            <strong>${avgStudy}h</strong>
            <em>非新生/导师口径</em>
          </div>
        </div>
      </section>

      <section class="stats-chart-grid">
        <section class="panel">
          <div class="panel__head">
            <div class="panel__title"><h2>考试情况图表统计</h2></div>
            <a class="panel__link" href="javascript:void(0)">导出全校各学院总表</a>
          </div>
          <div class="stats-chart-layout">
            <div id="exam-bar-chart" class="chart-box chart-box--lg"></div>
            <div id="exam-pie-chart" class="chart-box"></div>
          </div>
        </section>

        <section class="panel">
          <div class="panel__head">
            <div class="panel__title"><h2>实验室与人员匹配</h2></div>
            <div class="panel__desc">根据实验室分级和实验室导出学生名单和人数</div>
          </div>
          <div class="stats-chart-layout">
            <div id="lab-level-chart" class="chart-box"></div>
            <div class="stats-export-card">
              <h3>导出入口</h3>
              <div class="stats-action-list">
                <button class="ghost-button">根据分级导出人数</button>
                <button class="ghost-button">根据分级导出学生名单</button>
                <button class="ghost-button">根据实验室导出名单</button>
              </div>
              <p>统计页 mock 出导出入口和明细表结构，便于后续接正式接口。</p>
            </div>
          </div>
        </section>
      </section>

      <section class="panel">
        <div class="panel__head">
          <div class="panel__title"><h2>考试情况分类</h2></div>
          <div class="panel__desc">字段包含应考人数、通过人数、未通过人数、未考人数</div>
        </div>
        <div class="table-wrap">
          <table class="data-table">
            <thead>
              <tr>
                <th>学院</th>
                <th>应考人数</th>
                <th>通过人数</th>
                <th>未通过人数</th>
                <th>未考人数</th>
                <th>通过率</th>
              </tr>
            </thead>
            <tbody>
              ${examRows.map((item) => `
                <tr>
                  <td>${item.college}</td>
                  <td>${item.should}</td>
                  <td>${item.pass}</td>
                  <td>${item.fail}</td>
                  <td>${item.absent}</td>
                  <td>${Math.round(item.pass / item.should * 100)}%</td>
                </tr>
              `).join("")}
            </tbody>
          </table>
        </div>
      </section>

      <section class="stats-chart-grid">
        <section class="panel">
          <div class="panel__head">
            <div class="panel__title"><h2>应知应会学习时长</h2></div>
            <div class="panel__desc">体现各学院非新生 / 导师应知应会平均学习时长</div>
          </div>
          <div class="stats-chart-layout">
            <div id="study-hours-chart" class="chart-box chart-box--lg"></div>
          </div>
        </section>

        <section class="panel">
          <div class="panel__head">
            <div class="panel__title"><h2>学院数据明细</h2></div>
            <a class="panel__link" href="javascript:void(0)">导出学院明细</a>
          </div>
          <div class="table-wrap">
            <table class="data-table data-table--compact">
              <thead>
                <tr>
                  <th>姓名</th>
                  <th>学院</th>
                  <th>身份</th>
                  <th>学习时长</th>
                  <th>考试类型</th>
                  <th>状态</th>
                </tr>
              </thead>
              <tbody>
                ${statsData.collegeDetailRows.map((item) => `
                  <tr>
                    <td>${item.name}</td>
                    <td>${item.college}</td>
                    <td>${item.role}</td>
                    <td>${item.hours}h</td>
                    <td>${item.exam}</td>
                    <td>${item.status}</td>
                  </tr>
                `).join("")}
              </tbody>
            </table>
          </div>
        </section>
      </section>

      <section class="panel">
        <div class="panel__head">
          <div class="panel__title"><h2>实验室 / 学生名单明细</h2></div>
          <div class="panel__desc">覆盖根据分级导出学生名单、根据实验室导出名单两类明细结构</div>
        </div>
        <div class="stats-double-table">
          <div class="table-wrap">
            <table class="data-table data-table--compact">
              <thead>
                <tr>
                  <th>学生</th>
                  <th>身份</th>
                  <th>学院</th>
                  <th>实验室</th>
                  <th>分级</th>
                  <th>状态</th>
                </tr>
              </thead>
              <tbody>
                ${statsData.labStudentRows.map((item) => `
                  <tr>
                    <td>${item.student}</td>
                    <td>${item.identity}</td>
                    <td>${item.college}</td>
                    <td>${item.lab}</td>
                    <td>${item.level}</td>
                    <td>${item.status}</td>
                  </tr>
                `).join("")}
              </tbody>
            </table>
          </div>
          <div class="table-wrap">
            <table class="data-table data-table--compact">
              <thead>
                <tr>
                  <th>学院</th>
                  <th>实验室</th>
                  <th>分级</th>
                  <th>分类</th>
                  <th>负责人</th>
                  <th>人数</th>
                </tr>
              </thead>
              <tbody>
                ${statsData.labRosterRows.map((item) => `
                  <tr>
                    <td>${item.college}</td>
                    <td>${item.lab}</td>
                    <td>${item.level}</td>
                    <td>${item.category}</td>
                    <td>${item.manager}</td>
                    <td>${item.students}</td>
                  </tr>
                `).join("")}
              </tbody>
            </table>
          </div>
        </div>
      </section>
    </div>
  `;
}

function renderUserCard(role) {
  const percent = hoursPercent(role);
  const bindingText = role.bindingStatus === "unbound"
    ? "待绑定"
    : role.bindingStatus === "pending"
      ? "审批中"
      : role.labChoiceMode === "no_lab"
        ? "无需进入实验室"
        : "已绑定";
  const resourceTab = resolveResourceTab(role);

  return `
    <section class="panel">
      <div class="panel__head">
        <div class="panel__title"><h2>用户信息卡</h2></div>
        <div class="panel__desc">当前推荐资料类型：${resourceTab}</div>
      </div>
      <div class="user-card">
        <div class="user-card__summary">
          <div class="meta-box">
            <div class="meta-grid">
              <div class="meta-item"><span>用户姓名</span><strong>${role.name}</strong></div>
              <div class="meta-item"><span>学工号</span><strong>${role.code}</strong></div>
              <div class="meta-item"><span>用户类型</span><strong>${role.type}</strong></div>
              <div class="meta-item"><span>所属单位</span><strong>${role.org}</strong></div>
              <div class="meta-item"><span>实验室信息</span><strong>${role.lab ? role.lab.title : "暂无绑定实验室"}</strong></div>
              <div class="meta-item"><span>负责人</span><strong>${role.lab ? role.lab.manager : "不适用"}</strong></div>
            </div>
            <div class="summary-tip">
              绑定状态：${bindingText}
              ${role.lab ? `，实验室类型：${role.lab.type}` : "，新入学研究生需先完成绑定。"}
            </div>
          </div>
          <div class="status-box">
            <div class="tag-row">
              <span class="mini-tag normal">${role.term}</span>
              ${role.lab ? `<span class="mini-tag ${levelClass(role.lab.level)}">教育部分级 ${role.lab.level} 级</span>` : ""}
              ${role.lab ? `<span class="mini-tag normal">${role.lab.category}</span>` : ""}
            </div>
            <div class="progress">
              <div class="progress__head">
                <span>年度学时进度</span>
                <strong>${role.completedHours} / ${role.requiredHours} 学时</strong>
              </div>
              <div class="bar"><span style="width:${percent}%"></span></div>
            </div>
            <div class="status-kpi">
              <div class="kpi-box">
                <span>完成度</span>
                <strong>${percent}<em>%</em></strong>
              </div>
              <div class="kpi-box">
                <span>目标考试</span>
                <strong style="font-size:18px">${role.examCard.title}</strong>
              </div>
            </div>
          </div>
          <div class="status-box">
            <div class="panel__desc">当前学年任务状态</div>
            <div class="status-list">
              <div class="status-item">
                <span>考试状态</span>
                <span class="status-chip ${role.examCard.status === "已通过" ? "success" : role.bindingStatus === "pending" ? "pending" : role.bindingStatus === "unbound" || percent < 100 ? "locked" : "success"}">${role.examStatus}</span>
              </div>
              <div class="status-item">
                <span>证书状态</span>
                <span class="status-chip ${role.certificateTag}">${role.certificateStatus}</span>
              </div>
              <div class="status-item">
                <span>当前资料路径</span>
                <span>${role.resourceSummary.title}</span>
              </div>
            </div>
            ${role.key === "newGraduate" && role.bindingStatus === "unbound" ? `
              <div class="summary-tip">首次进入的研究生需完成实验室绑定。你可以重新打开弹窗演示完整流程。</div>
            ` : ""}
          </div>
        </div>
      </div>
    </section>
  `;
}

function renderFeatureCards(role) {
  return `
    <section class="panel">
      <div class="panel__head">
        <div class="panel__title"><h2>工作台功能卡片区</h2></div>
        <div class="panel__desc">五个板块保持等宽等高，并随角色自动切换业务内容</div>
      </div>
      <div class="feature-grid">
        <article class="feature-card">
          <h3>学年数据统计</h3>
          <p>按学年统计当前用户历年考试通过情况与成绩，便于查看年度履约轨迹。</p>
          <div class="record-list">
            ${role.yearlyRecords.map((item) => `
              <div class="record-item">
                <strong>${item.year} 学年</strong>
                <span>${item.status} · ${item.score}</span>
              </div>
            `).join("")}
          </div>
        </article>
        <article class="feature-card">
          <h3>学习任务</h3>
          <p>展示当前用户需完成的学习任务和进度，卡片信息直接映射待办状态。</p>
          <div class="task-list">
            ${role.tasks.map((item) => `
              <div class="task-item">
                <strong>${item.title}</strong>
                <span>${item.progress} · ${item.note}</span>
              </div>
            `).join("")}
          </div>
        </article>
        <article class="feature-card">
          <h3>资料类型</h3>
          <p>${role.resourceSummary.desc}</p>
          <div class="resource-list">
            <div class="resource-item">
              <strong>${role.resourceSummary.title}</strong>
              <span>${role.lab ? `根据实验室 ${role.lab.category} 分类推荐` : "默认推荐应知应会通识资源"}</span>
            </div>
            <div class="resource-item">
              <strong>进入详情页</strong>
              <span>可在资源区点击具体资料模拟进入详情。</span>
            </div>
          </div>
        </article>
        <article class="feature-card">
          <h3>模拟练习</h3>
          <p>展示刷题进度和正确率，适合应知应会考试、分级考试前自检。</p>
          <div class="meter-box">
            <strong>${role.practice.done} / ${role.practice.total}</strong>
            <span>已完成题目数 / 题库总数</span>
          </div>
          <div class="meter-box">
            <strong>${role.practice.correctRate}</strong>
            <span>当前模拟练习正确率</span>
          </div>
        </article>
        <article class="feature-card">
          <h3>${role.examCard.title}</h3>
          <p>${role.examCard.desc}</p>
          <div class="exam-points">
            ${role.examCard.points.map((point) => `
              <div class="exam-point">
                <strong>${point.title}</strong>
                <span>${point.detail}</span>
              </div>
            `).join("")}
          </div>
        </article>
      </div>
    </section>
  `;
}

function renderResourceSection(role) {
  const currentTab = state.activeResourceTab;
  const data = resourceCatalog[currentTab] || { docs: [], banks: [] };
  return `
    <section class="panel">
      <div class="panel__head">
        <div class="panel__title"><h2>实验室安全素养资源区</h2></div>
        <a class="panel__link" href="javascript:void(0)">查看全部资源</a>
      </div>
      <div class="tabs">
        ${Object.keys(resourceCatalog).map((tab) => `
          <button class="tab ${tab === currentTab ? "is-active" : ""}" data-resource-tab="${tab}">${tab}</button>
        `).join("")}
      </div>
      <div class="resource-panel">
        <div class="resource-column">
          <div class="resource-column__head">
            <h3>资料</h3>
            <a class="panel__link" href="javascript:void(0)">查看更多</a>
          </div>
          ${data.docs.map((item) => `
            <div class="resource-card">
              <div class="resource-card__meta">
                <strong>${item.title}</strong>
                <p>${item.desc}</p>
                <p>${item.meta}</p>
              </div>
              <a class="resource-card__action" href="javascript:void(0)">进入详情</a>
            </div>
          `).join("")}
        </div>
        <div class="resource-column">
          <div class="resource-column__head">
            <h3>题库</h3>
            <a class="panel__link" href="javascript:void(0)">查看更多</a>
          </div>
          ${data.banks.map((item) => `
            <div class="resource-card">
              <div class="resource-card__meta">
                <strong>${item.title}</strong>
                <p>${item.desc}</p>
                <p>${item.meta}</p>
              </div>
              <a class="resource-card__action" href="javascript:void(0)">开始练习</a>
            </div>
          `).join("")}
        </div>
      </div>
    </section>
  `;
}

function renderVideoSection() {
  const videoData = visibleVideos();
  return `
    <section class="panel">
      <div class="panel__head">
        <div class="panel__title"><h2>视频卡片资源区</h2></div>
        <div class="panel__desc">支持分类切换、搜索与翻页，风格接近流媒体内容卡片</div>
      </div>
      <div class="video-toolbar">
        <div class="tabs" style="padding:0">
          ${Object.keys(videoCatalog).map((tab) => `
            <button class="tab ${tab === state.activeVideoTab ? "is-active" : ""}" data-video-tab="${tab}">${tab}</button>
          `).join("")}
        </div>
        <div class="search-box">
          <input id="video-search" type="text" placeholder="搜索视频标题或内容关键词" value="${state.videoSearch}">
        </div>
      </div>
      ${videoData.items.length ? `
        <div class="video-grid">
          ${videoData.items.map((item) => `
            <article class="video-card">
              <div class="video-cover" style="background:${item.color}">
                <span class="video-duration">${item.duration}</span>
              </div>
              <div class="video-body">
                <strong>${item.title}</strong>
                <p>${item.desc}</p>
                <div class="video-meta">
                  <span>${item.meta}</span>
                  <span>${state.activeVideoTab}</span>
                </div>
              </div>
            </article>
          `).join("")}
        </div>
        <div class="pager">
          <button ${state.videoPage <= 1 ? "disabled" : ""} data-page-action="prev">上一页</button>
          <button ${state.videoPage >= videoData.totalPages ? "disabled" : ""} data-page-action="next">下一页</button>
        </div>
      ` : `
        <div class="empty-state">
          <div class="empty-state__icon"></div>
          <div>未检索到匹配视频，请更换关键字或切换分类。</div>
        </div>
      `}
    </section>
  `;
}

function renderModal() {
  const labs = filteredLabs();
  const keyword = state.labSearch.trim();
  const selectedLab = labCatalog.find((item) => item.id === state.selectedLabId);
  if (!state.modalOpen) return "";
  return `
    <div class="modal-mask">
      <div class="modal">
        <div class="modal__head">
          <div>
            <h3>绑定实验室</h3>
            <p>新入学研究生首次进入系统需绑定实验室。可选择进入实验室，或选择“无需进入实验室”走通识考试路径。</p>
          </div>
          <button class="close-button" id="close-modal" aria-label="关闭">×</button>
        </div>
        <div class="modal__body">
          <div class="form-group">
            <label for="lab-search">搜索实验室名称 / 房号</label>
            <input class="input" id="lab-search" type="text" value="${state.labSearch}" placeholder="例如：植物养分实验室、A201、农科楼">
            ${!keyword ? `
              <div class="choice-card">
                <h4>检索提示</h4>
                <div class="foot-tip">默认不展示实验室列表，请先输入实验室名称、房号或楼栋关键词，再从检索结果中选择目标实验室。</div>
              </div>
            ` : labs.length ? `
              <div class="lab-list">
                ${labs.map((lab) => `
                  <button class="lab-option ${lab.id === state.selectedLabId ? "is-active" : ""}" data-lab-id="${lab.id}">
                    ${lab.college}-${lab.name}（${lab.room}）-${lab.building}
                  </button>
                `).join("")}
              </div>
            ` : `
              <div class="choice-card">
                <h4>未匹配到实验室</h4>
                <div class="foot-tip">请尝试输入更准确的实验室名称、房号或楼栋信息。</div>
              </div>
            `}
          </div>
          ${selectedLab ? `
            <div class="lab-result">
              <h4>实验室完整信息</h4>
              <div class="lab-grid">
                <div><span>实验室负责人</span><strong>${selectedLab.manager}</strong></div>
                <div><span>实验室分级</span><strong>教育部 ${selectedLab.level} 级</strong></div>
                <div><span>实验室分类</span><strong>${selectedLab.category}</strong></div>
                <div><span>实验室类型</span><strong>${selectedLab.type}</strong></div>
              </div>
            </div>
          ` : ""}
          <div class="choice-card">
            <h4>其他选择</h4>
            <label class="inline-check">
              <input type="checkbox" id="no-lab-mode" ${state.noLabMode ? "checked" : ""}>
              <span>我无需进入实验室，仅使用系统完成 4 学时学习和应知应会考试</span>
            </label>
          </div>
          <label class="inline-check">
            <input type="checkbox" id="notice-check" ${state.noticeChecked ? "checked" : ""}>
            <span>我已阅读并同意《新生绑定实验室须知及责任说明》，知悉需对绑定信息准确性负责。</span>
          </label>
        </div>
        <div class="modal__foot">
          <div class="foot-tip">审批规则演示：提交后由实验室负责人审批，7 天未处理可自动通过。</div>
          <div class="button-row">
            <button class="ghost-button" id="close-modal-secondary">稍后再说</button>
            <button class="primary-button" id="submit-binding">提交绑定</button>
          </div>
        </div>
      </div>
    </div>
  `;
}

function renderPendingActions(role) {
  if (!(role.key === "newGraduate" && role.bindingStatus === "pending")) return "";
  return `
    <section class="panel">
      <div class="panel__head">
        <div class="panel__title"><h2>绑定审批演示</h2></div>
        <div class="panel__desc">模拟实验室负责人审批与 7 天自动通过机制</div>
      </div>
      <div style="padding: 0 22px 22px; display:flex; gap:12px; flex-wrap:wrap;">
        <button class="primary-button" id="approve-now">模拟负责人通过</button>
        <button class="ghost-button" id="approve-auto">模拟 7 天自动通过</button>
        <button class="ghost-button" id="reopen-modal">重新编辑绑定</button>
      </div>
    </section>
  `;
}

function renderFloatingActions(role) {
  if (role.key !== "newGraduate") {
    return `
      <div style="display:flex; justify-content:flex-end;">
        <button class="ghost-button" id="open-binding-demo">查看研究生绑定弹窗演示</button>
      </div>
    `;
  }
  return `
    <div style="display:flex; justify-content:flex-end; gap:12px; flex-wrap:wrap;">
      ${role.bindingStatus === "unbound" ? `<button class="ghost-button" id="reopen-modal">打开绑定弹窗</button>` : ""}
      ${role.bindingStatus !== "unbound" ? `<button class="ghost-button" id="reset-role-state">重置为首次进入状态</button>` : ""}
    </div>
  `;
}

function render() {
  chartRegistry.splice(0).forEach((chart) => chart.dispose());
  const role = getCurrentRole();
  if (!state.activeResourceTab || !(state.activeResourceTab in resourceCatalog)) {
    state.activeResourceTab = resolveResourceTab(role);
  }

  document.getElementById("app").innerHTML = `
    <div class="shell">
      ${renderSidebar()}
      <main class="main">
        ${renderTopbar(role)}
        ${renderToolbar(role)}
        ${state.activePage === "stats" ? renderStatsPage() : `
          <div class="layout-stack">
            ${renderFloatingActions(role)}
            ${renderUserCard(role)}
            ${renderFeatureCards(role)}
            ${renderPendingActions(role)}
            ${renderResourceSection(role)}
            ${renderVideoSection()}
          </div>
        `}
      </main>
    </div>
    ${state.activePage === "workbench" ? renderModal() : ""}
  `;

  bindEvents();
  initCharts();
}

function bindEvents() {
  document.querySelectorAll("[data-page]").forEach((button) => {
    button.addEventListener("click", () => setPage(button.dataset.page));
  });

  document.querySelectorAll("[data-exam-type]").forEach((button) => {
    button.addEventListener("click", () => {
      state.statsExamType = button.dataset.examType;
      render();
    });
  });

  document.querySelectorAll("[data-role]").forEach((button) => {
    button.addEventListener("click", () => setRole(button.dataset.role));
  });

  document.querySelectorAll("[data-resource-tab]").forEach((button) => {
    button.addEventListener("click", () => {
      state.activeResourceTab = button.dataset.resourceTab;
      render();
    });
  });

  document.querySelectorAll("[data-video-tab]").forEach((button) => {
    button.addEventListener("click", () => {
      state.activeVideoTab = button.dataset.videoTab;
      state.videoPage = 1;
      render();
    });
  });

  const videoSearch = document.getElementById("video-search");
  if (videoSearch) {
    videoSearch.addEventListener("input", (event) => {
      state.videoSearch = event.target.value;
      state.videoPage = 1;
      render();
    });
  }

  document.querySelectorAll("[data-page-action]").forEach((button) => {
    button.addEventListener("click", () => {
      state.videoPage += button.dataset.pageAction === "prev" ? -1 : 1;
      render();
    });
  });

  const reopenModal = document.getElementById("reopen-modal");
  if (reopenModal) {
    reopenModal.addEventListener("click", () => {
      state.modalOpen = true;
      render();
    });
  }

  const resetRoleState = document.getElementById("reset-role-state");
  if (resetRoleState) {
    resetRoleState.addEventListener("click", () => {
      roleState.newGraduate = cloneProfile(roleProfiles.newGraduate);
      setRole("newGraduate");
    });
  }

  const openBindingDemo = document.getElementById("open-binding-demo");
  if (openBindingDemo) {
    openBindingDemo.addEventListener("click", () => {
      roleState.newGraduate = cloneProfile(roleProfiles.newGraduate);
      setRole("newGraduate");
      state.modalOpen = true;
      render();
    });
  }

  const approveNow = document.getElementById("approve-now");
  if (approveNow) {
    approveNow.addEventListener("click", fastApproveBinding);
  }

  const approveAuto = document.getElementById("approve-auto");
  if (approveAuto) {
    approveAuto.addEventListener("click", autoApproveBinding);
  }

  const closeModalBtn = document.getElementById("close-modal");
  if (closeModalBtn) closeModalBtn.addEventListener("click", closeModal);
  const closeModalSecondary = document.getElementById("close-modal-secondary");
  if (closeModalSecondary) closeModalSecondary.addEventListener("click", closeModal);

  const labSearch = document.getElementById("lab-search");
  if (labSearch) {
    labSearch.addEventListener("input", (event) => {
      state.labSearch = event.target.value;
      render();
    });
  }

  document.querySelectorAll("[data-lab-id]").forEach((button) => {
    button.addEventListener("click", () => selectLab(button.dataset.labId));
  });

  const noLabMode = document.getElementById("no-lab-mode");
  if (noLabMode) noLabMode.addEventListener("change", toggleNoLabMode);

  const noticeCheck = document.getElementById("notice-check");
  if (noticeCheck) {
    noticeCheck.addEventListener("change", (event) => {
      state.noticeChecked = event.target.checked;
    });
  }

  const submitBindingBtn = document.getElementById("submit-binding");
  if (submitBindingBtn) submitBindingBtn.addEventListener("click", submitBinding);
}

function initCharts() {
  if (state.activePage !== "stats" || typeof echarts === "undefined") return;

  const examRows = statsData.examOverview[state.statsExamType];
  const pieSource = examRows.reduce((acc, item) => {
    acc.pass += item.pass;
    acc.fail += item.fail;
    acc.absent += item.absent;
    return acc;
  }, { pass: 0, fail: 0, absent: 0 });

  const examBarDom = document.getElementById("exam-bar-chart");
  if (examBarDom) {
    const chart = echarts.init(examBarDom);
    chart.setOption({
      color: ["#5b95f7", "#36b37e", "#ffb020", "#e84d5b"],
      tooltip: { trigger: "axis" },
      legend: { top: 0, textStyle: { color: "#60708a" } },
      grid: { left: 48, right: 20, top: 48, bottom: 28 },
      xAxis: {
        type: "category",
        data: examRows.map((item) => item.college),
        axisLabel: { color: "#60708a", interval: 0, rotate: 12 }
      },
      yAxis: {
        type: "value",
        axisLabel: { color: "#60708a" },
        splitLine: { lineStyle: { color: "#edf2fa" } }
      },
      series: [
        { name: "应考人数", type: "bar", data: examRows.map((item) => item.should), barMaxWidth: 26 },
        { name: "通过人数", type: "bar", data: examRows.map((item) => item.pass), barMaxWidth: 26 },
        { name: "未通过人数", type: "bar", data: examRows.map((item) => item.fail), barMaxWidth: 26 },
        { name: "未考人数", type: "bar", data: examRows.map((item) => item.absent), barMaxWidth: 26 }
      ]
    });
    chartRegistry.push(chart);
  }

  const examPieDom = document.getElementById("exam-pie-chart");
  if (examPieDom) {
    const chart = echarts.init(examPieDom);
    chart.setOption({
      color: ["#36b37e", "#ffb020", "#e84d5b"],
      tooltip: { trigger: "item" },
      legend: { bottom: 0, textStyle: { color: "#60708a" } },
      series: [{
        type: "pie",
        radius: ["48%", "72%"],
        center: ["50%", "46%"],
        label: { color: "#60708a", formatter: "{b}\n{d}%" },
        data: [
          { name: "通过", value: pieSource.pass },
          { name: "未通过", value: pieSource.fail },
          { name: "未考", value: pieSource.absent }
        ]
      }]
    });
    chartRegistry.push(chart);
  }

  const labLevelDom = document.getElementById("lab-level-chart");
  if (labLevelDom) {
    const chart = echarts.init(labLevelDom);
    chart.setOption({
      color: ["#5b95f7"],
      tooltip: { trigger: "axis" },
      grid: { left: 40, right: 20, top: 24, bottom: 28 },
      xAxis: {
        type: "category",
        data: statsData.labLevelSummary.map((item) => item.level),
        axisLabel: { color: "#60708a" }
      },
      yAxis: {
        type: "value",
        axisLabel: { color: "#60708a" },
        splitLine: { lineStyle: { color: "#edf2fa" } }
      },
      series: [{
        name: "人数",
        type: "bar",
        data: statsData.labLevelSummary.map((item) => item.students),
        barMaxWidth: 36,
        itemStyle: { borderRadius: [10, 10, 0, 0] }
      }]
    });
    chartRegistry.push(chart);
  }

  const studyHoursDom = document.getElementById("study-hours-chart");
  if (studyHoursDom) {
    const chart = echarts.init(studyHoursDom);
    chart.setOption({
      color: ["#5b95f7", "#36b37e"],
      tooltip: { trigger: "axis" },
      legend: { top: 0, textStyle: { color: "#60708a" } },
      grid: { left: 48, right: 20, top: 48, bottom: 28 },
      xAxis: {
        type: "category",
        data: statsData.averageStudyHours.map((item) => item.college),
        axisLabel: { color: "#60708a", interval: 0, rotate: 12 }
      },
      yAxis: {
        type: "value",
        axisLabel: { color: "#60708a", formatter: "{value}h" },
        splitLine: { lineStyle: { color: "#edf2fa" } }
      },
      series: [
        {
          name: "非新生平均学习时长",
          type: "line",
          smooth: true,
          data: statsData.averageStudyHours.map((item) => item.nonFresh),
          symbolSize: 8
        },
        {
          name: "导师平均学习时长",
          type: "line",
          smooth: true,
          data: statsData.averageStudyHours.map((item) => item.tutor),
          symbolSize: 8
        }
      ]
    });
    chartRegistry.push(chart);
  }

  window.onresize = () => {
    chartRegistry.forEach((chart) => chart.resize());
  };
}

render();
