let currentUser = null;
let authToken = window.localStorage.getItem("keyissueToken") || "";
let customers = [];
let issues = [];
let inspections = [];
let adminConfig = null;
let activePage = "dashboard";
let activeStatus = "all";
let selectedIssueId = null;
let selectedCustomerId = null;
let dictionaries = {
  departments: ["光宸", "澜光", "蘭堂", "焕境"],
  customerSources: ["转介绍", "公司特殊关系", "标杆项目", "风险关注"],
  issueSources: ["线下巡检", "客户群反馈", "每日线上巡查", "客户主动反馈", "管理层转办", "监察部发现"],
  issueTypes: ["施工质量", "设计变更", "沟通响应", "材料交付", "客户满意度"],
  progressStatuses: ["正常", "延期"]
};

const pageTitles = {
  dashboard: "A+在建客户动态管理驾驶舱",
  customers: "A/A+客户库",
  inspections: "每日线上巡查",
  issues: "问题反馈池",
  audit: "监察核查",
  analysis: "问题分析",
  rules: "预警规则",
  admin: "系统后台"
};

const pageTitle = document.querySelector("#pageTitle");
const searchInput = document.querySelector("#searchInput");
const tierFilter = document.querySelector("#tierFilter");
const departmentFilter = document.querySelector("#departmentFilter");
const statusButtons = document.querySelectorAll("[data-status]");
const drawer = document.querySelector("#detailDrawer");
const customerDrawer = document.querySelector("#customerDrawer");
const drawerBackdrop = document.querySelector("#drawerBackdrop");
const modalBackdrop = document.querySelector("#modalBackdrop");
const toast = document.querySelector("#toast");
const loginScreen = document.querySelector("#loginScreen");
const appShell = document.querySelector("#appShell");
const currentUserName = document.querySelector("#currentUserName");
const currentRoleName = document.querySelector("#currentRoleName");
const logoutBtn = document.querySelector("#logoutBtn");
const loginForm = document.querySelector("#loginForm");
const loginUsername = document.querySelector("#loginUsername");
const loginPassword = document.querySelector("#loginPassword");
const loginMessage = document.querySelector("#loginMessage");
const registerForm = document.querySelector("#registerForm");
const registerName = document.querySelector("#registerName");
const registerPhone = document.querySelector("#registerPhone");
const registerPassword = document.querySelector("#registerPassword");
const registerPasswordConfirm = document.querySelector("#registerPasswordConfirm");
const registerMessage = document.querySelector("#registerMessage");
const issueCustomerSearch = document.querySelector("#issueCustomerSearch");

function escapeHtml(value) {
  return String(value ?? "").replace(/[&<>"']/g, (char) => ({
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': "&quot;",
    "'": "&#039;"
  })[char]);
}

function showToast(message) {
  toast.textContent = message;
  toast.classList.add("show");
  window.clearTimeout(showToast.timer);
  showToast.timer = window.setTimeout(() => toast.classList.remove("show"), 2200);
}

async function apiRequest(path, options = {}) {
  const headers = {
    Accept: "application/json",
    ...(options.headers || {})
  };
  const request = { ...options, headers };

  if (authToken) headers.Authorization = `Bearer ${authToken}`;
  if (options.body && typeof options.body !== "string") {
    headers["Content-Type"] = "application/json";
    request.body = JSON.stringify(options.body);
  }

  const response = await fetch(path, request);
  const contentType = response.headers.get("content-type") || "";
  const payload = contentType.includes("application/json") ? await response.json() : await response.text();

  if (!response.ok) {
    const error = new Error(payload.message || `请求失败：${response.status}`);
    error.status = response.status;
    error.payload = payload;
    throw error;
  }
  return payload;
}

function hasPermission(permission) {
  if (!currentUser) return false;
  if (currentUser.permissions.includes("*")) return true;
  if (permission.startsWith("page:")) {
    return currentUser.pages.includes(permission.replace("page:", ""));
  }
  return currentUser.permissions.includes(permission);
}

function requirePermission(permission, actionName = "执行该操作") {
  if (hasPermission(permission)) return true;
  showToast(`当前登录人无权${actionName}`);
  return false;
}

function applyPermissions() {
  document.querySelectorAll("[data-page]").forEach((button) => {
    const allowed = hasPermission(`page:${button.dataset.page}`);
    button.disabled = !allowed;
    button.title = allowed ? "" : "后台未授权访问该页面";
  });

  document.querySelectorAll("[data-requires]").forEach((element) => {
    const allowed = hasPermission(element.dataset.requires);
    element.disabled = !allowed;
    element.classList.toggle("is-disabled", !allowed);
    element.title = allowed ? "" : "后台未授权执行该操作";
  });

  document.querySelectorAll(".permission-list div").forEach((item) => {
    const label = item.querySelector("strong")?.textContent || "";
    item.classList.toggle("is-current", currentUser && label === currentUser.roleName);
  });
}

function handleApiError(error) {
  if (error.status === 401) {
    clearSession();
    showToast("登录已失效，请重新登录。");
    return;
  }
  showToast(error.message || "操作失败，请稍后再试。");
}

function beginFormSubmit(form) {
  if (form.dataset.submitting === "true") return false;
  form.dataset.submitting = "true";
  form.querySelectorAll('button[type="submit"]').forEach((button) => {
    button.dataset.wasDisabled = button.disabled ? "true" : "false";
    button.disabled = true;
  });
  return true;
}

function endFormSubmit(form) {
  delete form.dataset.submitting;
  form.querySelectorAll('button[type="submit"]').forEach((button) => {
    button.disabled = button.dataset.wasDisabled === "true";
    delete button.dataset.wasDisabled;
  });
}

function getCustomer(id) {
  return customers.find((customer) => customer.id === id) || {
    id,
    name: "未匹配客户",
    tier: "-",
    source: "-",
    keyCustomerReason: "-",
    customerOwner: "-",
    address: "-",
    department: "-",
    designer: "-",
    manager: "-",
    stage: "-",
    startDate: "-",
    plannedFinishDate: "-",
    progressStatus: "正常",
    satisfaction: "-",
    inspectionStatus: "-",
    inspectionAt: "-",
    inspector: "-",
    inspectionSummary: "-"
  };
}

function statusClass(status) {
  if (status === "红色预警") return "risk";
  if (status === "橙色预警") return "orange";
  if (status === "蓝色关注") return "blue";
  if (status === "待核查") return "audit";
  if (status === "已处理") return "closed";
  return "normal";
}

function inspectionClass(status) {
  if (status === "异常") return "risk";
  if (status === "未巡查" || status === "-" || !status) return "orange";
  return "closed";
}

