statusLabels.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /**
  2. * 统一业务 code → 中文展示入口。
  3. * 图表/Tag/列表禁止直接把英文枚举抛给用户;未知 code 显示「未知(code)」。
  4. */
  5. export type StatusDictType =
  6. | 'batchStatus'
  7. | 'flowStage'
  8. | 'personnelStatus'
  9. | 'insuranceMatch'
  10. | 'alertHandleStatus'
  11. | 'alertType'
  12. | 'alertLevel'
  13. | 'specialBizType'
  14. | 'processAction'
  15. const BATCH_STATUS: Record<string, string> = {
  16. DRAFT: '草稿',
  17. PENDING_TOWN_APPROVE: '待镇经发初审',
  18. PENDING_INSURANCE_MATCH: '待居保匹配',
  19. PENDING_STATUS_MAINTAIN: '待状态维护',
  20. PENDING_LEADER_APPROVE: '待分管领导审批',
  21. READY_EXPORT: '可出盘',
  22. EXPORTED: '已出盘',
  23. RETURNED: '已回盘',
  24. ARCHIVED: '已归档',
  25. REJECTED: '已驳回',
  26. }
  27. /** 流程阶段(与业务状态语义分离;EXPORTED 在流程上多为「回盘信息确认」) */
  28. const FLOW_STAGE: Record<string, string> = {
  29. STAGE1_PERSONNEL_INPUT: '人员新增录入',
  30. STAGE2_TOWN_PRECHECK: '镇经发中心初审',
  31. STAGE3_INSURANCE_MATCH: '居保状态匹配',
  32. STAGE4_MONTHLY_LIST: '生成月补贴清单',
  33. STAGE5_LEADER_ONLINE_APPROVE: '分管领导审批',
  34. STAGE6_COMPARE_FILE: '生成对照文件',
  35. STAGE7_OFFLINE_SIGN_PAY: '待线下发放',
  36. STAGE8_RETURN_CONFIRM: '回盘信息确认',
  37. DRAFT: '人员新增录入',
  38. PENDING_TOWN_APPROVE: '镇经发中心初审',
  39. PENDING_INSURANCE_MATCH: '居保状态匹配',
  40. PENDING_STATUS_MAINTAIN: '比对结果已生成',
  41. PENDING_LEADER_APPROVE: '分管领导审批',
  42. READY_EXPORT: '待线下发放',
  43. EXPORTED: '回盘信息确认',
  44. RETURNED: '已回盘确认',
  45. ARCHIVED: '已归档',
  46. REJECTED: '退回修改',
  47. }
  48. const PERSONNEL_STATUS: Record<string, string> = {
  49. DRAFT: '待提交资格',
  50. PENDING_TOWN_APPROVE: '待资格审批',
  51. NEW: '新增',
  52. PENDING_INSURANCE_MATCH: '待居保匹配',
  53. NORMAL: '正常发放',
  54. PAUSED: '暂停',
  55. STOPPED: '停止',
  56. FUNERAL: '死亡丧葬',
  57. EXITED: '已退出',
  58. ABNORMAL: '异常待处理',
  59. ARCHIVED: '已归档',
  60. }
  61. const INSURANCE_MATCH: Record<string, string> = {
  62. PENDING: '未匹配',
  63. SUCCESS: '匹配通过',
  64. LOSE_ELIGIBILITY: '丧失资格',
  65. FAIL: '匹配失败',
  66. MANUAL_PASS: '匹配通过',
  67. }
  68. const ALERT_HANDLE: Record<string, string> = {
  69. PENDING: '待处理',
  70. PROCESSING: '处理中',
  71. CLOSED: '已关闭',
  72. }
  73. const ALERT_TYPE: Record<string, string> = {
  74. BANK_CARD_ABNORMAL: '银行卡异常',
  75. NAME_MISMATCH: '姓名不一致',
  76. INSURANCE_MATCH_FAIL: '居保匹配失败',
  77. AMOUNT_ABNORMAL: '金额异常',
  78. DEATH_STATUS: '死亡停发预警',
  79. MATERIAL_PENDING: '材料待补',
  80. RETURN_FAIL: '回盘失败',
  81. LAND_MATCH_FAIL: '土地匹配不符合',
  82. APPROVAL_TIMEOUT: '审批超时',
  83. REFUND_FISCAL: '多发退款待退缴',
  84. QUALIFY_REJECT: '退养资格驳回',
  85. 民政死亡比对: '死亡停发预警',
  86. 回盘发放失败: '回盘失败',
  87. }
  88. const ALERT_LEVEL: Record<string, string> = {
  89. HIGH: '高',
  90. MEDIUM: '中',
  91. LOW: '低',
  92. }
  93. const SPECIAL_BIZ: Record<string, string> = {
  94. FUNERAL: '丧葬补贴',
  95. PAUSE: '暂停发放',
  96. STOP: '停止发放',
  97. RESUME: '恢复发放',
  98. STANDARD_ADJUST: '调标差额补发',
  99. SUPPLEMENT: '纳入下月补发',
  100. REFUND: '多发退款',
  101. HEIR_UPDATE: '继承人信息变更',
  102. STANDARD_CHANGE: '标准变更',
  103. INSURANCE_MATCH: '居保匹配',
  104. PERSONNEL_STATUS: '人员状态变更',
  105. RETIRE_QUALIFY: '退养资格审批',
  106. }
  107. /** 流程动作 / bizType 英文码 → 中文(禁止直接渲染 code) */
  108. const PROCESS_ACTION: Record<string, string> = {
  109. SPECIAL_BIZ: '特殊业务申请',
  110. SPECIAL_APPROVE_PASS: '分管领导审批通过',
  111. SPECIAL_APPROVE_REJECT: '分管领导审批驳回',
  112. STATUS_STOPPED: '停止发放',
  113. STATUS_PAUSED: '暂停发放',
  114. STATUS_NORMAL: '恢复发放',
  115. STATUS_FUNERAL: '死亡丧葬状态落地',
  116. STATUS_ARCHIVED: '人员归档',
  117. STATUS_ABNORMAL: '异常待处理',
  118. STATUS_PENDING_INSURANCE_MATCH: '待居保匹配',
  119. QUALIFY_SUBMIT: '提交退养资格',
  120. QUALIFY_PASS: '退养资格审批通过',
  121. QUALIFY_REJECT: '退养资格审批驳回',
  122. QUALIFY_REJECT_CLOSED: '资格驳回告警已关闭,退回待提交资格',
  123. RETIRE_QUALIFY: '退养资格审批',
  124. RETIRE_QUALIFY_SNAPSHOT: '退养资格',
  125. STATUS_NEW: '新增',
  126. PERSONNEL_STATUS: '人员状态变更',
  127. PERSONNEL_STATUS_SNAPSHOT: '人员业务状态',
  128. FUNERAL: '丧葬/死亡登记',
  129. STOP: '停止发放申请',
  130. PAUSE: '暂停发放申请',
  131. RESUME: '恢复发放申请',
  132. SUPPLEMENT: '补发申请',
  133. NOTE: '补充备注',
  134. INSURANCE_MATCH: '居保匹配',
  135. INSURANCE_MATCH_SUCCESS: '居保匹配通过',
  136. INSURANCE_MATCH_MANUAL: '居保人工确认',
  137. INSURANCE_MATCH_FAIL: '居保匹配失败',
  138. INSURANCE_MATCH_PENDING: '居保待确认',
  139. INSURANCE_MATCH_SNAPSHOT: '居保匹配结果',
  140. CALC_ROUND: '测算轮次',
  141. CALC_LOCK: '锁定测算',
  142. CALC_UNLOCK: '解锁测算',
  143. TODO_READ: '待办已读',
  144. PERSONNEL_IMPORT: '人员导入',
  145. PERSONNEL_FIELD_CHANGE: '人员字段变更',
  146. RETURN_ARREARS: '回盘失败待补发',
  147. SYS_USER: '系统用户',
  148. SYS_CONFIG: '系统配置',
  149. LOGIN_LOG: '登录日志',
  150. LOGIN_AUDIT: '登录审计',
  151. LOGOUT_AUDIT: '登出审计',
  152. OP_LOG: '操作日志',
  153. STANDARD_CHANGE: '标准变更',
  154. STANDARD_ADJUST: '调标差额补发',
  155. REFUND: '多发退款',
  156. HEIR_UPDATE: '继承人信息变更',
  157. SUCCESS: '成功',
  158. FAIL: '失败',
  159. PENDING: '待处理',
  160. PASS: '通过',
  161. REJECT: '驳回',
  162. LOGIN: '登录',
  163. LOGOUT: '登出',
  164. 成功: '成功',
  165. 登出: '登出',
  166. 失败: '失败',
  167. }
  168. /** 角色 key / 英文角色码 → 中文称谓 */
  169. const ROLE_LABEL: Record<string, string> = {
  170. village: '村合作社',
  171. town: '镇经发中心',
  172. social: '镇社区事务受理中心',
  173. leader: '分管领导',
  174. agri: '区农委',
  175. hr: '区人社局',
  176. admin: '系统管理员',
  177. district: '区级',
  178. unknown: '未知角色',
  179. 系统: '系统',
  180. 业务部门: '业务部门',
  181. 分管领导: '分管领导',
  182. 历史: '历史',
  183. }
  184. const DICTS: Record<StatusDictType, Record<string, string>> = {
  185. batchStatus: BATCH_STATUS,
  186. flowStage: FLOW_STAGE,
  187. personnelStatus: PERSONNEL_STATUS,
  188. insuranceMatch: INSURANCE_MATCH,
  189. alertHandleStatus: ALERT_HANDLE,
  190. alertType: ALERT_TYPE,
  191. alertLevel: ALERT_LEVEL,
  192. specialBizType: SPECIAL_BIZ,
  193. processAction: PROCESS_ACTION,
  194. }
  195. /** 是否像未翻译的英文枚举 code */
  196. function looksLikeCode(s: string) {
  197. return /^[A-Z][A-Z0-9_]*$/.test(s)
  198. }
  199. /** 命中字典或已是中文则返回;未知英文 code 返回 null */
  200. export function tryLabelOf(dictType: StatusDictType, code?: string | null): string | null {
  201. if (code == null || code === '') return null
  202. const raw = String(code).trim()
  203. const table = DICTS[dictType]
  204. if (table[raw]) return table[raw]
  205. const upper = raw.toUpperCase()
  206. if (table[upper]) return table[upper]
  207. if (!looksLikeCode(raw)) return raw
  208. return null
  209. }
  210. /**
  211. * @param dictType 字典册
  212. * @param code 后端枚举或已是中文的文案
  213. */
  214. export function labelOf(dictType: StatusDictType, code?: string | null): string {
  215. if (code == null || code === '') return ''
  216. const hit = tryLabelOf(dictType, code)
  217. if (hit != null) return hit
  218. const raw = String(code).trim()
  219. if (import.meta.env.DEV) {
  220. // eslint-disable-next-line no-console
  221. console.warn(`[statusLabels] 未知 ${dictType} code:`, raw)
  222. }
  223. return `未知(${raw})`
  224. }
  225. export function batchStatusLabel(code?: string | null) {
  226. return labelOf('batchStatus', code)
  227. }
  228. export function flowStageLabelOf(code?: string | null) {
  229. return labelOf('flowStage', code)
  230. }
  231. export function personnelStatusLabel(code?: string | null) {
  232. return labelOf('personnelStatus', code)
  233. }
  234. /** 退养资格类型展示:空/UNSET → 待认定 */
  235. export function retireQualifyLabel(code?: string | null) {
  236. const s = String(code || '').trim()
  237. if (!s || s === '—' || s === 'UNSET' || s === 'NONE' || s === 'CLEARED') return '待认定'
  238. if (s === 'WITH_LAND') return '有土地退养'
  239. if (s === 'WITHOUT_LAND') return '无土地有资格'
  240. if (s === 'INELIGIBLE') return '无资格'
  241. return s
  242. }
  243. const REFUND_PROGRESS: Record<string, string> = {
  244. REGISTERED: '已登记',
  245. VERIFYING: '核实中',
  246. DEDUCTING: '下月扣减中',
  247. RETURNING: '退缴财政中',
  248. VOUCHER_ARCHIVED: '凭证已归档',
  249. DONE: '已完成',
  250. }
  251. export function refundProgressLabel(code?: string | null): string {
  252. if (code == null || code === '') return ''
  253. const raw = String(code).trim()
  254. if (REFUND_PROGRESS[raw]) return REFUND_PROGRESS[raw]
  255. if (REFUND_PROGRESS[raw.toUpperCase()]) return REFUND_PROGRESS[raw.toUpperCase()]
  256. if (looksLikeCode(raw)) return labelOf('processAction', raw)
  257. return raw
  258. }
  259. /** 流程动作展示:已是中文则原样,英文 code 走字典 */
  260. export function processActionLabelOf(code?: string | null): string {
  261. if (code == null || code === '') return '办理'
  262. const raw = String(code).trim()
  263. if (!looksLikeCode(raw)) return raw
  264. return labelOf('processAction', raw)
  265. }
  266. /** 结果/状态短码展示 */
  267. export function resultLabelOf(code?: string | null): string {
  268. if (code == null || code === '') return ''
  269. const raw = String(code).trim()
  270. if (!looksLikeCode(raw) && !/^(SUCCESS|FAIL|PENDING|PASS|REJECT)$/i.test(raw)) {
  271. return raw
  272. }
  273. return (
  274. tryLabelOf('processAction', raw) ||
  275. tryLabelOf('alertHandleStatus', raw) ||
  276. tryLabelOf('insuranceMatch', raw) ||
  277. tryLabelOf('batchStatus', raw) ||
  278. labelOf('processAction', raw)
  279. )
  280. }
  281. /** 角色展示:禁止直接渲染 village/social 等 key */
  282. export function roleLabelOf(code?: string | null): string {
  283. if (code == null || code === '') return ''
  284. const raw = String(code).trim()
  285. if (ROLE_LABEL[raw]) return ROLE_LABEL[raw]
  286. if (ROLE_LABEL[raw.toLowerCase()]) return ROLE_LABEL[raw.toLowerCase()]
  287. if (!looksLikeCode(raw) && !/^[a-z][a-z0-9_]*$/i.test(raw)) return raw
  288. return raw
  289. }
  290. /** 通用展示:优先中文,疑似英文码则尝试多字典转义 */
  291. export function displayBizText(code?: string | null): string {
  292. if (code == null || code === '') return '—'
  293. const raw = String(code).trim()
  294. if (!looksLikeCode(raw) && !/^[a-z][a-z0-9_]*$/i.test(raw)) return raw
  295. return (
  296. tryLabelOf('batchStatus', raw) ||
  297. tryLabelOf('flowStage', raw) ||
  298. tryLabelOf('personnelStatus', raw) ||
  299. tryLabelOf('insuranceMatch', raw) ||
  300. tryLabelOf('specialBizType', raw) ||
  301. tryLabelOf('processAction', raw) ||
  302. tryLabelOf('alertType', raw) ||
  303. roleLabelOf(raw) ||
  304. `未知(${raw})`
  305. )
  306. }