diff --git a/apps/backend/src/db/migrations/114_work_order_share_cancel_reason_comment.sql b/apps/backend/src/db/migrations/114_work_order_share_cancel_reason_comment.sql new file mode 100644 index 00000000..a14a84df --- /dev/null +++ b/apps/backend/src/db/migrations/114_work_order_share_cancel_reason_comment.sql @@ -0,0 +1,6 @@ +-- 114_work_order_share_cancel_reason_comment.sql +-- 「取消部分」把被撤销的份额标记为 admin_partial,校准 cancelled_reason 的枚举注释。 +-- 纯注释变更,无结构/数据改动;重复执行无副作用。 + +COMMENT ON COLUMN work_order_shares.cancelled_reason IS + '取消来源:timeout/worker_request/admin/admin_partial/problem/settlement'; diff --git a/apps/frontend/src/pages/admin/panels/shared.tsx b/apps/frontend/src/pages/admin/panels/shared.tsx index f7860925..82ba6531 100644 --- a/apps/frontend/src/pages/admin/panels/shared.tsx +++ b/apps/frontend/src/pages/admin/panels/shared.tsx @@ -252,17 +252,6 @@ export function formatSharingShareStatus(status: string) { return labels[status] || status } -/** 撤单原因:份额级独立撤单后,后台需要一眼看出是谁撤的。 */ -export function formatSharingShareCancelledReason(reason: string) { - const labels: Record = { - timeout: '超时失效', - admin: '后台撤单', - worker_request: '打手退单', - problem: '问题单处置', - } - return labels[reason] || reason -} - export function formatAcceptanceMode(mode: string) { if (mode === 'friend_gift') return '好友赠送' return '标准验收' @@ -271,6 +260,9 @@ export function formatAcceptanceMode(mode: string) { // 阶段文案与配色在 utils 里实现,便于单测覆盖「内部现货单显示待加好友」这条口径。 export { formatGiftPhase, resolveGiftPhaseColor } from '@/utils/gift-phase' +// 取消来源文案同样抽到 utils,避免新增枚举值时漏映射(admin_partial 就踩过)。 +export { formatSharingShareCancelledReason } from '@/utils/worker-share-cancel-reason' + export function resolveSharingShareStatusColor(status: string) { if (status === 'accepted') return 'green' if (status === 'submitted') return 'gold' diff --git a/apps/frontend/src/utils/worker-share-cancel-reason.ts b/apps/frontend/src/utils/worker-share-cancel-reason.ts new file mode 100644 index 00000000..492cb289 --- /dev/null +++ b/apps/frontend/src/utils/worker-share-cancel-reason.ts @@ -0,0 +1,20 @@ +/** + * 拼单份额取消来源的中文标签。 + * + * 后端 `work_order_shares.cancelled_reason` 使用英文枚举: + * timeout / worker_request / admin / admin_partial / problem / settlement。 + * 新增来源时必须同步这里,否则后台「拼单明细」会直接显示原始值。 + */ +export const SHARE_CANCEL_REASON_LABELS: Record = { + timeout: '超时失效', + admin: '后台撤单', + admin_partial: '后台取消部分', + worker_request: '打手退单', + problem: '问题单处置', + settlement: '结算处置', +} + +/** 撤单原因:份额级独立撤单后,后台需要一眼看出是谁撤的。 */ +export function formatSharingShareCancelledReason(reason: string) { + return SHARE_CANCEL_REASON_LABELS[reason] || reason +} diff --git a/apps/frontend/tests/worker-share-cancel-reason.test.ts b/apps/frontend/tests/worker-share-cancel-reason.test.ts new file mode 100644 index 00000000..d546c82a --- /dev/null +++ b/apps/frontend/tests/worker-share-cancel-reason.test.ts @@ -0,0 +1,32 @@ +import assert from 'node:assert/strict' +import test from 'node:test' + +import { + SHARE_CANCEL_REASON_LABELS, + formatSharingShareCancelledReason, +} from '../src/utils/worker-share-cancel-reason.ts' + +test('拼单取消来源:已知枚举值都必须有中文标签', () => { + for (const reason of [ + 'timeout', + 'admin', + 'admin_partial', + 'worker_request', + 'problem', + 'settlement', + ]) { + const label = formatSharingShareCancelledReason(reason) + assert.notEqual(label, reason, `${reason} 缺少中文映射`) + assert.equal(label, SHARE_CANCEL_REASON_LABELS[reason]) + assert.ok(label.trim().length > 0) + } +}) + +test('拼单取消来源:取消部分必须映射为后台取消部分', () => { + assert.equal(formatSharingShareCancelledReason('admin_partial'), '后台取消部分') +}) + +test('拼单取消来源:未知值保留原始值,便于排查', () => { + assert.equal(formatSharingShareCancelledReason('some_new_reason'), 'some_new_reason') + assert.equal(formatSharingShareCancelledReason(''), '') +})