function inspectionFlag(status) {
  return status === "未巡查" || status === "-" || !status ? "未巡查" : "已巡查";
}

function inspectionFlagClass(status) {
  return status === "未巡查" || status === "-" || !status ? "orange" : "closed";
}

function progressClass(status) {
  return status === "延期" ? "risk" : "closed";
}

function cell(label, content) {
  return `<td data-label="${escapeHtml(label)}">${content}</td>`;
}

function dataTagBadge(item) {
  return item?.dataTag ? `<span class="data-tag">${escapeHtml(item.dataTag)}</span>` : "";
}

function dictionaryValues(key) {
  const values = dictionaries[key];
  return Array.isArray(values) && values.length ? values : [];
}

function optionList(values, selected = "") {
  return values.map((value) => {
    const text = String(value);
    const isSelected = selected === text ? " selected" : "";
    return `<option value="${escapeHtml(text)}"${isSelected}>${escapeHtml(text)}</option>`;
  }).join("");
}

function setSelectOptions(select, values, selectedValue) {
  if (!select) return;
  const currentValue = selectedValue ?? select.value;
  const safeValues = values.length ? values : [currentValue].filter(Boolean);
  select.innerHTML = optionList(safeValues, currentValue);
  if (safeValues.includes(currentValue)) select.value = currentValue;
}

function renderDictionaryOptions() {
  const departments = dictionaryValues("departments");
  const customerSources = dictionaryValues("customerSources");
  const issueSources = dictionaryValues("issueSources");
  const issueTypes = dictionaryValues("issueTypes");
  const progressStatuses = dictionaryValues("progressStatuses");
  const activeDepartment = departmentFilter.value || "all";

  departmentFilter.innerHTML = `<option value="all">全部部门</option>${optionList(departments, activeDepartment)}`;
  departmentFilter.value = departments.includes(activeDepartment) ? activeDepartment : "all";
  setSelectOptions(document.querySelector('#customerForm select[name="source"]'), customerSources);
  setSelectOptions(document.querySelector('#customerForm select[name="department"]'), departments);
  setSelectOptions(document.querySelector('#customerForm select[name="progressStatus"]'), progressStatuses);
  setSelectOptions(document.querySelector('#issueForm select[name="source"]'), issueSources);
  setSelectOptions(document.querySelector('#issueForm select[name="type"]'), issueTypes);
}

function customerCell(customer) {
  return `
    <button class="customer-cell-button" type="button" data-view-customer="${escapeHtml(customer.id)}">
      <strong>${escapeHtml(customer.name)}${dataTagBadge(customer)}</strong>
      <small>${escapeHtml(customer.address)}</small>
      <span class="customer-cell-meta">
        <span class="badge">${escapeHtml(customer.tier)}</span>
        <span class="status-badge ${progressClass(customer.progressStatus)}">${escapeHtml(customer.progressStatus || "正常")}</span>
        <span class="status-badge ${inspectionFlagClass(customer.inspectionStatus)}">${escapeHtml(inspectionFlag(customer.inspectionStatus))}</span>
      </span>
    </button>
  `;
}

function filteredIssues() {
  const keyword = searchInput.value.trim().toLowerCase();
  const tier = tierFilter.value;
  const department = departmentFilter.value;

  return issues.filter((issue) => {
    const customer = getCustomer(issue.customerId);
    const targetText = [
      customer.name,
      customer.address,
      customer.stage,
      customer.startDate,
      customer.plannedFinishDate,
      customer.progressStatus,
      issue.type,
      issue.source,
      issue.rootCause,
      issue.owner,
      issue.action
    ].join(" ").toLowerCase();
    const matchesKeyword = !keyword || targetText.includes(keyword);
    const matchesTier = tier === "all" || customer.tier === tier;
    const matchesDepartment = department === "all" || customer.department === department;
    const matchesStatus = activeStatus === "all" || issue.status === activeStatus;
    return matchesKeyword && matchesTier && matchesDepartment && matchesStatus;
  });
}

function countBy(list, getter) {
  return list.reduce((acc, item) => {
    const key = getter(item);
    acc[key] = (acc[key] || 0) + 1;
    return acc;
  }, {});
}

function renderKpis() {
  const visible = filteredIssues();
  const red = visible.filter((issue) => issue.status === "红色预警").length;
  const audit = visible.filter((issue) => issue.status === "待核查").length;
  const inspectionDone = customers.filter((customer) => customer.inspectionStatus === "已巡查" || customer.inspectionStatus === "异常").length;
  const abnormalInspection = customers.filter((customer) => customer.inspectionStatus === "异常").length;

  document.querySelector("#kpiInspectionDone").textContent = inspectionDone;
  document.querySelector("#kpiAbnormalInspections").textContent = abnormalInspection;
  document.querySelector("#kpiRedIssues").textContent = red;
  document.querySelector("#kpiAuditIssues").textContent = audit;
  document.querySelector("#funnelRed").textContent = `${issues.filter((issue) => issue.status === "红色预警").length} 件`;
  document.querySelector("#funnelOrange").textContent = `${issues.filter((issue) => issue.status === "橙色预警").length} 件`;
  document.querySelector("#funnelBlue").textContent = `${issues.filter((issue) => issue.status === "蓝色关注").length} 件`;
  document.querySelector("#sideAlertCount").textContent = `${issues.filter((issue) => issue.status === "红色预警").length} 件`;
}

function renderBars() {
  const typeCounts = countBy(issues, (issue) => issue.type);
  const typeMax = Math.max(1, ...Object.values(typeCounts));
  document.querySelector("#issueTypeBars").innerHTML = Object.entries(typeCounts).map(([type, count]) => `
    <div class="bar-item">
      <span>${escapeHtml(type)}</span>
      <div><i style="width: ${Math.max(22, Math.round((count / typeMax) * 100))}%;"></i></div>
      <strong>${count}</strong>
    </div>
  `).join("");

  const departmentCounts = countBy(issues, (issue) => getCustomer(issue.customerId).department);
  document.querySelector("#departmentRanks").innerHTML = Object.entries(departmentCounts)
    .sort((a, b) => b[1] - a[1])
    .map(([department, count], index) => `<div><strong>${index + 1}. ${escapeHtml(department)}</strong><span>${count} 件</span></div>`)
    .join("");
}

