<script setup>
import { computed, reactive, ref } from "vue";
import LedgerPager from "@/components/common/LedgerPager.vue";
import StatusBadge from "@/components/common/StatusBadge.vue";
import { specialtyCatalog, specialtyTypesFor } from "@/data/specialties";
import { useLedger } from "@/composables/useLedger";
import { api } from "@/lib/api";
import { uiStore } from "@/stores/ui";

const props = defineProps({
  page: { type: String, required: true },
  data: { type: Object, default: () => ({}) },
});
const emit = defineEmits(["reload"]);
const busy = ref(false);
const error = ref("");
const issued = ref(null);
const notes = reactive({});
const setting = reactive({
  examId: "",
  preferenceStart: "",
  preferenceEnd: "",
  status: "draft",
  maxChoices: 5,
  maxSubmissions: 3,
  progress: "",
  enabled: false,
  autoPublish: true,
});
const account = reactive({
  schoolId: "",
  username: "",
  password: "",
  displayName: "",
});
const plan = reactive({
  examId: "",
  schoolId: "",
  note: "",
  categories: [
    { name: "普通生", quota: 1, specialtyCategory: "", specialtyType: "" },
  ],
});

const accountSelected = ref([]);
const planSelected = ref([]);
const reportingSelected = ref([]);
const placementSelected = ref([]);
const preferenceSelected = ref([]);

const accountLedger = useLedger(() => props.data.schoolAccounts || [], {
  filters: {
    status: (row, value) => (row.active ? "active" : "disabled") === value,
  },
  searchText: (row) =>
    `${row.displayName} ${row.username} ${row.schoolName} ${row.schoolCode}`,
});
const planLedger = useLedger(() => props.data.plans || [], {
  filters: {
    exam: (row, value) => row.examId === value,
    school: (row, value) => row.schoolId === value,
    status: (row, value) => row.status === value,
  },
  searchText: (row) =>
    `${row.examName} ${row.schoolName} ${row.payload?.note || ""} ${JSON.stringify(row.payload?.categories || [])}`,
});
const reportingLedger = useLedger(() => props.data.reportingRequests || [], {
  filters: {
    exam: (row, value) => row.examId === value,
    school: (row, value) => row.schoolId === value,
    status: (row, value) => row.status === value,
  },
  searchText: (row) =>
    `${row.examName} ${row.schoolName} ${row.payload?.decisionNote || ""} ${row.payload?.approvalNote || ""}`,
});
const placementLedger = useLedger(() => props.data.placements || [], {
  filters: {
    exam: (row, value) => row.examId === value,
    school: (row, value) => row.schoolId === value,
    status: (row, value) => row.status === value,
  },
  searchText: (row) =>
    `${row.candidate?.name} ${row.candidate?.registrationNumber} ${row.examName} ${row.schoolName} ${row.payload?.categoryName}`,
});
const preferenceLedger = useLedger(() => props.data.preferenceRows || [], {
  filters: {
    exam: (row, value) => row.examId === value,
    school: (row, value) =>
      row.sourceSchoolId === value || row.sourceSchoolName === value,
    status: (row, value) => row.fillStatus === value,
  },
  searchText: (row) =>
    `${row.candidate?.name} ${row.candidate?.registrationNumber} ${row.examName} ${row.sourceSchoolName} ${JSON.stringify(row.choices || [])}`,
});

const selectedSetting = computed(() =>
  props.data.settings?.find((item) => item.examId === setting.examId),
);
const admissionSchools = computed(
  () => props.data.admissionSchools || props.data.schools || [],
);
const sourceSchools = computed(() => [
  ...new Set(
    (props.data.preferenceRows || [])
      .map((item) => item.sourceSchoolName)
      .filter(Boolean),
  ),
]);
const placementStatuses = computed(() => [
  ...new Set(
    (props.data.placements || []).map((item) => item.status).filter(Boolean),
  ),
]);
const preferenceStatuses = computed(() => [
  ...new Set(
    (props.data.preferenceRows || [])
      .map((item) => item.fillStatus)
      .filter(Boolean),
  ),
]);

