/** 对齐 bx-mobile/src/utils/format.ts(Batch2 所需子集) */ export function statusLabel(status) { if (status == null || status === '') return '-' const map = { 1: '启用', 0: '禁用', draft: '待提交', pending: '审批中', approved: '已通过', rejected: '已驳回', withdrawn: '已撤回', issued: '已发放', paid: '已支付', offset: '已冲抵', partial: '部分冲抵', processed: '已处理' } return map[status] ?? String(status) } export function statusTone(status) { if (status == null) return 'info' const map = { 1: 'done', 0: 'error', draft: 'info', pending: 'warn', approved: 'done', rejected: 'error', withdrawn: 'warn', issued: 'done', paid: 'done', offset: 'done', partial: 'warn', processed: 'done' } return map[status] ?? 'info' } export function workflowListStatusTagClass(status) { const raw = status == null || status === '' ? 'draft' : String(status) return `s-${raw}` } export function ticketHeaderStatusToneClass(status) { const tone = statusTone(status) const map = { info: 'advance-ticket-status--info', warn: 'advance-ticket-status--warn', done: 'advance-ticket-status--done', error: 'advance-ticket-status--err', processing: 'advance-ticket-status--processing' } return map[tone] || 'advance-ticket-status--info' } export function formatAmount(amount) { const n = typeof amount === 'string' ? parseFloat(amount) : amount if (Number.isNaN(n)) return '0.00' return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) } export function formatDate(dateStr) { if (!dateStr) return '-' return String(dateStr).substring(0, 10) } export function formatDateTime(dateStr) { if (!dateStr) return '-' return String(dateStr).substring(0, 16).replace('T', ' ') } export function pickApplyTime(row) { if (!row || typeof row !== 'object') return undefined const v = row.applyTime ?? row.createTime ?? row.apply_time ?? row.create_time if (v == null || v === '') return undefined return String(v) } export function formatApplyDateTime(row) { return formatDateTime(pickApplyTime(row)) } export function formatApplyDate(row) { return formatDate(pickApplyTime(row)) } /** 费用树扁平化(tree → flatList) */ export function flattenExpenseTree(tree) { const result = [] for (const node of tree || []) { result.push(node) if (node.children?.length) result.push(...flattenExpenseTree(node.children)) } return result } export function normalizeExpenseItem(raw) { const children = Array.isArray(raw?.children) ? raw.children.map(normalizeExpenseItem) : undefined return { id: String(raw?.id ?? ''), parentId: raw?.parentId == null || raw?.parentId === '' ? '0' : String(raw.parentId), itemName: raw?.itemName ?? '', itemCode: raw?.itemCode ?? '', level: Number(raw?.level ?? 0), sortOrder: Number(raw?.sortOrder ?? 0), status: raw?.status, childCount: Number(raw?.childCount ?? children?.length ?? 0), children } } export function formatExpenseName(id, flatList) { if (id == null || id === '') return '-' const sid = String(id) const parts = [] let cur = (flatList || []).find((i) => String(i.id) === sid) const guard = new Set() while (cur && !guard.has(cur.id)) { guard.add(cur.id) parts.unshift(cur.itemName) const pid = cur.parentId cur = pid != null && pid !== '' && pid !== '0' ? (flatList || []).find((i) => String(i.id) === pid) : undefined } return parts.length ? parts.join('/') : '-' } export function pickExpenseItemId(row) { if (!row || typeof row !== 'object') return null const raw = row.expenseId ?? row.expense_id ?? row.expenseItemId ?? row.expense_item_id if (raw == null || raw === '') return null return String(raw) } export function resolveExpenseDisplay(row, flatList) { if (!row) return '-' const id = pickExpenseItemId(row) const nameFb = row.expenseName ?? row.expense_name if (id != null && flatList && flatList.length) { const p = formatExpenseName(id, flatList) if (p && p !== '-') return p } const fb = nameFb != null ? String(nameFb).trim() : '' return fb || '-' }