| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- /**
- * 后端 VO ↔ 新前端页面展示模型映射(不新增页面字段,只做值转换)
- */
- import type {
- AlertItem,
- DiskFailPerson,
- DiskRecord,
- Person,
- ProcessLogItem,
- SpecialBiz,
- SubsidyStandard,
- VillageBatch,
- VillageMonthlyBatch,
- } from '@/types/biz'
- import { regionName } from './regionStore'
- /** 后端批次 status → 前端 VillageBatch.stage(页面流程文案) */
- const BATCH_STATUS_TO_STAGE: Record<string, string> = {
- DRAFT: '人员新增录入',
- PENDING_TOWN_APPROVE: '镇经发中心初审',
- PENDING_INSURANCE_MATCH: '居保状态匹配',
- PENDING_STATUS_MAINTAIN: '比对结果已生成',
- PENDING_LEADER_APPROVE: '分管领导审批',
- READY_EXPORT: '待线下发放',
- EXPORTED: '回盘信息确认',
- RETURNED: '已回盘确认',
- ARCHIVED: '已归档',
- REJECTED: '退回修改',
- }
- /** 后端 status → 月补贴清单展示 status */
- const BATCH_STATUS_TO_MONTHLY: Record<string, string> = {
- PENDING_STATUS_MAINTAIN: '待提交',
- PENDING_LEADER_APPROVE: '待审核',
- READY_EXPORT: '已审核',
- EXPORTED: '已出盘',
- RETURNED: '已回盘',
- ARCHIVED: '已回盘',
- }
- const PERSON_STATUS_LABEL: Record<string, string> = {
- DRAFT: '草稿',
- PENDING_TOWN_APPROVE: '待镇审批',
- PENDING_INSURANCE_MATCH: '待居保匹配',
- NORMAL: '正常在库',
- PAUSED: '暂停',
- STOPPED: '停止',
- FUNERAL: '死亡丧葬',
- ABNORMAL: '异常待处理',
- ARCHIVED: '已归档',
- }
- const INSURANCE_LABEL: Record<string, string> = {
- PENDING: '未匹配',
- SUCCESS: '匹配通过',
- LOSE_ELIGIBILITY: '丧失资格',
- FAIL: '匹配失败',
- MANUAL_PASS: '匹配通过',
- }
- const ALERT_STATUS_LABEL: Record<string, string> = {
- PENDING: '待处理',
- PROCESSING: '处理中',
- CLOSED: '已关闭',
- }
- const ALERT_LEVEL_LABEL: Record<string, string> = {
- HIGH: '高',
- MEDIUM: '中',
- LOW: '低',
- }
- const SPECIAL_TYPE_LABEL: Record<string, string> = {
- FUNERAL: '丧葬补贴',
- PAUSE: '暂停发放',
- STOP: '停止发放',
- RESUME: '恢复发放',
- STANDARD_ADJUST: '调标差额补发',
- SUPPLEMENT: '纳入下月补发',
- REFUND: '退款',
- HEIR_UPDATE: '继承人信息变更',
- }
- const SPECIAL_TYPE_CODE: Record<string, string> = {
- 丧葬补贴: 'FUNERAL',
- 丧葬: 'FUNERAL',
- 暂停发放: 'PAUSE',
- 暂停: 'PAUSE',
- 停止发放: 'STOP',
- 停止: 'STOP',
- 恢复发放: 'RESUME',
- 恢复: 'RESUME',
- 调标差额补发: 'STANDARD_ADJUST',
- 调标补发: 'STANDARD_ADJUST',
- 纳入下月补发: 'SUPPLEMENT',
- 补发: 'SUPPLEMENT',
- }
- /** 发放年月形态:20 开头 6 位(含调标月键如 202699) */
- export function isPayMonthLike(value?: string): boolean {
- const s = String(value || '').replace(/-/g, '')
- return /^20\d{4}$/.test(s)
- }
- export function payMonthToMonth(payMonth?: string): string {
- if (!payMonth) return ''
- const s = String(payMonth).replace(/-/g, '')
- if (s.length === 6) return `${s.slice(0, 4)}-${s.slice(4)}`
- return payMonth
- }
- export function monthToPayMonth(month?: string): string {
- if (!month) return ''
- return String(month).replace(/-/g, '')
- }
- /**
- * 统一批次号展示:优先发放年月 payMonth(如 202608)
- * 历史库里可能把业务号前 6 位(如 214808)误填进 batchNo,需避开
- */
- export function resolveUnifiedBatchNo(raw: Record<string, unknown>): string {
- const pay = String(raw.payMonth || '').replace(/-/g, '')
- const no = String(raw.batchNo || '').replace(/-/g, '')
- if (isPayMonthLike(pay)) return pay
- if (isPayMonthLike(no)) return no
- // 都不是合法发放月:仍回传原值,便于排查脏数据
- return String(raw.batchNo || raw.payMonth || raw.id || '')
- }
- export function fmtTime(ts?: number | string | null): string {
- if (ts == null || ts === '') return ''
- const n = Number(ts)
- if (!Number.isFinite(n) || n <= 0) return String(ts)
- const d = new Date(n)
- if (Number.isNaN(d.getTime())) return String(ts)
- 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())}:${p(d.getSeconds())}`
- }
- export function mapPerson(raw: Record<string, unknown>, batchNoHint?: string): Person {
- const biz = String(raw.bizStatus || '')
- const ins = String(raw.insuranceMatchResult || raw.insuranceStatus || '')
- let status = PERSON_STATUS_LABEL[biz] || biz || '草稿'
- // 居保失败待人工:页面用「待人工确认」
- if (ins === 'FAIL' || status === '异常待处理') status = '待人工确认'
- // 资格备注
- const remarks = String(raw.remarks || '')
- let retireQualifyType: Person['retireQualifyType']
- if (remarks.includes('无土地')) retireQualifyType = '无土地有资格'
- else if (remarks.includes('有土地') || remarks.includes('资格已核验')) retireQualifyType = '有土地退养'
- return {
- id: String(raw.id || '') as unknown as number,
- batchNo: batchNoHint || '',
- name: String(raw.name || ''),
- idCard: String(raw.idNumber || ''),
- town: regionName(String(raw.townId || '')),
- village: regionName(String(raw.villageId || '')),
- bankCard: String(raw.bankCardNumber || ''),
- bankName: String(raw.bankName || ''),
- socialInsuranceCode: raw.socialInsuranceCode ? String(raw.socialInsuranceCode) : undefined,
- // 月补只认街镇标准表关联结果;无标准时勿回退 0/陈旧冗余值
- standard:
- raw.monthlyStandard == null || raw.monthlyStandard === ''
- ? undefined
- : Number(raw.monthlyStandard),
- startMonth: payMonthToMonth(String(raw.enjoyStartMonth || '')),
- status,
- source: String(raw.source || ''),
- insuranceStatus: INSURANCE_LABEL[ins] || String(raw.insuranceStatus || '未匹配'),
- remark: remarks || undefined,
- retireQualifyType,
- }
- }
- const FLOW_STAGE_LABEL: Record<string, string> = {
- STAGE1_PERSONNEL_INPUT: '人员新增录入',
- STAGE2_TOWN_PRECHECK: '镇经发中心初审',
- STAGE3_INSURANCE_MATCH: '居保状态匹配',
- STAGE4_MONTHLY_LIST: '生成月补贴清单',
- STAGE5_LEADER_ONLINE_APPROVE: '分管领导审批',
- STAGE6_COMPARE_FILE: '生成对照文件',
- STAGE7_OFFLINE_SIGN_PAY: '待线下发放',
- STAGE8_RETURN_CONFIRM: '回盘信息确认',
- }
- export function flowStageLabel(code?: string): string {
- if (!code) return ''
- return FLOW_STAGE_LABEL[code] || BATCH_STATUS_TO_STAGE[code] || code
- }
- function resolveSubmittedAt(raw: Record<string, unknown>): string | undefined {
- const fromField =
- fmtTime(raw.submitTime as number | string) || fmtTime(raw.updateTime as number | string)
- if (fromField) return fromField
- const remarks = String(raw.remarks || '')
- const m = remarks.match(/SUBMIT_TIME\|(\d+)/)
- if (m?.[1]) return fmtTime(m[1])
- return undefined
- }
- export function mapVillageBatch(raw: Record<string, unknown>): VillageBatch {
- const status = String(raw.status || '')
- const stage =
- BATCH_STATUS_TO_STAGE[status] ||
- flowStageLabel(String(raw.currentStage || '')) ||
- status
- const batchNo = resolveUnifiedBatchNo(raw)
- const payMonth = isPayMonthLike(String(raw.payMonth || ''))
- ? String(raw.payMonth).replace(/-/g, '')
- : batchNo
- return {
- id: String(raw.id || ''),
- batchNo,
- month: payMonthToMonth(payMonth),
- town: regionName(String(raw.townId || '')),
- village: regionName(String(raw.villageId || '')),
- peopleCount: Number(raw.peopleCount || 0),
- totalAmount: Number(raw.totalAmount || 0),
- stage,
- submitter: String(raw.submitter || ''),
- submittedAt: resolveSubmittedAt(raw),
- statusCode: status || undefined,
- exportStatus: raw.exportStatus ? String(raw.exportStatus) : undefined,
- returnStatus: raw.returnStatus ? String(raw.returnStatus) : undefined,
- exportDiskNo: raw.exportDiskNo ? String(raw.exportDiskNo) : undefined,
- exportFileName: raw.exportFileName ? String(raw.exportFileName) : undefined,
- townOpinion: raw.townOpinion ? String(raw.townOpinion) : undefined,
- remarks: raw.remarks ? String(raw.remarks) : undefined,
- normalAmount: Number(raw.normalAmount || 0) || undefined,
- supplementAmount: Number(raw.supplementAmount || 0) || undefined,
- deductAmount: Number(raw.deductAmount || 0) || undefined,
- }
- }
- export function mapProcessLog(raw: Record<string, unknown>): ProcessLogItem {
- return {
- id: String(raw.id || ''),
- batchId: raw.batchId ? String(raw.batchId) : undefined,
- batchNo: raw.batchNo ? String(raw.batchNo) : undefined,
- stage: flowStageLabel(String(raw.stage || '')),
- action: String(raw.action || raw.approveNode || '办理'),
- approveNode: raw.approveNode ? String(raw.approveNode) : undefined,
- operator: String(raw.operator || raw.operatorRole || ''),
- operatorRole: raw.operatorRole ? String(raw.operatorRole) : undefined,
- operatorOrg: raw.operatorOrg ? String(raw.operatorOrg) : undefined,
- opinion: raw.opinion ? String(raw.opinion) : undefined,
- result: String(raw.result || raw.status || ''),
- status: raw.status ? String(raw.status) : undefined,
- operateTime: fmtTime(raw.operateTime as number),
- fileUrls: raw.fileUrls ? String(raw.fileUrls) : undefined,
- }
- }
- export function mapVillageMonthly(raw: Record<string, unknown>): VillageMonthlyBatch {
- const b = mapVillageBatch(raw)
- const status = String(raw.status || '')
- return {
- id: b.id,
- batchNo: b.batchNo,
- month: b.month,
- town: b.town,
- village: b.village,
- peopleCount: b.peopleCount,
- normalAmount: Number(raw.normalAmount || 0),
- extraAmount: Number(raw.supplementAmount || 0),
- deductAmount: Number(raw.deductAmount || 0),
- totalAmount: Number(raw.totalAmount || b.totalAmount || 0),
- status: BATCH_STATUS_TO_MONTHLY[status] || b.stage,
- stage: b.stage,
- submitter: b.submitter,
- submittedAt: b.submittedAt,
- }
- }
- export function mapDisk(raw: Record<string, unknown>): DiskRecord {
- const status = String(raw.status || '')
- const returnStatusRaw = String(raw.returnStatus || '未回盘')
- let diskStatus = '待回盘'
- let returnStatus = '待确认'
- if (status === 'RETURNED' || status === 'ARCHIVED') {
- diskStatus = '已回盘'
- if (returnStatusRaw.includes('部分') || returnStatusRaw.includes('异常')) returnStatus = '部分失败'
- else if (returnStatusRaw.includes('成功') || returnStatusRaw === '全部成功') returnStatus = '成功'
- else returnStatus = '成功'
- } else if (status === 'EXPORTED') {
- diskStatus = '待回盘'
- returnStatus = '待确认'
- }
- return {
- id: String(raw.id || ''),
- batchNo: String(raw.batchNo || ''),
- town: regionName(String(raw.townId || '')),
- fileName: String(raw.exportFileName || `${raw.batchNo || ''}-月补贴发放文件.xlsx`),
- peopleCount: Number(raw.peopleCount || 0),
- amount: Number(raw.totalAmount || 0),
- status: diskStatus,
- returnStatus,
- failCount: 0,
- returnFileName: undefined,
- }
- }
- export function mapReturnFail(raw: Record<string, unknown>, diskId: string): DiskFailPerson {
- return {
- id: String(raw.id || raw.paymentDetailId || ''),
- diskId,
- batchNo: String(raw.batchId || ''),
- town: regionName(String(raw.townId || '')),
- village: regionName(String(raw.villageId || '')),
- personName: String(raw.name || ''),
- idCard: String(raw.idNumber || ''),
- bankCard: undefined,
- failReason: String(raw.failReasonDesc || raw.failReasonCode || ''),
- amount: Number(raw.amount ?? raw.actualAmount ?? 0),
- payStatus: raw.success === false ? '待确认' : '已确认发放',
- }
- }
- function alertBatchLabel(raw: Record<string, unknown>): string {
- const no = String(raw.batchNo || '').trim()
- if (no) return no
- const id = String(raw.batchId || '').trim()
- if (id) return id
- // 兼容历史:正文里「批次 VB…」
- const content = String(raw.content || '')
- const m = content.match(/批次\s*([A-Za-z0-9_-]+)/)
- return m?.[1] || ''
- }
- export function mapAlert(raw: Record<string, unknown>): AlertItem {
- const hs = String(raw.handleStatus || '')
- const level = String(raw.level || '')
- return {
- id: String(raw.id || ''),
- batchNo: alertBatchLabel(raw),
- personName: String(raw.personnelName || ''),
- town: regionName(String(raw.townId || '')),
- village: regionName(String(raw.villageId || '')),
- type: String(raw.type || ''),
- level: ALERT_LEVEL_LABEL[level] || level,
- content: String(raw.content || ''),
- status: ALERT_STATUS_LABEL[hs] || hs || '待处理',
- result: raw.handleResult ? String(raw.handleResult) : undefined,
- createdAt: fmtTime(raw.createTime as number),
- failReason: raw.failReasonCode ? String(raw.failReasonCode) : undefined,
- }
- }
- export function mapSpecial(raw: Record<string, unknown>): SpecialBiz {
- const bizType = String(raw.bizType || '')
- return {
- id: String(raw.id || ''),
- batchNo: String(raw.batchNo || ''),
- town: regionName(String(raw.townId || '')),
- village: '',
- type: SPECIAL_TYPE_LABEL[bizType] || bizType,
- personName: String(raw.name || ''),
- reason: String(raw.reason || ''),
- amount: Number(raw.amount || 0),
- status: String(raw.approveStatus || ''),
- heirName: raw.heirName ? String(raw.heirName) : undefined,
- createdAt: fmtTime(raw.createTime as number),
- }
- }
- export function specialTypeToCode(type: string): string {
- return SPECIAL_TYPE_CODE[type] || type
- }
- export function mapStandard(raw: Record<string, unknown>): SubsidyStandard {
- // effectiveTime 可能是毫秒时间戳或 yyyy-MM-dd
- let date = ''
- const effRaw = raw.effectiveTime
- if (typeof effRaw === 'number' && Number.isFinite(effRaw)) {
- const d = new Date(effRaw)
- date = Number.isNaN(d.getTime())
- ? ''
- : `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
- } else {
- const eff = String(effRaw || '')
- date = eff.length >= 10 ? eff.slice(0, 10) : eff
- }
- const year = date ? Number(date.slice(0, 4)) : new Date().getFullYear()
- // id 可能是字符串,页面用 number 比较「是否最新」——用 hash
- const idStr = String(raw.id || '')
- let idNum = Number(idStr)
- if (!Number.isFinite(idNum)) {
- idNum = [...idStr].reduce((s, c) => s + c.charCodeAt(0), 0)
- }
- return {
- id: idNum,
- town: String(raw.townName || regionName(String(raw.townId || ''))),
- year: Number.isFinite(year) ? year : new Date().getFullYear(),
- monthly: Number(raw.amount || 0),
- funeral: Number(raw.funeralAmount || 0),
- date,
- reason: String(raw.adjustReason || raw.remarks || ''),
- }
- }
- /** 审批单合成 ID:B:batchId / S:specialId */
- export function approvalIdBatch(batchId: string) {
- return `B:${batchId}`
- }
- export function approvalIdSpecial(specialId: string) {
- return `S:${specialId}`
- }
- export function parseApprovalId(id: string): { kind: 'batch' | 'special'; bizId: string } | null {
- if (id.startsWith('B:')) return { kind: 'batch', bizId: id.slice(2) }
- if (id.startsWith('S:')) return { kind: 'special', bizId: id.slice(2) }
- // 兼容直接传批次/特殊单 ID
- if (id.startsWith('VB') || id.startsWith('MB')) return { kind: 'batch', bizId: id }
- return { kind: 'special', bizId: id }
- }
- export function personIdStr(id: number | string): string {
- return String(id)
- }
|