function hydrateSetting() {
  const current = selectedSetting.value || props.data.settings?.[0];
  if (!current) {
    setting.examId ||= props.data.exams?.[0]?.id || "";
    return;
  }
  Object.assign(setting, {
    examId: current.examId,
    preferenceStart: current.payload?.preferenceStart?.slice(0, 16) || "",
    preferenceEnd: current.payload?.preferenceEnd?.slice(0, 16) || "",
    status: current.status || "draft",
    maxChoices: current.payload?.maxChoices || 5,
    maxSubmissions: current.payload?.maxSubmissions || 3,
    progress: current.payload?.progress || "",
    enabled: Boolean(current.payload?.enabled),
    autoPublish: current.payload?.autoPublish !== false,
  });
}
function addCategory() {
  plan.categories.push({
    name: "",
    quota: 1,
    specialtyCategory: "",
    specialtyType: "",
  });
}
function resetSpecialty(category) {
  category.specialtyType = "";
}
function togglePageSelection(selection, rows, eligible = () => true) {
  const ids = rows
    .filter(eligible)
    .map(
      (item) =>
        item.id || `${item.examId}:${item.candidate?.registrationNumber}`,
    );
  const allSelected =
    ids.length > 0 && ids.every((id) => selection.value.includes(id));
  selection.value = allSelected
    ? selection.value.filter((id) => !ids.includes(id))
    : [...new Set([...selection.value, ...ids])];
}
function selectedRows(selection, rows) {
  return rows.filter((item) =>
    selection.value.includes(
      item.id || `${item.examId}:${item.candidate?.registrationNumber}`,
    ),
  );
}
async function act(action, success, reload = true) {
  busy.value = true;
  error.value = "";
  try {
    const result = await action();
    if (success) uiStore.notify(success);
    if (reload) emit("reload");
    return result;
  } catch (requestError) {
    error.value = requestError.message;
    return null;
  } finally {
    busy.value = false;
  }
}
async function runBulk(items, request, success) {
  if (!items.length) return;
  busy.value = true;
  error.value = "";
  let completed = 0;
  try {
    for (const item of items) {
      await request(item);
      completed += 1;
    }
    uiStore.notify(`${success}，共 ${completed} 条`);
    emit("reload");
  } catch (requestError) {
    error.value = `${completed} 条已完成；${requestError.message}`;
  } finally {
    busy.value = false;
  }
}
function saveSetting() {
  act(
    () =>
      api(`/api/admin/admissions/${setting.examId}/setting`, {
        method: "PUT",
        body: {
          ...setting,
          maxChoices: Number(setting.maxChoices),
          maxSubmissions: Number(setting.maxSubmissions),
          preferenceStart: setting.preferenceStart
            ? new Date(setting.preferenceStart).toISOString()
            : "",
          preferenceEnd: setting.preferenceEnd
            ? new Date(setting.preferenceEnd).toISOString()
            : "",
        },
      }),
    "志愿设置已保存",
  );
}
function runAdmission(actionName) {
  const labels = {
    match: "按规则投档",
    finalize: "签发通知书并开启报到",
    supplementary: "开启补录",
  };
  if (
    window.confirm(
      `确认执行“${labels[actionName]}”吗？该操作会改变本场录取状态。`,
    )
  )
    act(
      () =>
        api(`/api/admin/admissions/${setting.examId}/${actionName}`, {
          method: "POST",
          body: {},
        }),
      `${labels[actionName]}已完成`,
    );
}
async function createAccount() {
  const result = await act(
    () =>
      api("/api/admin/admission-school-accounts", {
        method: "POST",
        body: account,
      }),
    "招生学校账户已创建",
    false,
  );
  if (result) {
    issued.value = result.temporaryPassword
      ? { account: result.username, password: result.temporaryPassword }
      : null;
    emit("reload");
  }
}
function toggleAccount(item) {
  return api(`/api/admin/admission-school-accounts/${item.id}`, {
    method: "PATCH",
    body: { active: !item.active },
  });
}
async function resetAccount(item) {
  const result = await act(
    () =>
      api(`/api/admin/admission-school-accounts/${item.id}/reset-password`, {
        method: "POST",
      }),
    "",
    false,
  );
  if (result)
    issued.value = {
      account: result.username,
      password: result.temporaryPassword,
    };
}
function bulkAccounts(active) {
  const rows = selectedRows(
    accountSelected,
    props.data.schoolAccounts || [],
  ).filter((item) => item.active !== active);
  runBulk(
    rows,
    (item) =>
      api(`/api/admin/admission-school-accounts/${item.id}`, {
        method: "PATCH",
        body: { active },
      }),
    active ? "已批量启用招生账户" : "已批量停用招生账户",
  ).then(() => {
    accountSelected.value = [];
  });
}
function submitPlan() {
  const categories = plan.categories
    .map((item, index) => ({
      code: `category_${index + 1}`,
      name: item.name.trim(),
      quota: Number(item.quota),
      isSpecialty: Boolean(item.specialtyCategory),
      specialtyCategory: item.specialtyCategory,
      specialtyType: item.specialtyType,
      indicatorAllocations: [],
    }))
    .filter((item) => item.name && item.quota > 0);
  if (categories.some((item) => item.isSpecialty && !item.specialtyType)) {
    error.value = "特长生类别必须选择具体特长项目";
    return;
  }
  act(
    () =>
      api("/api/admin/admission-plans", {
        method: "POST",
        body: {
          examId: plan.examId,
          schoolId: plan.schoolId,
          note: plan.note,
          categories,
        },
      }),
    "招生计划已代上传并通过",
  );
}
function reviewPlan(item, status) {
  return api(`/api/admin/admission-plans/${item.id}`, {
    method: "PATCH",
    body: { status, reviewNote: notes[item.id] || "" },
  });
}
function bulkPlans(status) {
  const rows = selectedRows(planSelected, props.data.plans || []).filter(
    (item) => item.status === "pending",
  );
  runBulk(
    rows,
    (item) => reviewPlan(item, status),
    status === "approved" ? "招生计划已批量通过" : "招生计划已批量退回",
  ).then(() => {
    planSelected.value = [];
  });
}
function reportingBody(item, approved, preferenceEnd = "") {
  return { approved, approvalNote: notes[item.id] || "", preferenceEnd };
}
function reviewReporting(item, approved) {
  const preferenceEnd =
    approved && item.payload?.supplementDecision === "supplement"
      ? window.prompt("补录志愿结束时间（ISO 或本地日期时间）", "") || ""
      : "";
  if (
    approved &&
    item.payload?.supplementDecision === "supplement" &&
    !preferenceEnd
  )
    return;
  act(
    () =>
      api(`/api/admin/admission-reporting/${item.id}`, {
        method: "PATCH",
        body: reportingBody(item, approved, preferenceEnd),
      }),
    approved ? "报到与补录决定已批准" : "报到决定已退回",
  );
}
function bulkReporting(approved) {
  const rows = selectedRows(
    reportingSelected,
    props.data.reportingRequests || [],
  ).filter((item) => item.status === "pending_approval");
  let preferenceEnd = "";
  if (
    approved &&
    rows.some((item) => item.payload?.supplementDecision === "supplement")
  ) {
    preferenceEnd =
      window.prompt(
        "批量批准中的补录申请统一结束时间（ISO 或本地日期时间）",
        "",
      ) || "";
    if (!preferenceEnd) return;
  }
  runBulk(
    rows,
    (item) =>
      api(`/api/admin/admission-reporting/${item.id}`, {
        method: "PATCH",
        body: reportingBody(
          item,
          approved,
          item.payload?.supplementDecision === "supplement"
            ? preferenceEnd
            : "",
        ),
      }),
    approved ? "报到决定已批量批准" : "报到决定已批量退回",
  ).then(() => {
    reportingSelected.value = [];
  });
}
function reviewWithdrawal(item, approved) {
  return api(`/api/admin/admission-withdrawals/${item.id}`, {
    method: "PATCH",
    body: { approved, reviewNote: notes[item.id] || "" },
  });
}
function bulkWithdrawals(approved) {
  const rows = selectedRows(
    placementSelected,
    props.data.placements || [],
  ).filter((item) => item.status === "withdrawal_pending");
  runBulk(
    rows,
    (item) => reviewWithdrawal(item, approved),
    approved ? "退档申请已批量批准" : "退档申请已批量驳回",
  ).then(() => {
    placementSelected.value = [];
  });
}
function exportUrl(kind, ledger) {
  const params = new URLSearchParams();
  if (ledger.query) params.set("q", ledger.query);
  for (const [key, value] of Object.entries(ledger.filters))
    if (value)
      params.set(
        key === "school"
          ? kind === "preferences"
            ? "sourceSchool"
            : "schoolId"
          : key === "exam"
            ? "examId"
            : key === "status" && kind === "preferences"
              ? "fillStatus"
              : key,
        value,
      );
  return `/api/admin/admissions/${kind}/export?${params}`;
}
function exportAdmissionSelected(kind, selection) {
  const ids = Array.isArray(selection) ? selection : selection.value;
  if (!ids.length) return;
  const anchor = document.createElement("a");
  anchor.href = `/api/admin/admissions/${kind}/export?ids=${encodeURIComponent(ids.join(","))}`;
  anchor.click();
}