function issueRow(issue, compact = false) {
  const customer = getCustomer(issue.customerId);
  const cells = compact ? `
    ${cell("客户", customerCell(customer))}
    ${cell("等级", `<span class="badge">${escapeHtml(customer.tier)}</span>`)}
    ${cell("部门", escapeHtml(customer.department))}
    ${cell("问题来源", escapeHtml(issue.source || "-"))}
    ${cell("问题类型", escapeHtml(issue.type))}
    ${cell("预警状态", `<span class="status-badge ${statusClass(issue.status)}">${escapeHtml(issue.status)}</span>`)}
    ${cell("责任人", escapeHtml(issue.owner))}
    ${cell("当前处置", escapeHtml(issue.action))}
  ` : `
    ${cell("反馈编号", `${escapeHtml(issue.id)}${dataTagBadge(issue)}`)}
    ${cell("客户", customerCell(customer))}
    ${cell("问题来源", escapeHtml(issue.source || "-"))}
    ${cell("问题类型", escapeHtml(issue.type))}
    ${cell("问题描述", escapeHtml(issue.summary || "未填写"))}
    ${cell("预警状态", `<span class="status-badge ${statusClass(issue.status)}">${escapeHtml(issue.status)}</span>`)}
    ${cell("责任人", escapeHtml(issue.owner))}
    ${cell("根因", escapeHtml(issue.rootCause))}
    ${cell("当前处置", escapeHtml(issue.action))}
    ${cell("处置后满意度", `<span class="status-badge ${statusClass(issue.postSatisfaction)}">${escapeHtml(issue.postSatisfaction || "待处置")}</span>`)}
  `;

  return `<tr>${cells}${cell("操作", `<div class="action-cell"><button class="small-button" type="button" data-view-issue="${escapeHtml(issue.id)}" data-requires="issue:view">查看</button><button class="small-button" type="button" data-quick-handle="${escapeHtml(issue.id)}" data-requires="issue:handle">处置</button></div>`)}</tr>`;
}

function renderIssueTables() {
  const visible = filteredIssues();
  const highPriority = [...visible].sort((a, b) => b.score - a.score).slice(0, 5);

  document.querySelector("#dashboardRows").innerHTML = highPriority.map((issue) => issueRow(issue, true)).join("") ||
    `<tr><td colspan="9">暂无符合条件的问题。</td></tr>`;

  document.querySelector("#issueRows").innerHTML = visible.map((issue) => issueRow(issue)).join("") ||
    `<tr><td colspan="11">暂无符合条件的问题反馈。</td></tr>`;

  const auditIssues = issues.filter((issue) => issue.status === "待核查");
  document.querySelector("#auditCount").textContent = `${auditIssues.length} 件`;
  document.querySelector("#auditRows").innerHTML = auditIssues.map((issue) => {
    const customer = getCustomer(issue.customerId);
    return `
      <tr>
        ${cell("客户", customerCell(customer))}
        ${cell("问题", escapeHtml(issue.type))}
        ${cell("处置说明", escapeHtml(issue.handlerNote))}
        ${cell("提交人", escapeHtml(issue.submitter))}
        ${cell("操作", `<div class="action-cell"><button class="small-button" type="button" data-view-issue="${escapeHtml(issue.id)}" data-requires="issue:view">查看</button><button class="small-button" type="button" data-audit-pass="${escapeHtml(issue.id)}" data-requires="audit:review">通过</button><button class="small-button" type="button" data-audit-reject="${escapeHtml(issue.id)}" data-requires="audit:review">驳回</button></div>`)}
      </tr>
    `;
  }).join("") || `<tr><td colspan="5">当前没有待核查问题。</td></tr>`;
}

function renderCustomers() {
  document.querySelector("#customerRows").innerHTML = customers.map((customer) => {
    const count = issues.filter((issue) => issue.customerId === customer.id).length;
    return `
      <tr>
        ${cell("客户", customerCell(customer))}
        ${cell("等级", `<span class="badge">${escapeHtml(customer.tier)}</span>`)}
        ${cell("新居地址", escapeHtml(customer.address))}
        ${cell("客管负责人", escapeHtml(customer.customerOwner || "-"))}
        ${cell("入选说明", escapeHtml(customer.keyCustomerReason || "-"))}
        ${cell("部门", escapeHtml(customer.department))}
        ${cell("设计师", escapeHtml(customer.designer))}
        ${cell("项目经理", escapeHtml(customer.manager))}
        ${cell("施工阶段", escapeHtml(customer.stage))}
        ${cell("开工日期", escapeHtml(customer.startDate || "-"))}
        ${cell("计划完工日期", escapeHtml(customer.plannedFinishDate || "-"))}
        ${cell("当前进度", `<span class="status-badge ${progressClass(customer.progressStatus)}">${escapeHtml(customer.progressStatus || "正常")}</span>`)}
        ${cell("巡查与否", `<span class="status-badge ${inspectionFlagClass(customer.inspectionStatus)}">${escapeHtml(inspectionFlag(customer.inspectionStatus))}</span>`)}
        ${cell("巡查状态", `<span class="status-badge ${inspectionClass(customer.inspectionStatus)}">${escapeHtml(customer.inspectionStatus || "未巡查")}</span>`)}
        ${cell("最近巡查", `${escapeHtml(customer.inspectionAt || "-")}<br><small>${escapeHtml(customer.inspectionSummary || "")}</small>`)}
        ${cell("问题数", count)}
        ${cell("操作", `<div class="action-cell"><button class="small-button" type="button" data-open-modal="inspectionModal" data-inspection-customer="${escapeHtml(customer.id)}" data-requires="inspection:create">日查</button><button class="small-button" type="button" data-open-modal="issueModal" data-customer="${escapeHtml(customer.id)}" data-requires="issue:create">反馈</button></div>`)}
      </tr>
    `;
  }).join("");

  renderCustomerSelects();
}

function renderCustomerSelects(filter = "") {
  const keyword = filter.trim().toLowerCase();
  const visibleCustomers = customers.filter((customer) => {
    const text = `${customer.name} ${customer.address} ${customer.manager} ${customer.designer} ${customer.stage} ${customer.startDate} ${customer.plannedFinishDate} ${customer.progressStatus}`.toLowerCase();
    return !keyword || text.includes(keyword);
  });
  const options = visibleCustomers.map((customer) => `<option value="${escapeHtml(customer.id)}">${escapeHtml(customer.name)} · ${escapeHtml(customer.address)}</option>`).join("");
  const issueSelect = document.querySelector("#issueCustomerSelect");
  const inspectionSelect = document.querySelector("#inspectionCustomerSelect");
  if (issueSelect) issueSelect.innerHTML = options;
  if (inspectionSelect) inspectionSelect.innerHTML = customers.map((customer) => `<option value="${escapeHtml(customer.id)}">${escapeHtml(customer.name)} · ${escapeHtml(customer.address)}</option>`).join("");
}

