/** * 寄卖凭证(提报凭证 / 赠送凭证)的纯展示逻辑。 * * 客服要在列表和详情里一句话看清「赠送凭证交没交、交了几张、验没验」, * 所以把文案规则集中在这里。刻意写成纯函数:不依赖 React / antd, * 也不使用 `@/` 别名,方便 `node --experimental-strip-types --test` 直接跑单测。 */ import type { GiftEvidenceReviewStatus } from '../types/consignment' export type { GiftEvidenceReviewStatus } export type GiftEvidenceBadge = { /** 标签文案 */ text: string /** antd Tag 的 color 取值 */ color: string } export type GiftEvidenceSummaryInput = { status: GiftEvidenceReviewStatus /** 赠送凭证图片(赠送完成截图) */ images: string[] /** 凭证提交时间(ISO 字符串,可能为空) */ submittedAt?: string } /** * 赠送凭证状态 → 客服标签。 * 后端以后新增状态时不能崩:未知状态一律回退成「未提交」。 */ export function resolveGiftEvidenceBadge(status: GiftEvidenceReviewStatus): GiftEvidenceBadge { switch (status) { case 'pending': return { text: '待客服验收', color: 'gold' } case 'accepted': return { text: '已验收', color: 'green' } case 'submitted': return { text: '已提交', color: 'blue' } default: return { text: '未提交', color: 'default' } } } /** * 给客服看的一句话赠送凭证说明: * - `未提交` * - `已提交 3 张,待客服验收` * - `已验收(3 张)· 2026-09-17 10:00` * - 有图但没时间 / 时间非法:省略 ` · 时间` 部分 * - 已提交但 0 张图:`已提交,无截图`(带状态后缀时如 `已提交,无截图,待客服验收`) * - `none`(以及未来新增状态)只看成「还没交」:即使残留了时间也不拼进文案,避免自相矛盾 */ export function describeGiftEvidence(input: GiftEvidenceSummaryInput): string { const count = countEvidenceImages(input?.images) const time = formatEvidenceTime(input?.submittedAt) switch (input?.status) { case 'pending': return appendEvidenceTime( count > 0 ? `已提交 ${count} 张,待客服验收` : '已提交,无截图,待客服验收', time, ) case 'accepted': return appendEvidenceTime(count > 0 ? `已验收(${count} 张)` : '已验收,无截图', time) case 'submitted': return appendEvidenceTime(count > 0 ? `已提交 ${count} 张` : '已提交,无截图', time) default: return '未提交' } } /** 追加提交时间;没有有效时间就原样返回(不留下孤零零的分隔符) */ function appendEvidenceTime(text: string, time: string): string { if (!time) return text // 以全角右括号收尾的短句(如「已验收(3 张)」)直接紧凑接 ·,其余用空格分隔更易读 return text.endsWith(')') ? `${text}· ${time}` : `${text} · ${time}` } /** 统计有效图片张数:空字符串 / 空白串不算凭证 */ function countEvidenceImages(images?: string[] | null): number { if (!Array.isArray(images)) return 0 return images.filter((src) => String(src ?? '').trim()).length } /** 凭证提交时间 → `YYYY-MM-DD HH:mm`;空值或非法时间返回空串(调用方直接省略这段) */ function formatEvidenceTime(submittedAt?: string | null): string { const normalized = String(submittedAt ?? '').trim() if (!normalized) return '' const date = new Date(normalized) if (Number.isNaN(date.getTime())) return '' const pad = (value: number) => String(value).padStart(2, '0') const datePart = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}` const timePart = `${pad(date.getHours())}:${pad(date.getMinutes())}` return `${datePart} ${timePart}` }