hydrateSetting();
</script>

<template>
  <div class="admin-admission-workspace">
    <div v-if="error" class="form-error">{{ error }}</div>
    <section v-if="issued" class="issued-credential">
      <div>
        <span>一次性登录凭据</span>
        <h2>招生学校临时密码</h2>
        <p>关闭后不再展示，请安全交付。</p>
      </div>
      <dl>
        <div>
          <dt>账号</dt>
          <dd>{{ issued.account }}</dd>
        </div>
        <div>
          <dt>临时密码</dt>
          <dd>{{ issued.password }}</dd>
        </div>
      </dl>
      <button class="app-button" @click="issued = null">我已保存</button>
    </section>
    <section class="admission-command-banner">
      <div>
        <span>招生工作总览</span>
        <h2>中考招生录取控制台</h2>
        <p>
          志愿内容仅超级管理员可见且不可代改；投档和录取变更全部进入审计日志。
        </p>
      </div>
    </section>

    <template v-if="page === 'admission-settings'">
      <form
        class="business-form admission-admin-setting"
        @submit.prevent="saveSetting"
      >
        <p>考试志愿设置</p>
        <h2>考试志愿与录取阶段</h2>
        <label
          ><span>考试</span
          ><select v-model="setting.examId" @change="hydrateSetting">
            <option v-for="exam in data.exams" :key="exam.id" :value="exam.id">
              {{ exam.name }}
            </option>
          </select></label
        >
        <div class="form-grid">
          <label
            ><span>填报开始</span
            ><input
              v-model="setting.preferenceStart"
              type="datetime-local" /></label
          ><label
            ><span>填报结束</span
            ><input
              v-model="setting.preferenceEnd"
              type="datetime-local" /></label
          ><label
            ><span>当前阶段</span
            ><select v-model="setting.status">
              <option
                v-for="(label, value) in {
                  draft: '草稿',
                  filling: '志愿填报中',
                  closed: '填报截止',
                  matching: '投档中',
                  school_review: '学校审核',
                  reporting: '考生报到',
                  supplementary: '补录填报',
                  completed: '录取完成',
                }"
                :key="value"
                :value="value"
              >
                {{ label }}
              </option>
            </select></label
          ><label
            ><span>普通志愿数</span
            ><input
              v-model="setting.maxChoices"
              type="number"
              min="1"
              max="20" /></label
          ><label
            ><span>最多提交次数</span
            ><input
              v-model="setting.maxSubmissions"
              type="number"
              min="1"
              max="50" /></label
          ><label
            ><span>考生进度说明</span><input v-model="setting.progress"
          /></label>
        </div>
        <div class="check-row">
          <label
            ><input v-model="setting.enabled" type="checkbox" />
            启用志愿填报</label
          ><label
            ><input v-model="setting.autoPublish" type="checkbox" />
            完成后自动公示</label
          >
        </div>
        <button class="app-button app-button--primary">保存志愿设置</button>
        <footer>
          <button
            class="app-button"
            type="button"
            @click="runAdmission('match')"
          >
            按规则投档</button
          ><button
            class="app-button"
            type="button"
            @click="runAdmission('finalize')"
          >
            签发通知书并开启报到</button
          ><button
            class="app-button"
            type="button"
            @click="runAdmission('supplementary')"
          >
            开启补录
          </button>
        </footer>
      </form>
      <section class="record-metrics">
        <article>
          <span>待审计划</span
          ><strong>{{
            data.plans?.filter((item) => item.status === "pending").length || 0
          }}</strong>
        </article>
        <article>
          <span>学校审核中</span
          ><strong>{{
            data.placements?.filter((item) => item.status === "school_review")
              .length || 0
          }}</strong>
        </article>
        <article>
          <span>退档待审</span
          ><strong>{{
            data.placements?.filter(
              (item) => item.status === "withdrawal_pending",
            ).length || 0
          }}</strong>
        </article>
        <article>
          <span>正式录取</span
          ><strong>{{
            data.placements?.filter((item) => item.status === "final").length ||
            0
          }}</strong>
        </article>
      </section>
    </template>

    <template v-else-if="page === 'admission-accounts'">
      <form class="business-form" @submit.prevent="createAccount">
        <p>招生学校账号</p>
        <h2>创建招生学校账户</h2>
        <div class="form-grid">
          <label
            ><span>招生学校</span
            ><select v-model="account.schoolId" required>
              <option value="">请选择</option>
              <option
                v-for="school in admissionSchools"
                :key="school.id"
                :value="school.id"
              >
                {{ school.code }} · {{ school.name }}
              </option>
            </select></label
          ><label
            ><span>显示名称</span
            ><input
              v-model="account.displayName"
              placeholder="学校招生办公室" /></label
          ><label
            ><span>登录账号</span
            ><input v-model="account.username" required /></label
          ><label
            ><span>初始密码</span
            ><input
              v-model="account.password"
              type="password"
              minlength="8"
              required
          /></label>
        </div>
        <button class="app-button app-button--primary">创建招生账户</button>
      </form>
      <section class="record-panel">
        <header>
          <div>
            <h2>招生学校账户台账</h2>
            <p>
              筛选结果 {{ accountLedger.total }} / 共
              {{ data.schoolAccounts?.length || 0 }} 个
            </p>
          </div>
        </header>
        <div class="ledger-toolbar">
          <label
            ><span>关键词</span
            ><input
              v-model="accountLedger.query"
              placeholder="名称、账号、学校代码" /></label
          ><label
            ><span>状态</span
            ><select v-model="accountLedger.filters.status">
              <option value="">全部状态</option>
              <option value="active">启用</option>
              <option value="disabled">停用</option>
            </select></label
          ><button class="table-action" @click="accountLedger.clear">
            清除筛选
          </button>
        </div>
        <div class="ledger-bulk">
          <label
            ><input
              type="checkbox"
              @change="togglePageSelection(accountSelected, accountLedger.rows)"
            />
            选择当前页</label
          ><strong>已选 {{ accountSelected.length }} 个</strong
          ><button
            :disabled="!accountSelected.length || busy"
            @click="bulkAccounts(true)"
          >
            批量启用</button
          ><button
            :disabled="!accountSelected.length || busy"
            @click="bulkAccounts(false)"
          >
            批量停用
          </button>
        </div>
        <div class="table-scroll">
          <table>
            <thead>
              <tr>
                <th>选择</th>
                <th>显示名称</th>
                <th>账号</th>
                <th>学校</th>
                <th>状态</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="item in accountLedger.rows" :key="item.id">
                <td>
                  <input
                    v-model="accountSelected"
                    type="checkbox"
                    :value="item.id"
                  />
                </td>
                <td>{{ item.displayName }}</td>
                <td>{{ item.username }}</td>
                <td>
                  {{ item.schoolName }}<small>{{ item.schoolCode }}</small>
                </td>
                <td>
                  <StatusBadge :value="item.active ? 'active' : 'disabled'" />
                </td>
                <td>
                  <button class="table-action" @click="resetAccount(item)">
                    重置密码</button
                  ><button
                    class="table-action"
                    @click="
                      act(
                        () => toggleAccount(item),
                        item.active ? '招生账户已停用' : '招生账户已启用',
                      )
                    "
                  >
                    {{ item.active ? "停用" : "启用" }}
                  </button>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
        <LedgerPager
          v-model:page="accountLedger.page"
          v-model:page-size="accountLedger.pageSize"
          :total="accountLedger.total"
        />
      </section>
    </template>

    <template v-else-if="page === 'admission-plans'">
      <form class="business-form" @submit.prevent="submitPlan">
        <p>代报招生计划</p>
        <h2>代上传招生计划</h2>
        <div class="form-grid">
          <label
            ><span>考试</span
            ><select v-model="plan.examId" required>
              <option
                v-for="exam in data.exams"
                :key="exam.id"
                :value="exam.id"
              >
                {{ exam.name }}
              </option>
            </select></label
          ><label
            ><span>招生学校</span
            ><select v-model="plan.schoolId" required>
              <option
                v-for="school in admissionSchools"
                :key="school.id"
                :value="school.id"
              >
                {{ school.name }}
              </option>
            </select></label
          >
        </div>
        <div
          v-for="(category, index) in plan.categories"
          :key="index"
          class="plan-admin-row"
        >
          <input
            v-model="category.name"
            required
            placeholder="类别名称"
          /><input
            v-model="category.quota"
            type="number"
            min="1"
            required
            placeholder="计划人数"
          /><select
            v-model="category.specialtyCategory"
            @change="resetSpecialty(category)"
          >
            <option value="">普通 / 政策类</option>
            <option
              v-for="item in specialtyCatalog"
              :key="item.code"
              :value="item.code"
            >
              {{ item.name }}特长生
            </option></select
          ><select
            v-model="category.specialtyType"
            :disabled="!category.specialtyCategory"
          >
            <option value="">选择特长项目</option>
            <option
              v-for="item in specialtyTypesFor(category.specialtyCategory)"
              :key="item[0]"
              :value="item[0]"
            >
              {{ item[1] }}
            </option></select
          ><button type="button" @click="plan.categories.splice(index, 1)">
            移除
          </button>
        </div>
        <button class="app-button" type="button" @click="addCategory">
          ＋ 添加类别</button
        ><label
          ><span>计划说明</span><textarea v-model="plan.note"></textarea></label
        ><button class="app-button app-button--primary">
          代上传并审核通过
        </button>
      </form>
      <section class="record-panel">
        <header>
          <div>
            <h2>招生计划审核台账</h2>
            <p>
              筛选结果 {{ planLedger.total }} / 共
              {{ data.plans?.length || 0 }} 份
            </p>
          </div>
        </header>
        <div class="ledger-toolbar ledger-toolbar--wide">
          <label
            ><span>关键词</span
            ><input
              v-model="planLedger.query"
              placeholder="考试、学校、计划类别" /></label
          ><label
            ><span>考试</span
            ><select v-model="planLedger.filters.exam">
              <option value="">全部考试</option>
              <option
                v-for="exam in data.exams"
                :key="exam.id"
                :value="exam.id"
              >
                {{ exam.name }}
              </option>
            </select></label
          ><label
            ><span>学校</span
            ><select v-model="planLedger.filters.school">
              <option value="">全部学校</option>
              <option
                v-for="school in admissionSchools"
                :key="school.id"
                :value="school.id"
              >
                {{ school.name }}
              </option>
            </select></label
          ><label
            ><span>状态</span
            ><select v-model="planLedger.filters.status">
              <option value="">全部状态</option>
              <option value="pending">待审核</option>
              <option value="approved">已通过</option>
              <option value="rejected">已退回</option>
            </select></label
          >
        </div>
        <div class="ledger-bulk">
          <label
            ><input
              type="checkbox"
              @change="
                togglePageSelection(
                  planSelected,
                  planLedger.rows,
                  (item) => item.status === 'pending',
                )
              "
            />
            选择当前页待审项</label
          ><strong>已选 {{ planSelected.length }} 份</strong
          ><button
            :disabled="!planSelected.length || busy"
            @click="bulkPlans('rejected')"
          >
            批量退回</button
          ><button
            :disabled="!planSelected.length || busy"
            @click="bulkPlans('approved')"
          >
            批量通过
          </button>
        </div>
        <div class="table-scroll">
          <table>
            <thead>
              <tr>
                <th>选择</th>
                <th>考试 / 学校</th>
                <th>计划构成</th>
                <th>状态</th>
                <th>审核</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="item in planLedger.rows" :key="item.id">
                <td>
                  <input
                    v-model="planSelected"
                    type="checkbox"
                    :value="item.id"
                  />
                </td>
                <td>
                  {{ item.examName }}<small>{{ item.schoolName }}</small>
                </td>
                <td>
                  <span
                    v-for="category in item.payload?.categories"
                    :key="category.code"
                    class="table-stack"
                    >{{ category.name }} {{ category.quota }} 人</span
                  >
                </td>
                <td><StatusBadge :value="item.status" /></td>
                <td>
                  <div v-if="item.status === 'pending'" class="row-decision">
                    <input
                      v-model="notes[item.id]"
                      placeholder="审核意见"
                    /><button
                      @click="
                        act(
                          () => reviewPlan(item, 'rejected'),
                          '招生计划已退回',
                        )
                      "
                    >
                      退回</button
                    ><button
                      @click="
                        act(
                          () => reviewPlan(item, 'approved'),
                          '招生计划已通过',
                        )
                      "
                    >
                      通过
                    </button>
                  </div>
                  <span v-else>{{ item.payload?.reviewNote }}</span>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
        <LedgerPager
          v-model:page="planLedger.page"
          v-model:page-size="planLedger.pageSize"
          :total="planLedger.total"
        />
      </section>
    </template>

    <template v-else-if="page === 'admission-reporting'">
      <section class="record-panel">
        <header>
          <div>
            <h2>学校报到与补录决定</h2>
            <p>
              筛选结果 {{ reportingLedger.total }} / 共
              {{ data.reportingRequests?.length || 0 }} 条
            </p>
          </div>
        </header>
        <div class="ledger-toolbar ledger-toolbar--wide">
          <label
            ><span>关键词</span
            ><input
              v-model="reportingLedger.query"
              placeholder="考试、学校、决定说明" /></label
          ><label
            ><span>考试</span
            ><select v-model="reportingLedger.filters.exam">
              <option value="">全部考试</option>
              <option
                v-for="exam in data.exams"
                :key="exam.id"
                :value="exam.id"
              >
                {{ exam.name }}
              </option>
            </select></label
          ><label
            ><span>学校</span
            ><select v-model="reportingLedger.filters.school">
              <option value="">全部学校</option>
              <option
                v-for="school in admissionSchools"
                :key="school.id"
                :value="school.id"
              >
                {{ school.name }}
              </option>
            </select></label
          ><label
            ><span>状态</span
            ><select v-model="reportingLedger.filters.status">
              <option value="">全部状态</option>
              <option value="pending_approval">待审批</option>
              <option value="approved">已批准</option>
              <option value="rejected">已退回</option>
            </select></label
          >
        </div>
        <div class="ledger-bulk">
          <label
            ><input
              type="checkbox"
              @change="
                togglePageSelection(
                  reportingSelected,
                  reportingLedger.rows,
                  (item) => item.status === 'pending_approval',
                )
              "
            />
            选择当前页待审项</label
          ><strong>已选 {{ reportingSelected.length }} 条</strong
          ><button
            :disabled="!reportingSelected.length || busy"
            @click="bulkReporting(false)"
          >
            批量退回</button
          ><button
            :disabled="!reportingSelected.length || busy"
            @click="bulkReporting(true)"
          >
            批量批准
          </button>
        </div>
        <div class="table-scroll">
          <table>
            <thead>
              <tr>
                <th>选择</th>
                <th>考试 / 学校</th>
                <th>轮次</th>
                <th>报到统计</th>
                <th>学校决定</th>
                <th>状态</th>
                <th>审批</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="item in reportingLedger.rows" :key="item.id">
                <td>
                  <input
                    v-model="reportingSelected"
                    type="checkbox"
                    :value="item.id"
                  />
                </td>
                <td>
                  {{ item.examName }}<small>{{ item.schoolName }}</small>
                </td>
                <td>第 {{ item.payload?.round || 1 }} 轮</td>
                <td>
                  计划 {{ item.progress?.totalQuota }} · 报到
                  {{ item.progress?.reportedCount }} · 缺额
                  {{ item.progress?.reportingGap }}
                </td>
                <td>
                  {{
                    item.payload?.supplementDecision === "supplement"
                      ? "申请补录"
                      : "不补录"
                  }}<small>{{ item.payload?.decisionNote }}</small>
                </td>
                <td><StatusBadge :value="item.status" /></td>
                <td>
                  <div
                    v-if="item.status === 'pending_approval'"
                    class="row-decision"
                  >
                    <input
                      v-model="notes[item.id]"
                      placeholder="审批意见"
                    /><button @click="reviewReporting(item, false)">退回</button
                    ><button @click="reviewReporting(item, true)">批准</button>
                  </div>
                  <span v-else>{{ item.payload?.approvalNote }}</span>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
        <LedgerPager
          v-model:page="reportingLedger.page"
          v-model:page-size="reportingLedger.pageSize"
          :total="reportingLedger.total"
        />
      </section>
    </template>

    <template v-else-if="page === 'admission-supervision'">
      <section class="record-panel">
        <header>
          <div>
            <h2>投档与退档监督</h2>
            <p>
              筛选结果 {{ placementLedger.total }} / 共
              {{ data.placements?.length || 0 }} 条
            </p>
          </div>
          <a class="app-button" :href="exportUrl('placements', placementLedger)"
            >导出当前筛选结果</a
          >
        </header>
        <div class="ledger-toolbar ledger-toolbar--wide">
          <label
            ><span>关键词</span
            ><input
              v-model="placementLedger.query"
              placeholder="考生、报名号、学校、类别" /></label
          ><label
            ><span>考试</span
            ><select v-model="placementLedger.filters.exam">
              <option value="">全部考试</option>
              <option
                v-for="exam in data.exams"
                :key="exam.id"
                :value="exam.id"
              >
                {{ exam.name }}
              </option>
            </select></label
          ><label
            ><span>投档学校</span
            ><select v-model="placementLedger.filters.school">
              <option value="">全部学校</option>
              <option
                v-for="school in admissionSchools"
                :key="school.id"
                :value="school.id"
              >
                {{ school.name }}
              </option>
            </select></label
          ><label
            ><span>状态</span
            ><select v-model="placementLedger.filters.status">
              <option value="">全部状态</option>
              <option
                v-for="status in placementStatuses"
                :key="status"
                :value="status"
              >
                {{ status }}
              </option>
            </select></label
          >
        </div>
        <div class="ledger-bulk">
          <label
            ><input
              type="checkbox"
              @change="
                togglePageSelection(placementSelected, placementLedger.rows)
              "
            />
            选择当前页</label
          ><strong>已选 {{ placementSelected.length }} 条</strong
          ><button
            :disabled="!placementSelected.length || busy"
            @click="bulkWithdrawals(false)"
          >
            批量驳回退档</button
          ><button
            :disabled="!placementSelected.length || busy"
            @click="bulkWithdrawals(true)"
          >
            批量批准退档</button
          ><button
            :disabled="!placementSelected.length"
            @click="exportAdmissionSelected('placements', placementSelected)"
          >
            导出选中项 XLSX
          </button>
        </div>
        <div class="table-scroll">
          <table>
            <thead>
              <tr>
                <th>选择</th>
                <th>考生</th>
                <th>考试 / 分数</th>
                <th>投档学校</th>
                <th>类别 / 志愿</th>
                <th>状态</th>
                <th>退档审批</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="item in placementLedger.rows" :key="item.id">
                <td>
                  <input
                    v-model="placementSelected"
                    type="checkbox"
                    :value="item.id"
                  />
                </td>
                <td>
                  {{ item.candidate?.name
                  }}<small>{{ item.candidate?.registrationNumber }}</small>
                </td>
                <td>
                  {{ item.examName
                  }}<small>{{ item.payload?.totalScore }} 分</small>
                </td>
                <td>{{ item.schoolName }}</td>
                <td>
                  {{ item.payload?.categoryName }} · 第
                  {{ item.payload?.preferenceOrder }} 志愿
                </td>
                <td><StatusBadge :value="item.status" /></td>
                <td>
                  <div
                    v-if="item.status === 'withdrawal_pending'"
                    class="row-decision"
                  >
                    <input
                      v-model="notes[item.id]"
                      :placeholder="
                        item.payload?.withdrawalReason || '审批意见'
                      "
                    /><button
                      @click="
                        act(
                          () => reviewWithdrawal(item, false),
                          '退档申请已驳回',
                        )
                      "
                    >
                      驳回</button
                    ><button
                      @click="
                        act(
                          () => reviewWithdrawal(item, true),
                          '退档申请已批准',
                        )
                      "
                    >
                      批准
                    </button>
                  </div>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
        <LedgerPager
          v-model:page="placementLedger.page"
          v-model:page-size="placementLedger.pageSize"
          :total="placementLedger.total"
        />
      </section>

      <section class="record-panel">
        <header>
          <div>
            <h2>考生志愿实时快照</h2>
            <p>
              筛选结果 {{ preferenceLedger.total }} / 共
              {{ data.preferenceRows?.length || 0 }} 人；只读监督
            </p>
          </div>
          <a
            class="app-button"
            :href="exportUrl('preferences', preferenceLedger)"
            >导出当前筛选结果</a
          >
        </header>
        <div class="ledger-toolbar ledger-toolbar--wide">
          <label
            ><span>关键词</span
            ><input
              v-model="preferenceLedger.query"
              placeholder="考生、报名号、生源校、志愿学校" /></label
          ><label
            ><span>考试</span
            ><select v-model="preferenceLedger.filters.exam">
              <option value="">全部考试</option>
              <option
                v-for="exam in data.exams"
                :key="exam.id"
                :value="exam.id"
              >
                {{ exam.name }}
              </option>
            </select></label
          ><label
            ><span>生源学校</span
            ><select v-model="preferenceLedger.filters.school">
              <option value="">全部学校</option>
              <option
                v-for="school in sourceSchools"
                :key="school"
                :value="school"
              >
                {{ school }}
              </option>
            </select></label
          ><label
            ><span>填报状态</span
            ><select v-model="preferenceLedger.filters.status">
              <option value="">全部状态</option>
              <option
                v-for="status in preferenceStatuses"
                :key="status"
                :value="status"
              >
                {{ status }}
              </option>
            </select></label
          >
        </div>
        <div class="ledger-bulk">
          <label
            ><input
              type="checkbox"
              @change="
                togglePageSelection(preferenceSelected, preferenceLedger.rows)
              "
            />
            选择当前页</label
          ><strong>已选 {{ preferenceSelected.length }} 人</strong
          ><span>志愿快照为只读数据，不允许批量改写</span
          ><button
            :disabled="!preferenceSelected.length"
            @click="exportAdmissionSelected('preferences', preferenceSelected)"
          >
            导出选中项 XLSX
          </button>
        </div>
        <div class="table-scroll">
          <table>
            <thead>
              <tr>
                <th>选择</th>
                <th>考生 / 报名号</th>
                <th>考试 / 生源校</th>
                <th>轮次 / 状态</th>
                <th>志愿顺序</th>
                <th>提交次数</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="item in preferenceLedger.rows" :key="item.id">
                <td>
                  <input
                    v-model="preferenceSelected"
                    type="checkbox"
                    :value="item.id"
                  />
                </td>
                <td>
                  {{ item.candidate?.name
                  }}<small>{{ item.candidate?.registrationNumber }}</small>
                </td>
                <td>
                  {{ item.examName }}<small>{{ item.sourceSchoolName }}</small>
                </td>
                <td>第 {{ item.round }} 轮 · {{ item.fillStatus }}</td>
                <td>
                  <span
                    v-for="(choice, index) in item.choices"
                    :key="index"
                    class="table-stack"
                    >{{
                      choice.preferenceType === "indicator" ? "指标" : index + 1
                    }}
                    · {{ choice.schoolName }} · {{ choice.categoryName }}</span
                  >
                </td>
                <td>{{ item.submissionCount }} / {{ item.maxSubmissions }}</td>
              </tr>
            </tbody>
          </table>
        </div>
        <LedgerPager
          v-model:page="preferenceLedger.page"
          v-model:page-size="preferenceLedger.pageSize"
          :total="preferenceLedger.total"
        />
      </section>
    </template>
  </div>
</template>