function renderInspections() {
  const done = customers.filter((customer) => customer.inspectionStatus === "已巡查" || customer.inspectionStatus === "异常").length;
  const abnormal = customers.filter((customer) => customer.inspectionStatus === "异常").length;
  const pending = customers.filter((customer) => customer.inspectionStatus === "未巡查").length;
  document.querySelector("#inspectionSummaryCards").innerHTML = `
    <article><span>今日已巡查</span><strong>${done}</strong></article>
    <article><span>异常巡查</span><strong>${abnormal}</strong></article>
    <article><span>未巡查</span><strong>${pending}</strong></article>
  `;

  document.querySelector("#inspectionRows").innerHTML = inspections.map((item) => `
    <tr>
      ${cell("巡查编号", `${escapeHtml(item.id)}${dataTagBadge(item)}`)}
      ${cell("客户", customerCell(getCustomer(item.customerId)))}
      ${cell("巡查与否", `<span class="status-badge ${inspectionFlagClass(item.status)}">${escapeHtml(inspectionFlag(item.status))}</span>`)}
      ${cell("巡查状态", `<span class="status-badge ${inspectionClass(item.status)}">${escapeHtml(item.status)}</span>`)}
      ${cell("巡查人", escapeHtml(item.inspector))}
      ${cell("巡查时间", escapeHtml(item.createdAt))}
      ${cell("施工质量", escapeHtml(item.siteQuality))}
      ${cell("文明施工", escapeHtml(item.civility))}
      ${cell("客户群反馈", escapeHtml(item.groupFeedback))}
      ${cell("巡查结论", escapeHtml(item.summary))}
    </tr>
  `).join("") || `<tr><td colspan="10">暂无每日线上巡查记录。</td></tr>`;
}

function adminRoleOptions(selectedRole) {
  if (!adminConfig) return "";
  return Object.entries(adminConfig.roles).map(([roleKey, role]) => {
    const selected = roleKey === selectedRole ? " selected" : "";
    return `<option value="${escapeHtml(roleKey)}"${selected}>${escapeHtml(role.roleName)}</option>`;
  }).join("");
}

function renderAdminRoleCards() {
  return Object.entries(adminConfig.roles).map(([roleKey, role]) => {
    const isAdmin = roleKey === "admin";
    const allPermissions = role.permissions.includes("*");
    const pageControls = adminConfig.pageCatalog.map((page) => `
      <label>
        <input type="checkbox" data-role-page="${escapeHtml(roleKey)}" value="${escapeHtml(page.key)}" ${role.pages.includes(page.key) || isAdmin ? "checked" : ""} ${isAdmin ? "disabled" : ""}>
        <span>${escapeHtml(page.name)}</span>
      </label>
    `).join("");
    const permissionControls = adminConfig.permissionCatalog.map((permission) => `
      <label>
        <input type="checkbox" data-role-permission="${escapeHtml(roleKey)}" value="${escapeHtml(permission.key)}" ${allPermissions || role.permissions.includes(permission.key) ? "checked" : ""} ${isAdmin ? "disabled" : ""}>
        <span>${escapeHtml(permission.name)}</span>
      </label>
    `).join("");

    return `
      <article class="role-card">
        <div class="role-card-head">
          <div>
            <strong>${escapeHtml(role.roleName)}</strong>
            <span>${escapeHtml(role.summary)}</span>
          </div>
          <button class="small-button" type="button" data-admin-save-role="${escapeHtml(roleKey)}" ${isAdmin ? "disabled" : ""}>保存角色权限</button>
        </div>
        <div class="role-card-section">
          <b>可访问页面</b>
          <div class="checkbox-grid">${pageControls}</div>
        </div>
        <div class="role-card-section">
          <b>可执行操作</b>
          <div class="checkbox-grid">${permissionControls}</div>
        </div>
      </article>
    `;
  }).join("");
}

function renderCustomerReviewRows() {
  const drafts = adminConfig.customerDrafts || [];
  return drafts.map((draft) => {
    const customer = draft.customer || {};
    const canReview = draft.status === "待审核";
    return `
      <tr>
        ${cell("审核单", `${escapeHtml(draft.id)}${dataTagBadge(draft)}`)}
        ${cell("客户", `<strong>${escapeHtml(customer.name)}</strong><br><small>${escapeHtml(customer.address || "-")}</small>`)}
        ${cell("等级", `<span class="badge">${escapeHtml(customer.tier || "-")}</span>`)}
        ${cell("提交人", `${escapeHtml(draft.submittedBy || "-")}<br><small>${escapeHtml(draft.submittedRole || "-")}</small>`)}
        ${cell("客管负责人", escapeHtml(customer.customerOwner || "-"))}
        ${cell("入选说明", escapeHtml(customer.keyCustomerReason || "-"))}
        ${cell("提交时间", escapeHtml(draft.submittedAt || "-"))}
        ${cell("状态", `<span class="status-badge ${draft.status === "待审核" ? "orange" : draft.status === "已通过" ? "closed" : "risk"}">${escapeHtml(draft.status)}</span>`)}
        ${cell("操作", canReview ? `<div class="action-cell"><button class="small-button" type="button" data-admin-customer-approve="${escapeHtml(draft.id)}">通过</button><button class="small-button" type="button" data-admin-customer-reject="${escapeHtml(draft.id)}">驳回</button></div>` : escapeHtml(draft.reviewNote || draft.customerId || "-"))}
      </tr>
    `;
  }).join("") || `<tr><td colspan="9">暂无客户入池审核单。</td></tr>`;
}

