<script setup>
import { computed, onMounted, reactive, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import PortalShell from '@/layouts/PortalShell.vue';
import PageState from '@/components/common/PageState.vue';
import StatusBadge from '@/components/common/StatusBadge.vue';
import { api } from '@/lib/api';
import { formatDate } from '@/lib/format';
import { uiStore } from '@/stores/ui';
import { specialtyCatalog, specialtyTypesFor } from '@/data/specialties';

const props = defineProps({ page: { type: String, required: true } });
const router = useRouter();
const loading = ref(true);
const saving = ref(false);
const error = ref('');
const data = ref({});
const search = ref('');
const statusFilter = ref('all');
const examFilter = ref('');
const selectedPlacements = ref([]);
const placementDrafts = reactive({});
const reportingDrafts = reactive({});
const scan = reactive({ examId: '', code: '', preview: null, status: 'reported', note: '' });
const planForm = reactive({ examId: '', note: '', categories: [] });
const templateForm = reactive({ examId: '', eyebrow: 'ADMISSION NOTICE', title: '录 取 通 知 书', body: '', footer: '', primaryColor: '#8d2028', accentColor: '#c9a45b' });

const meta = computed(() => ({
  dashboard: ['招生工作台', '查看本校计划完成率、报到进度和待办事项。'],
  plans: ['本校招生计划', '提交普通生、特长生计划及指标分配。'],
  placements: ['投档考生审核', '核对投档考生资料和当次成绩。'],
  reporting: ['考生报到', '暂存报到状态，支持 Excel 与通知书扫码核验。'],
  'notice-template': ['录取通知书模板', '设计本校录取通知书标题、正文与配色。']
}[props.page]));

const placements = computed(() => (data.value.placements || []).filter(item => {
  const text = `${item.candidate?.name || ''} ${item.candidate?.registrationNumber || ''} ${item.examName || ''} ${item.payload?.categoryName || ''} ${item.candidate?.specialtyLabel || ''}`.toLowerCase();
  return (!search.value || text.includes(search.value.toLowerCase())) && (statusFilter.value === 'all' || item.status === statusFilter.value) && (!examFilter.value || item.examId === examFilter.value);
}));
const placementExams = computed(() => [...new Map((data.value.placements || []).map(item => [item.examId, item.examName])).entries()]);
const selectedPending = computed(() => placements.value.filter(item => item.status === 'school_review' && selectedPlacements.value.includes(item.id)));
const previewBody = computed(() => templateForm.body.replaceAll('{{考生姓名}}', '张同学').replaceAll('{{考试名称}}', '示例考试').replaceAll('{{录取学校}}', data.value.school?.name || '本校').replaceAll('{{录取类别}}', '普通生'));

function emptyCategory() { return { name: '普通生', quota: '', kind: 'general', specialtyCategory: '', specialtyType: '', indicatorAllocations: [] }; }
function addCategory() { planForm.categories.push(emptyCategory()); }
function addAllocation(category) { category.indicatorAllocations.push({ sourceSchoolId: '', quota: '' }); }
function resetSpecialty(category) { category.specialtyCategory = ''; category.specialtyType = ''; }

async function load() {
  loading.value = true; error.value = ''; search.value = ''; statusFilter.value = 'all'; examFilter.value = ''; selectedPlacements.value = [];
  try {
    data.value = await api(`/api/admission/${props.page === 'dashboard' ? 'context' : props.page}`);
    hydrate();
  } catch (requestError) { error.value = requestError.message; }
  finally { loading.value = false; }
}

function hydrate() {
  if (props.page === 'plans') {
    planForm.examId = data.value.exams?.[0]?.id || '';
    planForm.note = '';
    planForm.categories = [emptyCategory()];
  }
  if (props.page === 'placements') for (const item of data.value.placements || []) placementDrafts[item.id] = { decision: 'accept', note: '' };
  if (props.page === 'reporting') for (const batch of data.value.batches || []) for (const row of batch.rows || []) reportingDrafts[row.placementId] = { status: row.status, note: row.note || '', selected: false };
  if (props.page === 'notice-template') Object.assign(templateForm, {
    examId: data.value.exams?.[0]?.id || '', eyebrow: data.value.template?.eyebrow || 'ADMISSION NOTICE',
    title: data.value.template?.title || '录 取 通 知 书', body: data.value.template?.body || '', footer: data.value.template?.footer || '',
    primaryColor: data.value.template?.primaryColor || '#8d2028', accentColor: data.value.template?.accentColor || '#c9a45b'
  });
}

async function act(action, success) {
  saving.value = true; error.value = '';
  try { await action(); if (success) uiStore.notify(success); await load(); }
  catch (requestError) { error.value = requestError.message; }
  finally { saving.value = false; }
}

function submitPlan() {
  const categories = planForm.categories.map((category, index) => ({
    code: `category_${index + 1}`, name: String(category.name).trim(), quota: Number(category.quota || 0), isSpecialty: category.kind === 'specialty',
    specialtyCategory: category.kind === 'specialty' ? category.specialtyCategory : '', specialtyType: category.kind === 'specialty' ? category.specialtyType : '',
    indicatorAllocations: category.indicatorAllocations.map(item => ({ sourceSchoolId: item.sourceSchoolId, quota: Number(item.quota || 0) })).filter(item => item.sourceSchoolId && item.quota > 0)
  })).filter(category => category.name && category.quota > 0);
  if (!categories.length) { error.value = '请至少添加一个有效招生类别'; return; }
  if (categories.some(category => category.isSpecialty && (!category.specialtyCategory || !category.specialtyType))) { error.value = '特长生类别必须填写特长大类和小类'; return; }
  act(() => api('/api/admission/plans', { method: 'POST', body: { examId: planForm.examId, note: planForm.note, categories } }), '招生计划已提交审核');
}

function reviewPlacement(item) {
  const draft = placementDrafts[item.id];
  if (draft.decision === 'withdraw' && draft.note.trim().length < 8) { error.value = '申请退档须填写至少 8 个字的特殊理由'; return; }
  act(() => api(`/api/admission/placements/${item.id}`, { method: 'PATCH', body: draft }), draft.decision === 'accept' ? '已接收投档考生' : '退档申请已提交');
}

function bulkPlacement(decision) {
  if (!selectedPending.value.length) { error.value = '请先选择待审核考生'; return; }
  let note = '';
  if (decision === 'withdraw') {
    note = window.prompt(`为所选 ${selectedPending.value.length} 名考生填写统一退档理由（至少 8 个字）`, '') || '';
    if (!note) return;
    if (note.trim().length < 8) { error.value = '退档理由至少需要 8 个字'; return; }
  } else if (!window.confirm(`确认接收所选 ${selectedPending.value.length} 名投档考生吗？`)) return;
  act(() => api('/api/admission/placements/bulk', { method: 'POST', body: { ids: selectedPending.value.map(item => item.id), decision, note } }), decision === 'accept' ? '批量接收完成' : '批量退档申请已提交');
}

function toggleFilteredPending(checked) {
  const ids = placements.value.filter(item => item.status === 'school_review').map(item => item.id);
  selectedPlacements.value = checked ? [...new Set([...selectedPlacements.value, ...ids])] : selectedPlacements.value.filter(id => !ids.includes(id));
}

function saveReporting(batch) {
  const rows = batch.rows.map(row => ({ placementId: row.placementId, status: reportingDrafts[row.placementId].status, note: reportingDrafts[row.placementId].note }));
  act(() => api('/api/admission/reporting/draft', { method: 'PUT', body: { examId: batch.exam.id, rows } }), '报到状态已暂存');
}
function applyReportingBulk(batch, status) {
  for (const row of batch.rows) if (reportingDrafts[row.placementId]?.selected) reportingDrafts[row.placementId].status = status;
}
function submitReporting(batch) {
  if (!window.confirm(`确认正式提交“${batch.exam.name}”全部报到情况吗？提交后将不能继续编辑。`)) return;
  act(() => api('/api/admission/reporting/submit', { method: 'POST', body: { examId: batch.exam.id } }), '报到情况已正式提交');
}
function submitDecision(batch, event) {
  const form = new FormData(event.currentTarget);
  act(() => api('/api/admission/reporting/decision', { method: 'POST', body: { examId: batch.exam.id, supplement: form.get('supplement') === 'true', decisionNote: form.get('decisionNote') } }), '学校补录决定已提交');
}
async function importReporting(batch, event) {
  const file = event.target.files?.[0]; if (!file) return;
  saving.value = true; error.value = '';
  try {
    const result = await api(`/api/admission/reporting/import?examId=${encodeURIComponent(batch.exam.id)}`, { method: 'POST', headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }, body: await file.arrayBuffer() });
    uiStore.notify('Excel 已导入暂存', `读取 ${result.count || 0} 行，更新 ${result.changedCount || 0} 人`); await load();
  } catch (requestError) { error.value = requestError.message; }
  finally { saving.value = false; event.target.value = ''; }
}
function verifyScan(batch) {
  scan.examId = batch.exam.id;
  act(async () => { scan.preview = await api('/api/admission/reporting/scan-preview', { method: 'POST', body: { code: scan.code, examId: batch.exam.id } }); }, '通知书核验通过');
}
async function saveScan() {
  saving.value = true; error.value = '';
  try {
    await api('/api/admission/reporting/scan', { method: 'POST', body: { examId: scan.examId, code: scan.code, status: scan.status, note: scan.note } });
    Object.assign(scan, { examId: '', code: '', preview: null, status: 'reported', note: '' }); uiStore.notify('扫码结果已暂存'); await load();
  } catch (requestError) { error.value = requestError.message; }
  finally { saving.value = false; }
}
function saveTemplate() { act(() => api('/api/admission/notice-template', { method: 'PUT', body: templateForm }), '录取通知书模板已保存'); }

