| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791 |
- <template>
- <div class="page-fill insurance-match-view">
- <PagePanel :title="panelTitle">
- <template #extra>
- <el-button
- :loading="exporting"
- :disabled="!canExport"
- @click="onExport"
- >
- 导出结果
- </el-button>
- <el-button
- v-if="!isHistoryTab"
- type="primary"
- :loading="matching"
- :disabled="!selectedBatches.length || matching"
- @click="onBatchMatch"
- >
- 批量匹配
- </el-button>
- </template>
- <p class="page-tip">
- <template v-if="isAdmin && isHistoryTab">
- 已提交领导及之后的各镇居保结果,只读。请按街镇筛选。
- </template>
- <template v-else-if="isHistoryTab">
- 已提交领导及之后的本镇居保结果,只读,不可再次匹配。
- </template>
- <template v-else-if="isAdmin">
- 每月 1 号全区月批生成后自动居保。本页按街镇查看匹配结果;失败须由对应镇社区事务人工确认后才能提交该镇月度清单。
- </template>
- <template v-else>
- 核验全区当月批次的本镇人员。失败须在本页人工确认后,才能提交月度清单;已匹配完成的不会被全选勾中。
- </template>
- </p>
- <el-tabs v-model="activeTab" @tab-change="onTabChange">
- <el-tab-pane label="待办理" name="todo" />
- <el-tab-pane label="历史记录" name="history" />
- </el-tabs>
- <div class="query-panel insurance-match-view__filter">
- <el-form :inline="true" size="small">
- <el-form-item v-if="isAdmin" label="街镇">
- <el-select
- v-model="filterTown"
- placeholder="全部"
- clearable
- style="width: 140px"
- @change="onTownChange"
- >
- <el-option v-for="t in townOptions" :key="t" :label="t" :value="t" />
- </el-select>
- </el-form-item>
- <el-form-item label="村居">
- <el-select v-model="filterVillage" placeholder="全部" clearable style="width: 140px">
- <el-option v-for="v in villageOptions" :key="v" :label="v" :value="v" />
- </el-select>
- </el-form-item>
- <el-form-item label="批次号">
- <el-input
- v-model="filterBatchNo"
- placeholder="如 202608"
- clearable
- style="width: 130px"
- @keyup.enter="applyFilter"
- />
- </el-form-item>
- <el-form-item label="流转状态">
- <el-select v-model="filterStage" placeholder="全部" clearable style="width: 150px">
- <el-option v-for="s in stageOptions" :key="s" :label="s" :value="s" />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" @click="applyFilter">查询</el-button>
- <el-button @click="resetFilter">重置</el-button>
- </el-form-item>
- </el-form>
- </div>
- <div class="page-fill__table">
- <el-table
- ref="tableRef"
- v-loading="batchLoading"
- :data="pagedBatches"
- border
- stripe
- size="small"
- height="100%"
- row-key="id"
- @selection-change="onSelectionChange"
- >
- <el-table-column
- v-if="!isHistoryTab"
- type="selection"
- width="42"
- align="center"
- :selectable="isBatchSelectable"
- />
- <el-table-column prop="batchNo" label="统一批次号" width="100" align="center" />
- <el-table-column prop="town" label="街镇" width="90" />
- <el-table-column label="范围" width="110">
- <template #default="{ row }">
- <el-button
- v-if="canViewMatchResult(row as VillageBatch)"
- link
- type="primary"
- @click="openVillageResult(row as VillageBatch)"
- >
- {{ isDistrictBatch(row as VillageBatch) && scopedTownName() ? '本镇' : row.village }}
- </el-button>
- <span v-else>{{ row.village }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="peopleCount" label="人数" width="72" align="center" />
- <el-table-column label="预计金额(元)" width="120" align="right">
- <template #default="{ row }">{{ formatAmount(row.totalAmount) }}</template>
- </el-table-column>
- <el-table-column label="流转状态" width="130" align="center">
- <template #default="{ row }">
- <StatusTag :status="row.stage" />
- </template>
- </el-table-column>
- <el-table-column prop="submitter" label="提交人" width="110" />
- <el-table-column prop="submittedAt" label="提交时间" min-width="140" />
- <el-table-column label="操作" width="320" align="center" fixed="right">
- <template #default="{ row }">
- <el-button
- link
- type="primary"
- size="small"
- @click="openBatchDrawer(row as VillageBatch, 'detail')"
- >
- 批次详情
- </el-button>
- <el-button
- link
- type="primary"
- size="small"
- @click="openBatchDrawer(row as VillageBatch, 'flow')"
- >
- 流程记录
- </el-button>
- <el-button
- v-if="row.stage === '居保状态匹配'"
- link
- type="success"
- size="small"
- :loading="matching"
- :disabled="matching"
- @click="onMatchOne(row as VillageBatch)"
- >
- 匹配
- </el-button>
- <el-button
- v-else-if="canViewMatchResult(row as VillageBatch)"
- link
- type="success"
- size="small"
- @click="openVillageResult(row as VillageBatch)"
- >
- 匹配结果
- </el-button>
- <el-button
- v-if="canViewMatchResult(row as VillageBatch)"
- link
- type="primary"
- size="small"
- :loading="exportingBatchId === row.id"
- @click="onExportBatch(row as VillageBatch)"
- >
- 导出
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- <TablePagination
- v-model:page="batchPage"
- v-model:page-size="batchPageSize"
- :total="batchTotal"
- />
- </PagePanel>
- <!-- 可研 5.1.4.1:任务态 / 失败清单 / 执行日志 -->
- <PagePanel v-if="lastTaskSummary || taskLogs.length" title="居保匹配任务执行情况">
- <p class="insurance-match-view__tip">
- 最近一次匹配的人数汇总、待人工处理名单与执行日志。
- </p>
- <div v-if="lastTaskSummary" class="insurance-match-view__task-summary">
- <el-tag type="info" effect="plain">
- 批次号 {{ taskBatchNoLabel }}
- </el-tag>
- <el-tag type="success" effect="plain">成功 {{ lastTaskSummary.successCount ?? 0 }} 人</el-tag>
- <el-tag type="danger" effect="plain">失败 {{ lastTaskSummary.failCount ?? 0 }} 人</el-tag>
- <el-tag type="warning" effect="plain">待确认 {{ lastTaskSummary.manualCount ?? 0 }} 人</el-tag>
- <el-tag effect="plain">
- 批次下一节点 {{ displayBizText(String(lastTaskSummary.nextStatus || '')) }}
- </el-tag>
- </div>
- <el-table
- v-if="(lastTaskSummary?.failItems as Record<string, unknown>[] | undefined)?.length"
- :data="(lastTaskSummary?.failItems as Record<string, unknown>[]) || []"
- border
- stripe
- size="small"
- max-height="220"
- style="margin: 10px 0"
- >
- <el-table-column prop="name" label="姓名" width="100" />
- <el-table-column label="身份证" min-width="160">
- <template #default="{ row }">{{ maskIdCard(String(row.idNumber || '')) }}</template>
- </el-table-column>
- <el-table-column label="匹配结果" width="120">
- <template #default="{ row }">
- {{ labelOf('insuranceMatch', String(row.matchResult || '')) || '—' }}
- </template>
- </el-table-column>
- <el-table-column prop="message" label="失败/待确认原因" min-width="220" show-overflow-tooltip />
- </el-table>
- <el-table
- v-loading="taskLogLoading"
- :data="taskLogs"
- border
- stripe
- size="small"
- max-height="220"
- >
- <el-table-column label="办理动作" width="140">
- <template #default="{ row }">
- {{ processActionLabelOf(String(row.action || '')) }}
- </template>
- </el-table-column>
- <el-table-column prop="operator" label="操作人" width="120" />
- <el-table-column label="结果" width="90">
- <template #default="{ row }">
- {{ resultLabelOf(String(row.result || '')) }}
- </template>
- </el-table-column>
- <el-table-column prop="opinion" label="摘要" min-width="240" show-overflow-tooltip />
- <el-table-column label="时间" width="160">
- <template #default="{ row }">
- {{ formatTaskTime(row.operateTime) }}
- </template>
- </el-table-column>
- </el-table>
- </PagePanel>
- <BatchDetailDrawer
- v-model="batchDrawerVisible"
- :batch-id="batchDrawerId"
- :initial-tab="batchDrawerTab"
- />
- <!-- 各村人员居保匹配结果弹窗 -->
- <el-dialog
- v-model="resultDialogVisible"
- :title="resultDialogTitle"
- width="900px"
- destroy-on-close
- @closed="onResultDialogClosed"
- >
- <el-table v-loading="resultLoading" :data="pagedResults" border stripe size="small" max-height="460">
- <el-table-column prop="name" label="姓名" width="80" />
- <el-table-column label="身份证" min-width="160">
- <template #default="{ row }">{{ maskIdCard(row.idCard) }}</template>
- </el-table-column>
- <el-table-column prop="town" label="街镇" width="90" />
- <el-table-column prop="village" label="村居" width="90" />
- <el-table-column label="居保状态" width="110" align="center">
- <template #default="{ row }">
- <StatusTag :status="row.insuranceStatus" />
- </template>
- </el-table-column>
- <el-table-column label="人员状态" width="110" align="center">
- <template #default="{ row }">
- <StatusTag :status="row.status" />
- </template>
- </el-table-column>
- <el-table-column prop="remark" label="备注" min-width="140" show-overflow-tooltip />
- <el-table-column label="操作" width="180" align="center" fixed="right">
- <template #default="{ row }">
- <el-button
- v-if="!isHistoryTab && row.insuranceStatus !== '匹配通过'"
- link
- type="primary"
- size="small"
- @click="openManualConfirm(row as Person)"
- >
- 人工确认
- </el-button>
- <el-button
- v-if="!isHistoryTab"
- link
- type="warning"
- size="small"
- :loading="rematchingId === String(row.id)"
- @click="onRematchOne(row as Person)"
- >
- 重新匹配
- </el-button>
- <span v-else-if="isHistoryTab && row.insuranceStatus === '匹配通过'" class="muted">已通过</span>
- </template>
- </el-table-column>
- </el-table>
- <TablePagination
- v-model:page="resultPage"
- v-model:page-size="resultPageSize"
- :total="resultTotal"
- />
- </el-dialog>
- <!-- 人工确认:继续发放 / 暂停发放 -->
- <el-dialog
- v-model="manualDialogVisible"
- title="居保匹配人工确认"
- width="480px"
- destroy-on-close
- @closed="onManualDialogClosed"
- >
- <template v-if="manualTarget">
- <p class="insurance-match-view__tip">
- 人员:{{ manualTarget.name }}({{ maskIdCard(manualTarget.idCard) }})
- </p>
- <p v-if="manualTarget.remark" class="insurance-match-view__match-msg">
- 最近匹配说明:{{ manualTarget.remark }}
- </p>
- <el-form label-width="80px" size="small">
- <el-form-item label="确认备注">
- <el-input
- v-model="manualRemark"
- type="textarea"
- :rows="3"
- maxlength="200"
- show-word-limit
- placeholder="请填写人工确认说明"
- />
- </el-form-item>
- </el-form>
- </template>
- <template #footer>
- <el-button @click="manualDialogVisible = false">取消</el-button>
- <el-button type="warning" :loading="manualSaving" @click="submitManualConfirm(false)">
- 暂停发放
- </el-button>
- <el-button type="success" :loading="manualSaving" @click="submitManualConfirm(true)">
- 继续发放
- </el-button>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup lang="ts">
- import { computed, onMounted, ref, watch } from 'vue'
- import { ElMessage } from 'element-plus'
- import type { TableInstance } from 'element-plus'
- import PagePanel from '@/components/common/PagePanel.vue'
- import StatusTag from '@/components/common/StatusTag.vue'
- import TablePagination from '@/components/common/TablePagination.vue'
- import {
- confirmInsuranceManual,
- exportInsuranceMatch,
- fetchInsuranceBatchesPage,
- fetchInsuranceResultsPage,
- fetchInsuranceTaskLogs,
- triggerInsuranceMatch,
- } from '@/api/biz'
- import { useServerPagination } from '@/composables/useServerPagination'
- import { useTownVillageOptions } from '@/composables/useTownVillageOptions'
- import { guardBusy, runSubmit } from '@/composables/useSubmitLock'
- import { useUserStore } from '@/stores/user'
- import BatchDetailDrawer from '@/components/biz/BatchDetailDrawer.vue'
- import { maskIdCard, formatAmount } from '@/utils/mask'
- import {
- displayBizText,
- labelOf,
- processActionLabelOf,
- resultLabelOf,
- } from '@/utils/statusLabels'
- import type { Person, VillageBatch } from '@/types/biz'
- import { resolveScopeIds } from '@/api/sjnmtybt/regionStore'
- const userStore = useUserStore()
- const isAdmin = computed(() => userStore.roleInfo?.key === 'admin')
- const {
- filterTown,
- filterVillage,
- townOptions,
- villageOptions,
- onTownChange,
- resetTownVillage,
- loadVillages,
- } = useTownVillageOptions()
- const activeTab = ref('todo')
- const isHistoryTab = computed(() => activeTab.value === 'history')
- const filterBatchNo = ref('')
- const filterStage = ref('')
- const panelTitle = computed(() =>
- isHistoryTab.value ? '居保匹配历史记录' : '全区月批居保匹配(本镇切片)',
- )
- const stageOptions = computed(() =>
- isHistoryTab.value
- ? ['分管领导审批', '待线下发放', '回盘信息确认', '已回盘确认', '已归档']
- : ['居保状态匹配', '比对结果已生成'],
- )
- const resultLoading = computed(() => resultPagerLoading.value)
- const matching = ref(false)
- const rematchingId = ref('')
- const exporting = ref(false)
- const exportingBatchId = ref('')
- const selectedBatches = ref<VillageBatch[]>([])
- const tableRef = ref<TableInstance>()
- const canExport = computed(() => {
- if (selectedBatches.value.length === 1) return true
- if (isAdmin.value) return !!filterTown.value
- return !!userStore.roleInfo?.town
- })
- const resultDialogVisible = ref(false)
- const currentBatch = ref<VillageBatch | null>(null)
- const batchDrawerVisible = ref(false)
- const batchDrawerId = ref('')
- const batchDrawerTab = ref('detail')
- const manualDialogVisible = ref(false)
- const manualTarget = ref<Person | null>(null)
- const manualRemark = ref('')
- const manualSaving = ref(false)
- const lastTaskSummary = ref<Record<string, unknown> | null>(null)
- const taskLogs = ref<Record<string, unknown>[]>([])
- const taskLogLoading = ref(false)
- /** 任务摘要展示批次号(禁止直接渲染内部 batchId) */
- const taskBatchNoLabel = computed(() => {
- const id = String(lastTaskSummary.value?.batchId || '')
- if (!id) return '—'
- const hit = batches.value.find((b) => b.id === id)
- return hit?.batchNo || id.replace(/^VB/, '')
- })
- function formatTaskTime(ts: unknown) {
- const n = Number(ts)
- if (!n) return '—'
- const d = new Date(n)
- if (Number.isNaN(d.getTime())) return '—'
- const p = (x: number) => String(x).padStart(2, '0')
- return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`
- }
- async function loadTaskLogs(batchId: string) {
- if (!batchId) {
- taskLogs.value = []
- return
- }
- taskLogLoading.value = true
- try {
- taskLogs.value = await fetchInsuranceTaskLogs(batchId)
- } catch {
- taskLogs.value = []
- } finally {
- taskLogLoading.value = false
- }
- }
- function openBatchDrawer(row: VillageBatch, tab: 'detail' | 'flow' = 'detail') {
- if (!row.id) return
- batchDrawerId.value = row.id
- batchDrawerTab.value = tab
- batchDrawerVisible.value = true
- }
- const resultDialogTitle = computed(() => {
- const b = currentBatch.value
- if (!b) return '人员居保匹配情况'
- const town = scopedTownName()
- if (town) return `${town}(批次 ${b.batchNo})本镇居保匹配`
- return `全区(批次 ${b.batchNo})居保匹配情况`
- })
- /** 非管理员必须用当前角色街镇;管理员用筛选街镇。全区月批本身没有街镇字段。 */
- function scopedTownName() {
- if (isAdmin.value) return filterTown.value || ''
- return userStore.roleInfo?.town || ''
- }
- function isDistrictBatch(b: VillageBatch) {
- return b.batchLevel === 'DISTRICT' || b.village === '全区' || (!b.town && !b.village)
- }
- const {
- page: batchPage,
- pageSize: batchPageSize,
- total: batchTotal,
- list: pagedBatches,
- loading: batchLoading,
- resetAndLoad: loadBatches,
- } = useServerPagination<VillageBatch>(async (pageNum, pageSize) => {
- selectedBatches.value = []
- const townName = isAdmin.value ? filterTown.value || '' : scopedTownName()
- const { townId } = await resolveScopeIds(townName || undefined, undefined)
- return fetchInsuranceBatchesPage({
- tab: isHistoryTab.value ? 'history' : 'todo',
- batchNo: filterBatchNo.value.trim() || undefined,
- stage: filterStage.value || undefined,
- townId: townId || undefined,
- pageNum,
- pageSize,
- })
- })
- const batches = pagedBatches
- const {
- page: resultPage,
- pageSize: resultPageSize,
- total: resultTotal,
- list: pagedResults,
- loading: resultPagerLoading,
- resetAndLoad: loadResultPage,
- } = useServerPagination<Person>(async (pageNum, pageSize) => {
- const row = currentBatch.value
- if (!row) return { list: [], total: 0 }
- return fetchInsuranceResultsPage({
- batchId: row.id,
- batchNo: row.batchNo,
- town: scopedTownName() || undefined,
- village: filterVillage.value || undefined,
- pageNum,
- pageSize,
- })
- })
- function applyFilter() {
- void loadBatches()
- }
- function resetFilter() {
- filterBatchNo.value = ''
- filterStage.value = ''
- if (isAdmin.value) {
- resetTownVillage()
- } else {
- filterVillage.value = ''
- }
- void loadBatches()
- }
- async function syncScopeTown() {
- const town = userStore.roleInfo?.town
- if (!isAdmin.value && town) {
- filterTown.value = town
- await loadVillages(town)
- }
- }
- /** 已匹配完成的村不可勾选,全选时也不会被选中 */
- function isBatchSelectable(row: VillageBatch) {
- return row.stage === '居保状态匹配'
- }
- function canViewMatchResult(row: VillageBatch) {
- return row.stage !== '居保状态匹配'
- }
- function onSelectionChange(rows: VillageBatch[]) {
- selectedBatches.value = rows
- }
- async function onBatchMatch() {
- const ids = selectedBatches.value
- .filter((b) => b.stage === '居保状态匹配')
- .map((b) => b.id)
- if (!ids.length) {
- ElMessage.warning('请先勾选待匹配的村居')
- return
- }
- if (guardBusy(matching)) return
- matching.value = true
- try {
- const res = (await triggerInsuranceMatch(ids)) as {
- ok?: boolean
- count?: number
- lastSummary?: Record<string, unknown> | null
- }
- if (res?.lastSummary) {
- lastTaskSummary.value = res.lastSummary
- await loadTaskLogs(String(res.lastSummary.batchId || ids[ids.length - 1]))
- }
- const fail = Number(res?.lastSummary?.failCount || 0)
- const countTip = typeof res?.count === 'number' ? `(${res.count} 个村)` : ''
- ElMessage.success(
- fail > 0
- ? `居保匹配完成${countTip},存在 ${fail} 人失败/待确认,请查看下方任务清单`
- : `已完成居保匹配${countTip},比对结果清单已生成`,
- )
- selectedBatches.value = []
- tableRef.value?.clearSelection()
- await loadBatches()
- } finally {
- matching.value = false
- }
- }
- async function onMatchOne(row: VillageBatch) {
- await runSubmit(matching, async () => {
- const res = (await triggerInsuranceMatch(row.id)) as {
- lastSummary?: Record<string, unknown> | null
- }
- if (res?.lastSummary) {
- lastTaskSummary.value = res.lastSummary
- }
- await loadTaskLogs(row.id)
- const fail = Number(res?.lastSummary?.failCount || 0)
- ElMessage.success(
- fail > 0
- ? `${row.village}匹配完成,有 ${fail} 人需处理`
- : `${row.village}比对结果清单已生成`,
- )
- await loadBatches()
- })
- }
- async function openVillageResult(row: VillageBatch) {
- currentBatch.value = row
- resultDialogVisible.value = true
- await Promise.all([loadVillageResults(row), loadTaskLogs(row.id)])
- }
- async function loadVillageResults(row: VillageBatch) {
- currentBatch.value = row
- await loadResultPage()
- }
- function onResultDialogClosed() {
- currentBatch.value = null
- }
- function openManualConfirm(row: Person) {
- manualTarget.value = row
- manualRemark.value = row.remark || ''
- manualDialogVisible.value = true
- }
- function onManualDialogClosed() {
- manualTarget.value = null
- manualRemark.value = ''
- }
- async function submitManualConfirm(pass: boolean) {
- if (!manualTarget.value) return
- if (guardBusy(manualSaving)) return
- manualSaving.value = true
- try {
- await confirmInsuranceManual(manualTarget.value.id, {
- batchId: currentBatch.value?.id,
- pass,
- remark: manualRemark.value.trim() || undefined,
- })
- ElMessage.success(
- pass
- ? '已确认继续发放。全部处理完后请到「月补贴清单」提交分管领导审核'
- : '已确认暂停发放',
- )
- manualDialogVisible.value = false
- if (currentBatch.value) {
- await loadVillageResults(currentBatch.value)
- }
- } finally {
- manualSaving.value = false
- }
- }
- async function onRematchOne(row: Person) {
- if (!currentBatch.value?.id) return
- if (guardBusy(matching)) return
- rematchingId.value = String(row.id)
- matching.value = true
- try {
- await triggerInsuranceMatch(currentBatch.value.id, String(row.id))
- ElMessage.success(`${row.name || '该人员'}已重新匹配`)
- await loadVillageResults(currentBatch.value)
- } finally {
- rematchingId.value = ''
- matching.value = false
- }
- }
- async function onExportBatch(row: VillageBatch) {
- if (!row.id) return
- if (guardBusy(exportingBatchId)) return
- exportingBatchId.value = row.id
- try {
- const res = await exportInsuranceMatch({
- batchId: row.id,
- town: scopedTownName() || undefined,
- })
- if (!res?.ok) {
- ElMessage.warning(res?.message || '导出失败')
- return
- }
- ElMessage.success(`已导出 ${res.fileName || '居保匹配结果'}`)
- } finally {
- exportingBatchId.value = ''
- }
- }
- async function onExport() {
- if (selectedBatches.value.length === 1) {
- await onExportBatch(selectedBatches.value[0])
- return
- }
- const town = isAdmin.value ? filterTown.value : userStore.roleInfo?.town
- if (!town) {
- ElMessage.warning(isAdmin.value ? '请先选择街镇,或勾选单个批次导出' : '未获取到当前街镇')
- return
- }
- if (guardBusy(exporting)) return
- exporting.value = true
- try {
- const res = await exportInsuranceMatch({ town })
- if (!res?.ok) {
- ElMessage.warning(res?.message || '导出失败')
- return
- }
- ElMessage.success(`已导出 ${res.fileName || '居保匹配结果'}`)
- } finally {
- exporting.value = false
- }
- }
- function onTabChange() {
- filterStage.value = ''
- tableRef.value?.clearSelection()
- loadBatches()
- }
- onMounted(async () => {
- await syncScopeTown()
- await loadBatches()
- })
- watch(
- () => userStore.currentRole,
- async () => {
- filterBatchNo.value = ''
- filterStage.value = ''
- if (isAdmin.value) resetTownVillage()
- else {
- filterVillage.value = ''
- await syncScopeTown()
- }
- await loadBatches()
- },
- )
- </script>
- <style scoped lang="less">
- .insurance-match-view__task-summary {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
- margin-bottom: 4px;
- }
- .insurance-match-view__tip {
- margin: 0 0 10px;
- font-size: 12px;
- color: @text-secondary;
- line-height: 1.5;
- }
- .insurance-match-view__filter {
- margin-bottom: 10px;
- padding: 8px 12px 0;
- }
- .muted {
- color: @text-secondary;
- font-size: 12px;
- }
- .insurance-match-view__match-msg {
- margin: 0 0 12px;
- padding: 8px 10px;
- font-size: 12px;
- line-height: 1.5;
- color: @text-regular;
- background: @table-header-bg;
- border-radius: @radius-sm;
- }
- </style>
|