function renderAdmin() {
  if (!adminConfig) {
    document.querySelector("#adminUserRows").innerHTML = `<tr><td colspan="9">当前登录人没有系统后台管理权限。</td></tr>`;
    document.querySelector("#adminRoleCards").innerHTML = `<p class="muted-text">后台配置仅系统管理员可维护。</p>`;
    return;
  }

  const activeUsers = adminConfig.users.filter((user) => user.status !== "停用").length;
  const pendingDrafts = (adminConfig.customerDrafts || []).filter((draft) => draft.status === "待审核").length;
  document.querySelector("#adminUserCount").textContent = adminConfig.users.length;
  document.querySelector("#adminActiveUserCount").textContent = activeUsers;
  document.querySelector("#adminRoleCount").textContent = Object.keys(adminConfig.roles).length;
  document.querySelector("#adminPermissionCount").textContent = adminConfig.permissionCatalog.length;
  document.querySelector("#adminPendingCustomerCount").textContent = pendingDrafts;
  document.querySelector("#adminCustomerReviewCount").textContent = `${pendingDrafts} 单待审核`;
  document.querySelector("#adminUserRoleSelect").innerHTML = adminRoleOptions("delivery");
  document.querySelector("#customerReviewRows").innerHTML = renderCustomerReviewRows();

  document.querySelector("#adminUserRows").innerHTML = adminConfig.users.map((user) => `
    <tr>
      ${cell("账号", `<strong>${escapeHtml(user.username)}</strong>`)}
      ${cell("姓名", `<input class="inline-input" data-admin-user-name="${escapeHtml(user.id)}" value="${escapeHtml(user.displayName)}">`)}
      ${cell("手机号", `<input class="inline-input" data-admin-user-phone="${escapeHtml(user.id)}" value="${escapeHtml(user.phone || "")}" placeholder="可选">`)}
      ${cell("部门", `<input class="inline-input" data-admin-user-department="${escapeHtml(user.id)}" value="${escapeHtml(user.department || "")}" placeholder="用于范围">`)}
      ${cell("岗位", `<input class="inline-input" data-admin-user-position="${escapeHtml(user.id)}" value="${escapeHtml(user.position || "")}" placeholder="用于范围">`)}
      ${cell("角色", `<select data-admin-user-role="${escapeHtml(user.id)}">${adminRoleOptions(user.role)}</select>`)}
      ${cell("状态", `<span class="status-badge ${user.status === "停用" ? "orange" : "closed"}">${escapeHtml(user.status)}</span>`)}
      ${cell("重置密码", `<input class="inline-input" type="password" data-admin-user-password="${escapeHtml(user.id)}" value="" placeholder="留空不修改">`)}
      ${cell("操作", `<div class="action-cell"><button class="small-button" type="button" data-admin-save-user="${escapeHtml(user.id)}">保存账号</button><button class="small-button" type="button" data-admin-toggle-user="${escapeHtml(user.id)}">${user.status === "停用" ? "启用" : "停用"}</button></div>`)}
    </tr>
  `).join("");

  document.querySelector("#adminRoleCards").innerHTML = renderAdminRoleCards();
  const dictionaryForm = document.querySelector("#adminDictionaryForm");
  Object.entries(adminConfig.dictionaries || {}).forEach(([key, values]) => {
    if (dictionaryForm.elements[key]) dictionaryForm.elements[key].value = values.join("\n");
  });
}

function renderAll() {
  renderKpis();
  renderBars();
  renderIssueTables();
  renderCustomers();
  renderInspections();
  if (activePage === "admin") renderAdmin();
  applyPermissions();
}

async function loadData() {
  const issueRequest = hasPermission("issue:view") ? apiRequest("/api/issues") : Promise.resolve({ issues: [] });
  const inspectionRequest = hasPermission("inspection:view") ? apiRequest("/api/inspections") : Promise.resolve({ inspections: [] });
  const adminRequest = hasPermission("admin:manage") ? apiRequest("/api/admin/config") : Promise.resolve(null);
  const [customerPayload, issuePayload, inspectionPayload, metaPayload, adminPayload] = await Promise.all([
    apiRequest("/api/customers"),
    issueRequest,
    inspectionRequest,
    apiRequest("/api/meta"),
    adminRequest
  ]);
  customers = customerPayload.customers;
  issues = issuePayload.issues;
  inspections = inspectionPayload.inspections;
  dictionaries = { ...dictionaries, ...(metaPayload.dictionaries || {}) };
  adminConfig = adminPayload;
  renderDictionaryOptions();
}

function switchPage(page) {
  if (!hasPermission(`page:${page}`)) {
    showToast("后台未授权访问该页面。");
    return;
  }
  activePage = page;
  pageTitle.textContent = pageTitles[page] || pageTitles.dashboard;
  document.querySelectorAll(".page-section").forEach((section) => {
    section.classList.toggle("active", section.dataset.section === page);
  });
  document.querySelectorAll("[data-page]").forEach((button) => {
    button.classList.toggle("active", button.dataset.page === page);
  });
  renderAll();
}

function openDrawer(issueId) {
  const issue = issues.find((item) => item.id === issueId);
  if (!issue) return;
  const customer = getCustomer(issue.customerId);
  selectedIssueId = issueId;
  selectedCustomerId = null;
  customerDrawer.classList.remove("open");
  customerDrawer.setAttribute("aria-hidden", "true");

  document.querySelector("#drawerName").textContent = `${customer.name} · ${issue.type}`;
  document.querySelector("#drawerScore").textContent = issue.score;
  document.querySelector("#drawerStatus").textContent = issue.status;
  document.querySelector("#drawerDepartment").textContent = customer.department;
  document.querySelector("#drawerType").textContent = issue.type;
  document.querySelector("#drawerOwner").textContent = issue.owner;
  document.querySelector("#drawerPostSatisfaction").textContent = issue.postSatisfaction || "待处置";
  document.querySelector("#drawerLatestHandle").textContent = issue.handlerNote || "待提交处置记录";
  document.querySelector("#drawerSummary").textContent = issue.summary || "未填写问题描述。";
  const records = issue.handlingRecords || [];
  document.querySelector("#drawerHandlingRecords").innerHTML = records.length ? records.map((record) => `
    <article class="record-card">
      <div><strong>${escapeHtml(record.handler)}</strong><span>${escapeHtml(record.handledAt)}</span></div>
      <p>${escapeHtml(record.note)}</p>
      <small>处置后满意度：${escapeHtml(record.satisfaction || "待回访")}；客户反馈：${escapeHtml(record.feedback || "待补充")}</small>
    </article>
  `).join("") : `<p class="muted-text">暂无处置记录，责任人提交后会按时间形成卡片流水。</p>`;
  document.querySelector("#drawerTimeline").innerHTML = issue.timeline.map((item) => `<li>${escapeHtml(item)}</li>`).join("");

  drawerBackdrop.hidden = false;
  drawer.classList.add("open");
  drawer.setAttribute("aria-hidden", "false");
  applyPermissions();
}

