diff --git a/web-admin/src/utils/mp-crm-contract-card.test.ts b/web-admin/src/utils/mp-crm-contract-card.test.ts new file mode 100644 index 000000000..3c7615fa0 --- /dev/null +++ b/web-admin/src/utils/mp-crm-contract-card.test.ts @@ -0,0 +1,116 @@ +import assert from 'node:assert/strict' +import { describe, it } from 'node:test' +import { + MP_CONTRACT_MANAGE_TABS, + MP_CONTRACT_APPROVE_TABS, + buildContractListQuery, + buildContractCard, + formatContractMoney +} from './mp-crm-contract-card' + +describe('tabs', () => { + it('manage all/approving/approved; approve submitted/approved', () => { + assert.deepEqual( + MP_CONTRACT_MANAGE_TABS.map((x) => x.value), + ['all', 'approving', 'approved'] + ) + assert.deepEqual( + MP_CONTRACT_APPROVE_TABS.map((x) => x.value), + ['submitted', 'approved'] + ) + }) +}) + +describe('buildContractListQuery', () => { + it('manage all excludes invalid and trims keyword', () => { + assert.deepEqual( + buildContractListQuery({ + mode: 'manage', + view: 'all', + pageNum: 1, + pageSize: 20, + keyword: ' 合同 ', + currentUserId: 'u1' + }), + { pageNum: 1, pageSize: 20, keyword: '合同', excludeStatus: 'invalid' } + ) + }) + + it('manage approving sets status only', () => { + const q = buildContractListQuery({ + mode: 'manage', + view: 'approving', + pageNum: 1, + pageSize: 20, + keyword: '', + currentUserId: 'u1' + }) + assert.equal(q.status, 'approving') + assert.equal('pendingApprovalUserId' in q, false) + }) + + it('manage approved sets status approved', () => { + const q = buildContractListQuery({ + mode: 'manage', + view: 'approved', + pageNum: 1, + pageSize: 20, + keyword: '', + currentUserId: 'u1' + }) + assert.equal(q.status, 'approved') + assert.equal('approvedByUserId' in q, false) + }) + + it('approve submitted uses pendingApprovalUserId', () => { + const q = buildContractListQuery({ + mode: 'approve', + view: 'submitted', + pageNum: 1, + pageSize: 20, + keyword: '', + currentUserId: 'u9' + }) + assert.equal(q.pendingApprovalUserId, 'u9') + }) + + it('approve approved uses approvedByUserId', () => { + const q = buildContractListQuery({ + mode: 'approve', + view: 'approved', + pageNum: 1, + pageSize: 20, + keyword: 'x', + currentUserId: 'u9' + }) + assert.equal(q.approvedByUserId, 'u9') + assert.equal(q.keyword, 'x') + }) +}) + +describe('buildContractCard', () => { + it('maps fields', () => { + const card = buildContractCard({ + id: 'c1', + contractNo: 'HT001', + contractTitle: '硫酸销售合同', + customerName: '甲公司', + amount: 1000, + freight: 50, + barrelDeposit: 20, + status: 'draft', + signDate: '2026-10-01' + }) + assert.equal(card.id, 'c1') + assert.equal(card.contractNo, 'HT001') + assert.equal(card.amountText, '¥1,070.00') + assert.equal(card.status, 'draft') + }) +}) + +describe('formatContractMoney', () => { + it('formats and handles empty', () => { + assert.equal(formatContractMoney(1000), '¥1,000.00') + assert.equal(formatContractMoney(undefined), '—') + }) +}) diff --git a/web-admin/src/utils/mp-crm-contract-card.ts b/web-admin/src/utils/mp-crm-contract-card.ts new file mode 100644 index 000000000..f46ec57c7 --- /dev/null +++ b/web-admin/src/utils/mp-crm-contract-card.ts @@ -0,0 +1,77 @@ +export type MpContractMode = 'manage' | 'approve' +export type MpContractManageView = 'all' | 'approving' | 'approved' +export type MpContractApproveView = 'submitted' | 'approved' +export type MpContractView = MpContractManageView | MpContractApproveView + +export const MP_CONTRACT_MANAGE_TABS: Array<{ value: MpContractManageView; label: string }> = [ + { value: 'all', label: '全部' }, + { value: 'approving', label: '待审批' }, + { value: 'approved', label: '已审批' } +] + +export const MP_CONTRACT_APPROVE_TABS: Array<{ value: MpContractApproveView; label: string }> = [ + { value: 'submitted', label: '待审批' }, + { value: 'approved', label: '已审批' } +] + +export function formatContractMoney(amount?: number | null): string { + if (amount === undefined || amount === null || Number.isNaN(Number(amount))) return '—' + return `¥${Number(amount).toLocaleString('zh-CN', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })}` +} + +export function buildContractListQuery(input: { + mode: MpContractMode + view: MpContractView + pageNum: number + pageSize: number + keyword: string + currentUserId: string +}): Record { + const params: Record = { + pageNum: input.pageNum, + pageSize: input.pageSize + } + const kw = String(input.keyword || '').trim() + if (kw) params.keyword = kw + + if (input.mode === 'manage') { + if (input.view === 'all') params.excludeStatus = 'invalid' + else if (input.view === 'approving') params.status = 'approving' + else params.status = 'approved' + return params + } + + if (input.view === 'submitted') { + params.pendingApprovalUserId = input.currentUserId + } else { + params.approvedByUserId = input.currentUserId + } + return params +} + +export function buildContractCard(row: { + id: string | number + contractNo?: string + contractTitle?: string + customerName?: string + amount?: number + freight?: number + barrelDeposit?: number + status?: string + signDate?: string +}) { + const total = + (Number(row.amount) || 0) + (Number(row.freight) || 0) + (Number(row.barrelDeposit) || 0) + return { + id: String(row.id), + contractNo: row.contractNo || '—', + contractTitle: row.contractTitle || '—', + customerName: row.customerName || '—', + amountText: formatContractMoney(total), + status: row.status || '', + signDate: row.signDate || '—' + } +}