watch(() => props.page, load);
onMounted(load);
</script>

<template>
  <PortalShell role="admission_school" :page="page" :title="meta[0]" :description="meta[1]">
    <PageState :loading="loading" :error="error" @retry="load">
      <template v-if="page === 'dashboard'">
        <section class="admission-command-banner"><div><span>ADMISSION OFFICE</span><h2>{{ data.school?.name }}</h2><p>学校只接收超级管理员正式投档的数据，不可查看考生完整志愿表。</p></div></section>
        <section class="admission-progress-grid"><article v-for="plan in data.plans" :key="plan.examId"><header><span>{{ plan.examName }}</span><strong>{{ plan.progress?.admissionRate || 0 }}%</strong></header><div><i :style="{ width: `${Math.min(100, plan.progress?.admissionRate || 0)}%` }"></i></div><p>计划 {{ plan.progress?.totalQuota || 0 }} 人 · 正式录取 {{ plan.progress?.finalCount || 0 }} 人 · 已报到 {{ plan.progress?.reportedCount || 0 }} 人</p><small>实际报到完成率 {{ plan.progress?.reportingRate || 0 }}%</small></article></section>
        <div class="admission-dashboard-grid"><section class="record-panel"><header><div><h2>本校工作入口</h2><p>{{ data.exams?.length || 0 }} 场考试已启用招生</p></div></header><button class="dashboard-row" @click="router.push('/admission/plans')"><b>计</b><span><strong>上传招生计划</strong><small>类别、特长资格与指标分配</small></span><i>→</i></button><button class="dashboard-row" @click="router.push('/admission/placements')"><b>审</b><span><strong>审核投档考生</strong><small>接收或申请特殊退档</small></span><i>→</i></button><button class="dashboard-row" @click="router.push('/admission/reporting')"><b>到</b><span><strong>登记考生报到</strong><small>台账、Excel 与通知书核验</small></span><i>→</i></button></section><section class="record-panel"><header><div><h2>系统通知</h2><p>{{ data.notifications?.length || 0 }} 条</p></div></header><button v-for="notice in data.notifications" :key="notice.id" class="dashboard-row" @click="router.push(`/announcements/${notice.id}`)"><time>{{ formatDate(notice.publishAt) }}</time><span><strong>{{ notice.title }}</strong></span><i>→</i></button></section></div>
      </template>

      <template v-else-if="page === 'plans'">
        <form class="business-form admission-plan-form" @submit.prevent="submitPlan"><header><div><p>PLAN SUBMISSION</p><h2>提交本校招生计划</h2><span>提交后由超级管理员审核；各类别指标合计不得超过该类别计划人数。</span></div></header><label><span>招生考试</span><select v-model="planForm.examId" required><option v-for="exam in data.exams" :key="exam.id" :value="exam.id">{{ exam.code }} · {{ exam.name }}</option></select></label><div class="plan-category-list"><article v-for="(category, categoryIndex) in planForm.categories" :key="categoryIndex" class="plan-category-card"><header><strong>招生类别 {{ categoryIndex + 1 }}</strong><button type="button" @click="planForm.categories.splice(categoryIndex, 1)">移除</button></header><div class="form-grid"><label><span>类别名称</span><input v-model="category.name" required placeholder="例如：普通生"></label><label><span>计划人数</span><input v-model="category.quota" type="number" min="1" required></label><label><span>类别性质</span><select v-model="category.kind" @change="resetSpecialty(category)"><option value="general">普通 / 政策类</option><option value="specialty">特长生</option></select></label><label v-if="category.kind === 'specialty'"><span>特长大类</span><select v-model="category.specialtyCategory" required @change="category.specialtyType = ''"><option value="">请选择</option><option v-for="item in specialtyCatalog" :key="item.code" :value="item.code">{{ item.name }}</option></select></label><label v-if="category.kind === 'specialty'"><span>特长项目</span><select v-model="category.specialtyType" required :disabled="!category.specialtyCategory"><option value="">请选择</option><option v-for="item in specialtyTypesFor(category.specialtyCategory)" :key="item[0]" :value="item[0]">{{ item[1] }}</option></select></label></div><section><header><div><strong>生源校指标</strong><small>仅填写需要定向分配的学校</small></div><button type="button" @click="addAllocation(category)">添加指标</button></header><div v-for="(allocation, allocationIndex) in category.indicatorAllocations" :key="allocationIndex" class="allocation-row"><select v-model="allocation.sourceSchoolId"><option value="">选择生源学校</option><option v-for="school in data.sourceSchools" :key="school.id" :value="school.id">{{ school.code }} · {{ school.name }}</option></select><input v-model="allocation.quota" type="number" min="1" placeholder="名额"><button type="button" @click="category.indicatorAllocations.splice(allocationIndex, 1)">移除</button></div></section></article></div><button class="app-button" type="button" @click="addCategory">＋ 添加招生类别</button><label><span>计划说明</span><textarea v-model="planForm.note" rows="3" placeholder="政策依据或补充说明"></textarea></label><button class="app-button app-button--primary" :disabled="saving">提交超级管理员审核</button></form>
        <section class="record-panel admission-plan-history"><header><div><h2>提交记录</h2><p>本校历次计划及实时完成率</p></div></header><div class="table-scroll"><table><thead><tr><th>考试</th><th>类别计划</th><th>完成进度</th><th>状态</th><th>审核意见</th></tr></thead><tbody><tr v-for="plan in data.plans" :key="plan.id"><td>{{ data.exams?.find(exam => exam.id === plan.examId)?.name || plan.examId }}</td><td><span v-for="category in plan.payload?.categories" :key="category.code" class="table-stack"><strong>{{ category.name }} {{ category.quota }} 人</strong><small>{{ category.isSpecialty ? '特长生' : '普通 / 政策类' }}</small></span></td><td><strong>{{ plan.progress?.admissionRate || 0 }}%</strong><small>录取 {{ plan.progress?.finalCount || 0 }} / {{ plan.progress?.totalQuota || 0 }}</small></td><td><StatusBadge :value="plan.status" /></td><td>{{ plan.payload?.reviewNote || '等待审核' }}</td></tr></tbody></table></div></section>
      </template>

      <template v-else-if="page === 'placements'">
        <section v-if="data.completedExams?.length" class="admission-export-bar"><div><span>FINAL ROSTER</span><strong>正式录取考生信息</strong><small>仅录取工作结束后开放下载。</small></div><select v-model="examFilter"><option value="">选择已完成考试</option><option v-for="exam in data.completedExams" :key="exam.id" :value="exam.id">{{ exam.name }}</option></select><a class="app-button app-button--primary" :href="`/api/admission/placements/export?examId=${encodeURIComponent(examFilter)}`" :class="{ disabled: !examFilter }">下载 Excel</a></section>
        <section class="record-panel ledger-panel"><header><div><h2>本校投档审核台账</h2><p>{{ data.placements?.filter(item => item.status === 'school_review').length || 0 }} 人待审核 / 共 {{ data.placements?.length || 0 }} 人</p></div></header><div class="ledger-toolbar"><input v-model="search" placeholder="搜索姓名、报名号、考试、类别或资格"><select v-model="examFilter"><option value="">全部考试</option><option v-for="([id, name]) in placementExams" :key="id" :value="id">{{ name }}</option></select><select v-model="statusFilter"><option value="all">全部状态</option><option value="school_review">待学校审核</option><option value="admitted">已接收</option><option value="withdrawal_pending">退档待审</option><option value="final">正式录取</option></select></div><div class="ledger-bulk"><label><input type="checkbox" @change="toggleFilteredPending($event.target.checked)">选择当前筛选结果中的待审核考生</label><strong>已选 {{ selectedPending.length }} 人</strong><button class="app-button" @click="bulkPlacement('withdraw')">批量申请退档</button><button class="app-button app-button--primary" @click="bulkPlacement('accept')">批量接收</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 placements" :key="item.id"><td><input v-model="selectedPlacements" type="checkbox" :value="item.id" :disabled="item.status !== 'school_review'"></td><td><strong>{{ item.candidate?.name }}</strong><small>{{ item.candidate?.registrationNumber }} · {{ item.candidate?.idNumberMasked }}</small><small>{{ item.examName }}</small></td><td>{{ item.candidate?.specialtyLabel || '普通生' }}<small>{{ item.candidate?.policyEligibility }}</small></td><td><span v-for="result in item.results" :key="result.subjectId" class="table-stack">{{ result.subjectName }} {{ result.score }}</span><strong>投档分 {{ item.payload?.totalScore }} · 特征分 {{ item.featureScore || 0 }}</strong></td><td>{{ item.payload?.categoryName }}<small>第 {{ item.payload?.preferenceOrder }} 志愿</small></td><td><StatusBadge :value="item.status" /></td><td><form v-if="item.status === 'school_review'" class="row-review-form" @submit.prevent="reviewPlacement(item)"><select v-model="placementDrafts[item.id].decision"><option value="accept">接收</option><option value="withdraw">申请退档</option></select><input v-model="placementDrafts[item.id].note" placeholder="退档理由至少 8 字"><button>确认</button></form><small v-else>{{ item.payload?.schoolDecisionNote || '已处理' }}</small></td></tr><tr v-if="!placements.length"><td colspan="7">没有符合条件的记录</td></tr></tbody></table></div></section>
      </template>

      <template v-else-if="page === 'reporting'">
        <section v-for="batch in data.batches" :key="`${batch.exam.id}-${batch.round}`" class="reporting-workbench"><header><div><span>{{ batch.exam.code }} · 第 {{ batch.round }} 轮</span><h2>{{ batch.exam.name }}</h2><p>计划 {{ batch.progress?.totalQuota }} 人，正式录取 {{ batch.progress?.finalCount }} 人，已报到 {{ batch.progress?.reportedCount }} 人。</p></div><strong>{{ batch.progress?.reportingRate || 0 }}%<small>计划报到完成率</small></strong></header><div class="reporting-stat-strip"><span>正式录取 <b>{{ batch.progress?.finalCount }}</b></span><span>已报到 <b>{{ batch.progress?.reportedCount }}</b></span><span>未报到 <b>{{ batch.progress?.notReportedCount }}</b></span><span>计划缺额 <b>{{ batch.progress?.reportingGap }}</b></span><StatusBadge :value="batch.status" /></div><section v-if="['draft','rejected'].includes(batch.status)" class="reporting-tools"><div><strong>Excel 批量维护</strong><small>导入只暂存，不会直接提交。</small><span><a class="app-button" :href="`/api/admission/reporting/export?examId=${encodeURIComponent(batch.exam.id)}`">导出 Excel</a><label class="app-button">导入暂存<input type="file" accept=".xlsx" hidden @change="importReporting(batch, $event)"></label></span></div><form @submit.prevent="verifyScan(batch)"><strong>通知书二维码核验</strong><small>粘贴 AN 防伪码或二维码链接，核对身份后再暂存。</small><input v-model="scan.code" required placeholder="AN 防伪码或二维码链接"><button class="app-button">核验</button></form></section><form v-if="scan.preview && scan.examId === batch.exam.id" class="scan-preview" @submit.prevent="saveScan"><header><div><span>NOTICE VERIFIED</span><h3>核对考生报到信息</h3></div><button type="button" @click="scan.preview = null">关闭</button></header><dl><div><dt>考生</dt><dd>{{ scan.preview.row?.name }}</dd></div><div><dt>报名号</dt><dd>{{ scan.preview.row?.candidateNumber }}</dd></div><div><dt>通知书</dt><dd>{{ scan.preview.row?.noticeNumber }}</dd></div><div><dt>录取类别</dt><dd>{{ scan.preview.row?.categoryName }}</dd></div></dl><select v-model="scan.status"><option value="reported">Y · 已报到</option><option value="not_reported">N · 未报到</option><option value="pending">P · 待确认</option></select><input v-model="scan.note" placeholder="报到备注"><button class="app-button app-button--primary">确认并暂存</button></form><form v-if="['draft','rejected'].includes(batch.status)" @submit.prevent="saveReporting(batch)"><div class="ledger-bulk"><strong>本轮报到台账</strong><button type="button" class="app-button" @click="applyReportingBulk(batch, 'reported')">所选设为已报到</button><button type="button" class="app-button" @click="applyReportingBulk(batch, 'not_reported')">所选设为未报到</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="row in batch.rows" :key="row.placementId"><td><input v-model="reportingDrafts[row.placementId].selected" type="checkbox"></td><td><strong>{{ row.name }}</strong><small>{{ row.candidateNumber }}</small></td><td><strong>{{ row.noticeNumber }}</strong><small>{{ row.categoryName }}</small></td><td><select v-model="reportingDrafts[row.placementId].status"><option value="pending">P · 待确认</option><option value="reported">Y · 已报到</option><option value="not_reported">N · 未报到</option></select></td><td><input v-model="reportingDrafts[row.placementId].note" placeholder="选填报到备注"></td></tr></tbody></table></div><footer><button class="app-button">暂存全部状态</button><button class="app-button app-button--primary" type="button" @click="submitReporting(batch)">正式提交报到情况</button></footer></form><form v-else-if="batch.status === 'submitted'" class="reporting-decision" @submit.prevent="submitDecision(batch, $event)"><div><strong>报到情况已提交</strong><p>请选择是否申请补录，学校决定将提交超级管理员审批。</p></div><select name="supplement"><option value="false">不进行补录</option><option value="true" :disabled="!batch.progress?.reportingGap">申请补录 {{ batch.progress?.reportingGap }} 人</option></select><input name="decisionNote" placeholder="补录原因或不补录说明"><button class="app-button app-button--primary">提交学校决定</button></form><div v-else class="form-callout"><strong>当前批次已锁定</strong><p>{{ batch.approvalNote || batch.decisionNote || '等待下一步处理' }}</p></div></section><div v-if="!data.batches?.length" class="page-state page-state--empty"><strong>暂无报到批次</strong><p>正式录取签发并开启报到后，本页会生成台账。</p></div>
      </template>

      <section v-else-if="page === 'notice-template'" class="notice-template-studio"><form class="business-form" @submit.prevent="saveTemplate"><p>TEMPLATE STUDIO</p><h2>模板设计</h2><span v-pre>正文支持：{{考生姓名}}、{{考试名称}}、{{录取学校}}、{{录取类别}}</span><label><span>适用考试</span><select v-model="templateForm.examId"><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="templateForm.eyebrow" maxlength="60"></label><label><span>中文主标题</span><input v-model="templateForm.title" maxlength="80" required></label></div><label><span>通知书正文</span><textarea v-model="templateForm.body" rows="9" maxlength="1600" required></textarea></label><label><span>页脚说明</span><textarea v-model="templateForm.footer" rows="3" maxlength="300"></textarea></label><div class="form-grid"><label><span>学校主色</span><input v-model="templateForm.primaryColor" type="color"></label><label><span>强调色</span><input v-model="templateForm.accentColor" type="color"></label></div><button class="app-button app-button--primary" :disabled="saving">保存并启用模板</button></form><article class="notice-template-preview" :style="{ '--template-primary': templateForm.primaryColor, '--template-accent': templateForm.accentColor }"><div><small>{{ templateForm.eyebrow }}</small><h2>{{ templateForm.title }}</h2><h3>{{ data.school?.name }}</h3><em>通知书编号：AD01-EX-2026-ZK-000001</em><strong>张同学：</strong><p>{{ previewBody }}</p><footer><span>{{ templateForm.footer }}</span><b>{{ data.school?.name }}</b></footer><i>防伪二维码</i></div><p>右侧为 A4 通知书预览；正式件会自动写入编号、防伪查询码与二维码。</p></article></section>
    </PageState>
  </PortalShell>
</template>