function openCustomerDrawer(customerId) {
  const customer = getCustomer(customerId);
  selectedCustomerId = customer.id;
  selectedIssueId = null;
  drawer.classList.remove("open");
  drawer.setAttribute("aria-hidden", "true");

  const relatedIssues = issues.filter((issue) => issue.customerId === customer.id);
  document.querySelector("#customerDrawerName").textContent = customer.name;
  document.querySelector("#customerDrawerInspectionFlag").textContent = inspectionFlag(customer.inspectionStatus);
  document.querySelector("#customerDrawerTier").textContent = customer.tier;
  document.querySelector("#customerDrawerSource").textContent = customer.source || "-";
  document.querySelector("#customerDrawerCustomerOwner").textContent = customer.customerOwner || "-";
  document.querySelector("#customerDrawerDepartment").textContent = customer.department;
  document.querySelector("#customerDrawerDesigner").textContent = customer.designer;
  document.querySelector("#customerDrawerManager").textContent = customer.manager;
  document.querySelector("#customerDrawerStage").textContent = customer.stage;
  document.querySelector("#customerDrawerStartDate").textContent = customer.startDate || "-";
  document.querySelector("#customerDrawerPlannedFinishDate").textContent = customer.plannedFinishDate || "-";
  document.querySelector("#customerDrawerProgressStatus").innerHTML = `<span class="status-badge ${progressClass(customer.progressStatus)}">${escapeHtml(customer.progressStatus || "正常")}</span>`;
  document.querySelector("#customerDrawerSatisfaction").textContent = `${customer.satisfaction || "-"} 分`;
  document.querySelector("#customerDrawerInspectionStatus").innerHTML = `<span class="status-badge ${inspectionClass(customer.inspectionStatus)}">${escapeHtml(customer.inspectionStatus || "未巡查")}</span>`;
  document.querySelector("#customerDrawerInspector").textContent = customer.inspector || "-";
  document.querySelector("#customerDrawerInspectionAt").textContent = customer.inspectionAt || "-";
  document.querySelector("#customerDrawerAddress").textContent = customer.address || "-";
  document.querySelector("#customerDrawerKeyReason").textContent = customer.keyCustomerReason || "暂无重点客户入选说明。";
  document.querySelector("#customerDrawerInspectionSummary").textContent = customer.inspectionSummary || "暂无巡查结论。";
  document.querySelector("#customerDrawerIssues").innerHTML = relatedIssues.length ? relatedIssues.map((issue) => `
    <article class="record-card">
      <div><strong>${escapeHtml(issue.type)}</strong><span class="status-badge ${statusClass(issue.status)}">${escapeHtml(issue.status)}</span></div>
      <p>${escapeHtml(issue.summary || "未填写问题描述。")}</p>
      <small>责任人：${escapeHtml(issue.owner)}；处置后满意度：${escapeHtml(issue.postSatisfaction || "待处置")}</small>
    </article>
  `).join("") : `<p class="muted-text">暂无关联问题反馈。</p>`;

  drawerBackdrop.hidden = false;
  customerDrawer.classList.add("open");
  customerDrawer.setAttribute("aria-hidden", "false");
  applyPermissions();
}

function closeDrawer() {
  drawer.classList.remove("open");
  drawer.setAttribute("aria-hidden", "true");
  customerDrawer.classList.remove("open");
  customerDrawer.setAttribute("aria-hidden", "true");
  drawerBackdrop.hidden = true;
  selectedIssueId = null;
  selectedCustomerId = null;
}

function openModal(id, customerId) {
  const modal = document.querySelector(`#${id}`);
  if (id === "issueModal" && customerId) {
    if (issueCustomerSearch) issueCustomerSearch.value = "";
    renderCustomerSelects();
    document.querySelector("#issueCustomerSelect").value = customerId;
  }
  if (id === "issueModal" && !customerId) {
    if (issueCustomerSearch) issueCustomerSearch.value = "";
    renderCustomerSelects();
  }
  if (id === "inspectionModal" && customerId) {
    document.querySelector("#inspectionCustomerSelect").value = customerId;
  }
  modalBackdrop.hidden = false;
  modal.classList.add("open");
  modal.setAttribute("aria-hidden", "false");
}

function closeModal() {
  document.querySelectorAll(".modal.open").forEach((modal) => {
    modal.classList.remove("open");
    modal.setAttribute("aria-hidden", "true");
  });
  modalBackdrop.hidden = true;
}

async function refreshAfterMutation(issueId, message) {
  await loadData();
  renderAll();
  if (issueId && drawer.classList.contains("open")) openDrawer(issueId);
  if (message) showToast(message);
}

async function refreshAdminConfig(message) {
  adminConfig = await apiRequest("/api/admin/config");
  dictionaries = { ...dictionaries, ...(adminConfig.dictionaries || {}) };
  renderDictionaryOptions();
  renderAdmin();
  applyPermissions();
  if (message) showToast(message);
}

async function mutateIssue(issueId, action, body = {}) {
  try {
    const payload = await apiRequest(`/api/issues/${encodeURIComponent(issueId)}/${action}`, {
      method: "PATCH",
      body
    });
    await refreshAfterMutation(issueId, payload.message);
  } catch (error) {
    handleApiError(error);
  }
}

async function enterApp(user, token, silent = false) {
  currentUser = user;
  authToken = token;
  window.localStorage.setItem("keyissueToken", token);
  loginScreen.hidden = true;
  appShell.hidden = false;
  currentUserName.textContent = currentUser.userName;
  currentRoleName.textContent = currentUser.roleName;
  activePage = currentUser.pages[0] || "dashboard";
  await loadData();
  switchPage(activePage);
  if (!silent) showToast(`已通过后台登录：${currentUser.roleName}`);
}

function clearSession() {
  currentUser = null;
  authToken = "";
  adminConfig = null;
  customers = [];
  issues = [];
  inspections = [];
  window.localStorage.removeItem("keyissueToken");
  appShell.hidden = true;
  loginScreen.hidden = false;
  currentUserName.textContent = "未登录";
  currentRoleName.textContent = "-";
  loginMessage.textContent = "";
  if (registerMessage) registerMessage.textContent = "";
  closeDrawer();
  closeModal();
}

async function restoreSession() {
  if (!authToken) return;
  try {
    const payload = await apiRequest("/api/auth/me");
    await enterApp(payload.user, authToken, true);
  } catch {
    clearSession();
  }
}

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

document.querySelectorAll("[data-page-jump]").forEach((button) => {
  button.addEventListener("click", () => switchPage(button.dataset.pageJump));
});

[searchInput, tierFilter, departmentFilter].forEach((control) => {
  control.addEventListener("input", renderAll);
  control.addEventListener("change", renderAll);
});

statusButtons.forEach((button) => {
  button.addEventListener("click", () => {
    activeStatus = button.dataset.status;
    statusButtons.forEach((item) => item.classList.toggle("active", item === button));
    renderAll();
  });
});

document.addEventListener("click", async (event) => {
  const saveUserButton = event.target.closest("[data-admin-save-user]");
  if (saveUserButton) {
    if (!requirePermission("admin:manage", "保存后台账号")) return;
    const userId = saveUserButton.dataset.adminSaveUser;
    try {
      const payload = await apiRequest(`/api/admin/users/${encodeURIComponent(userId)}`, {
        method: "PATCH",
        body: {
          displayName: document.querySelector(`[data-admin-user-name="${userId}"]`)?.value,
          phone: document.querySelector(`[data-admin-user-phone="${userId}"]`)?.value,
          department: document.querySelector(`[data-admin-user-department="${userId}"]`)?.value,
          position: document.querySelector(`[data-admin-user-position="${userId}"]`)?.value,
          password: document.querySelector(`[data-admin-user-password="${userId}"]`)?.value,
          role: document.querySelector(`[data-admin-user-role="${userId}"]`)?.value
        }
      });
      await refreshAdminConfig(payload.message);
    } catch (error) {
      handleApiError(error);
    }
    return;
  }

  const toggleUserButton = event.target.closest("[data-admin-toggle-user]");
  if (toggleUserButton) {
    if (!requirePermission("admin:manage", "停启用后台账号")) return;
    const userId = toggleUserButton.dataset.adminToggleUser;
    const user = adminConfig?.users.find((item) => item.id === userId);
    if (!user) return;
    try {
      const payload = await apiRequest(`/api/admin/users/${encodeURIComponent(userId)}`, {
        method: "PATCH",
        body: { status: user.status === "停用" ? "启用" : "停用" }
      });
      await refreshAdminConfig(payload.message);
    } catch (error) {
      handleApiError(error);
    }
    return;
  }

  const saveRoleButton = event.target.closest("[data-admin-save-role]");
  if (saveRoleButton) {
    if (!requirePermission("admin:manage", "保存角色权限")) return;
    const roleKey = saveRoleButton.dataset.adminSaveRole;
    let pages = [...document.querySelectorAll(`[data-role-page="${roleKey}"]`)].filter((input) => input.checked).map((input) => input.value);
    const permissions = [...document.querySelectorAll(`[data-role-permission="${roleKey}"]`)].filter((input) => input.checked).map((input) => input.value);
    if (!permissions.includes("admin:manage")) pages = pages.filter((page) => page !== "admin");
    try {
      const payload = await apiRequest(`/api/admin/roles/${encodeURIComponent(roleKey)}`, {
        method: "PATCH",
        body: { pages, permissions }
      });
      await refreshAdminConfig(payload.message);
    } catch (error) {
      handleApiError(error);
    }
    return;
  }

  const approveCustomerButton = event.target.closest("[data-admin-customer-approve]");
  if (approveCustomerButton) {
    if (!requirePermission("customer:approve", "审核客户入池")) return;
    try {
      const payload = await apiRequest(`/api/admin/customer-drafts/${encodeURIComponent(approveCustomerButton.dataset.adminCustomerApprove)}`, {
        method: "PATCH",
        body: { action: "approve" }
      });
      await loadData();
      renderAll();
      showToast(payload.message);
    } catch (error) {
      handleApiError(error);
    }
    return;
  }

  const rejectCustomerButton = event.target.closest("[data-admin-customer-reject]");
  if (rejectCustomerButton) {
    if (!requirePermission("customer:approve", "驳回客户入池")) return;
    try {
      const payload = await apiRequest(`/api/admin/customer-drafts/${encodeURIComponent(rejectCustomerButton.dataset.adminCustomerReject)}`, {
        method: "PATCH",
        body: { action: "reject", reviewNote: "管理员驳回，需补充入选说明或责任信息。" }
      });
      await loadData();
      renderAll();
      showToast(payload.message);
    } catch (error) {
      handleApiError(error);
    }
    return;
  }

  const openButton = event.target.closest("[data-open-modal]");
  if (openButton) {
    const modalName = openButton.dataset.openModal;
    const permissionMap = {
      customerModal: ["customer:submit", "提交客户入池申请"],
      issueModal: ["issue:create", "新增问题反馈"],
      inspectionModal: ["inspection:create", "提交每日巡查"],
      handleModal: ["issue:handle", "提交处置"]
    };
    const [required, actionName] = permissionMap[modalName] || ["issue:view", "打开表单"];
    if (!requirePermission(required, actionName)) return;
    openModal(modalName, openButton.dataset.customer || openButton.dataset.inspectionCustomer);
    return;
  }

  const customerButton = event.target.closest("[data-view-customer]");
  if (customerButton) {
    if (!requirePermission("issue:view", "查看客户详情")) return;
    openCustomerDrawer(customerButton.dataset.viewCustomer);
    return;
  }

  const viewButton = event.target.closest("[data-view-issue]");
  if (viewButton) {
    if (!requirePermission("issue:view", "查看问题详情")) return;
    openDrawer(viewButton.dataset.viewIssue);
    return;
  }

  const handleButton = event.target.closest("[data-quick-handle]");
  if (handleButton) {
    if (!requirePermission("issue:handle", "处置问题")) return;
    selectedIssueId = handleButton.dataset.quickHandle;
    openModal("handleModal");
    return;
  }

  const passButton = event.target.closest("[data-audit-pass]");
  if (passButton) {
    if (!requirePermission("audit:review", "核查通过")) return;
    mutateIssue(passButton.dataset.auditPass, "audit-pass");
    return;
  }

  const rejectButton = event.target.closest("[data-audit-reject]");
  if (rejectButton) {
    if (!requirePermission("audit:review", "驳回整改")) return;
    mutateIssue(rejectButton.dataset.auditReject, "audit-reject");
  }
});

document.querySelectorAll("[data-close-modal]").forEach((button) => button.addEventListener("click", closeModal));
modalBackdrop.addEventListener("click", closeModal);
document.querySelector("[data-close-drawer]").addEventListener("click", closeDrawer);
document.querySelector("[data-close-customer-drawer]").addEventListener("click", closeDrawer);
drawerBackdrop.addEventListener("click", closeDrawer);

document.querySelectorAll("[data-customer-drawer-action]").forEach((button) => {
  button.addEventListener("click", () => {
    if (!selectedCustomerId) return;
    if (button.dataset.customerDrawerAction === "inspection") {
      if (!requirePermission("inspection:create", "提交每日巡查")) return;
      openModal("inspectionModal", selectedCustomerId);
    }
    if (button.dataset.customerDrawerAction === "feedback") {
      if (!requirePermission("issue:create", "提交问题反馈")) return;
      openModal("issueModal", selectedCustomerId);
    }
  });
});

document.querySelectorAll("[data-drawer-action]").forEach((button) => {
  button.addEventListener("click", () => {
    if (!selectedIssueId) return;
    const action = button.dataset.drawerAction;
    if (action === "assign") {
      if (!requirePermission("issue:assign", "指派责任人")) return;
      mutateIssue(selectedIssueId, "assign", { owner: "部门负责人" });
    }
    if (action === "handle") {
      if (!requirePermission("issue:handle", "提交处置")) return;
      openModal("handleModal");
    }
    if (action === "approve") {
      if (!requirePermission("audit:review", "核查通过")) return;
      mutateIssue(selectedIssueId, "audit-pass");
    }
    if (action === "reject") {
      if (!requirePermission("audit:review", "驳回整改")) return;
      mutateIssue(selectedIssueId, "audit-reject");
    }
  });
});

document.querySelector("#issueForm").addEventListener("submit", async (event) => {
  event.preventDefault();
  if (!requirePermission("issue:create", "提交问题反馈")) return;
  const form = event.currentTarget;
  if (!beginFormSubmit(form)) return;
  try {
    const data = Object.fromEntries(new FormData(form).entries());
    const payload = await apiRequest("/api/issues", { method: "POST", body: data });
    form.reset();
    closeModal();
    await refreshAfterMutation(payload.issue.id, payload.message);
    switchPage("issues");
  } catch (error) {
    handleApiError(error);
  } finally {
    endFormSubmit(form);
  }
});

document.querySelector("#inspectionForm").addEventListener("submit", async (event) => {
  event.preventDefault();
  if (!requirePermission("inspection:create", "提交每日线上巡查")) return;
  const form = event.currentTarget;
  if (!beginFormSubmit(form)) return;
  try {
    const data = Object.fromEntries(new FormData(form).entries());
    const payload = await apiRequest("/api/inspections", { method: "POST", body: data });
    form.reset();
    closeModal();
    await loadData();
    switchPage("inspections");
    showToast(payload.message);
  } catch (error) {
    handleApiError(error);
  } finally {
    endFormSubmit(form);
  }
});

document.querySelector("#handleForm").addEventListener("submit", async (event) => {
  event.preventDefault();
  if (!selectedIssueId) return;
  if (!requirePermission("issue:handle", "提交处置")) return;
  const form = event.currentTarget;
  if (!beginFormSubmit(form)) return;
  try {
    const data = Object.fromEntries(new FormData(form).entries());
    const payload = await apiRequest(`/api/issues/${encodeURIComponent(selectedIssueId)}/handle`, {
      method: "PATCH",
      body: data
    });
    form.reset();
    closeModal();
    await refreshAfterMutation(selectedIssueId, payload.message);
  } catch (error) {
    handleApiError(error);
  } finally {
    endFormSubmit(form);
  }
});

document.querySelector("#customerForm").addEventListener("submit", async (event) => {
  event.preventDefault();
  if (!requirePermission("customer:submit", "提交客户入池申请")) return;
  const form = event.currentTarget;
  if (!beginFormSubmit(form)) return;
  try {
    const data = Object.fromEntries(new FormData(form).entries());
    const payload = await apiRequest("/api/customers", { method: "POST", body: data });
    form.reset();
    closeModal();
    await loadData();
    if (payload.customer) switchPage("customers");
    if (payload.draft && hasPermission("page:admin")) switchPage("admin");
    showToast(payload.message);
  } catch (error) {
    handleApiError(error);
  } finally {
    endFormSubmit(form);
  }
});

document.querySelector("#adminUserForm")?.addEventListener("submit", async (event) => {
  event.preventDefault();
  if (!requirePermission("admin:manage", "新增后台账号")) return;
  const form = event.currentTarget;
  if (!beginFormSubmit(form)) return;
  try {
    const data = Object.fromEntries(new FormData(form).entries());
    const payload = await apiRequest("/api/admin/users", { method: "POST", body: data });
    form.reset();
    await refreshAdminConfig(payload.message);
  } catch (error) {
    handleApiError(error);
  } finally {
    endFormSubmit(form);
  }
});

document.querySelector("#adminDictionaryForm")?.addEventListener("submit", async (event) => {
  event.preventDefault();
  if (!requirePermission("admin:manage", "保存基础字典")) return;
  const form = event.currentTarget;
  if (!beginFormSubmit(form)) return;
  try {
    const data = Object.fromEntries(new FormData(form).entries());
    const payload = await apiRequest("/api/admin/dictionaries", { method: "PATCH", body: data });
    dictionaries = { ...dictionaries, ...(payload.dictionaries || {}) };
    await refreshAdminConfig(payload.message);
  } catch (error) {
    handleApiError(error);
  } finally {
    endFormSubmit(form);
  }
});

issueCustomerSearch?.addEventListener("input", () => {
  renderCustomerSelects(issueCustomerSearch.value);
});

document.querySelector("#saveRulesBtn").addEventListener("click", async () => {
  if (!requirePermission("rules:edit", "保存预警规则")) return;
  try {
    const payload = await apiRequest("/api/rules", { method: "POST", body: { source: "official" } });
    showToast(payload.message);
  } catch (error) {
    handleApiError(error);
  }
});

loginForm.addEventListener("submit", async (event) => {
  event.preventDefault();
  loginMessage.textContent = "正在请求后台登录...";
  try {
    const payload = await apiRequest("/api/auth/login", {
      method: "POST",
      body: {
        username: loginUsername.value.trim(),
        password: loginPassword.value
      }
    });
    loginMessage.textContent = "";
    await enterApp(payload.user, payload.token);
  } catch (error) {
    loginMessage.textContent = error.message;
  }
});

registerForm?.addEventListener("submit", async (event) => {
  event.preventDefault();
  const form = event.currentTarget;
  const password = registerPassword.value.trim();
  const confirmPassword = registerPasswordConfirm.value.trim();
  if (password.length < 6) {
    registerMessage.textContent = "密码至少需要 6 位。";
    return;
  }
  if (password !== confirmPassword) {
    registerMessage.textContent = "两次输入的密码不一致。";
    return;
  }
  if (!beginFormSubmit(form)) return;
  registerMessage.textContent = "正在核对花名册并创建账号...";
  try {
    const payload = await apiRequest("/api/auth/register", {
      method: "POST",
      body: {
        name: registerName.value.trim(),
        phone: registerPhone.value.trim(),
        password,
        confirmPassword
      }
    });
    registerMessage.textContent = "";
    form.reset();
    await enterApp(payload.user, payload.token);
    showToast(payload.message);
  } catch (error) {
    registerMessage.textContent = error.message;
  } finally {
    endFormSubmit(form);
  }
});

logoutBtn.addEventListener("click", async () => {
  try {
    await apiRequest("/api/auth/logout", { method: "POST" });
  } catch {
    // 即使后台会话已经失效，也要清理本地登录态。
  }
  clearSession();
});

document.addEventListener("keydown", (event) => {
  if (event.key === "Escape") {
    closeDrawer();
    closeModal();
  }
});

restoreSession();
