From d946b91dd1acbb3dbb6bd7e1d96d2d8684cda706 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Thu, 30 Jul 2026 13:46:22 +0800 Subject: [PATCH] feat(web-admin): add receive account snapshot value helpers. Co-authored-by: Cursor --- .../utils/oa-receive-account-value.test.ts | 68 ++++++++++ .../src/utils/oa-receive-account-value.ts | 119 ++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 web-admin/src/utils/oa-receive-account-value.test.ts create mode 100644 web-admin/src/utils/oa-receive-account-value.ts diff --git a/web-admin/src/utils/oa-receive-account-value.test.ts b/web-admin/src/utils/oa-receive-account-value.test.ts new file mode 100644 index 00000000..e86ced27 --- /dev/null +++ b/web-admin/src/utils/oa-receive-account-value.test.ts @@ -0,0 +1,68 @@ +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' +import { + ACCOUNT_TYPE_LABEL, + formatReceiveAccountDisplay, + formatReceiveAccountLine, + isReceiveAccountSnapshot, + normalizeReceiveAccountModelValue, + type ReceiveAccountSnapshot +} from './oa-receive-account-value' + +const alipay: ReceiveAccountSnapshot = { + id: '1', + accountType: 'alipay', + accountName: '张三', + accountNo: '13800138000', + bankName: '', + bankProvince: '', + bankCity: '', + bankBranch: '', + remark: '日常' +} + +const personal: ReceiveAccountSnapshot = { + id: '2', + accountType: 'personal', + accountName: '李四', + accountNo: '6222', + bankName: '工行', + bankProvince: '安徽省', + bankCity: '合肥市', + bankBranch: '长江中路支行', + remark: '' +} + +describe('oa-receive-account-value', () => { + it('type labels', () => { + assert.equal(ACCOUNT_TYPE_LABEL.alipay, '支付宝') + assert.equal(ACCOUNT_TYPE_LABEL.personal, '个人银行卡') + assert.equal(ACCOUNT_TYPE_LABEL.corporate, '对公银行账户') + }) + it('isReceiveAccountSnapshot', () => { + assert.equal(isReceiveAccountSnapshot(alipay), true) + assert.equal(isReceiveAccountSnapshot({ id: '1' }), false) + }) + it('normalize always array', () => { + assert.deepEqual(normalizeReceiveAccountModelValue(null), []) + assert.deepEqual(normalizeReceiveAccountModelValue(alipay), [alipay]) + assert.deepEqual(normalizeReceiveAccountModelValue([alipay, personal]), [alipay, personal]) + }) + it('format line alipay omits bank', () => { + const line = formatReceiveAccountLine(alipay) + assert.ok(line.includes('支付宝')) + assert.ok(line.includes('张三')) + assert.ok(!line.includes('工行')) + assert.ok(line.includes('日常')) + }) + it('format line personal full', () => { + const line = formatReceiveAccountLine(personal) + assert.ok(line.includes('个人银行卡')) + assert.ok(line.includes('安徽省 / 合肥市')) + assert.ok(line.includes('长江中路支行')) + }) + it('format display multiline', () => { + const text = formatReceiveAccountDisplay([alipay, personal]) + assert.ok(text.includes('\n')) + }) +}) diff --git a/web-admin/src/utils/oa-receive-account-value.ts b/web-admin/src/utils/oa-receive-account-value.ts new file mode 100644 index 00000000..09b7e723 --- /dev/null +++ b/web-admin/src/utils/oa-receive-account-value.ts @@ -0,0 +1,119 @@ +export type ReceiveAccountType = 'alipay' | 'personal' | 'corporate' + +export type ReceiveAccountSnapshot = { + id: string + accountType: ReceiveAccountType + accountName: string + accountNo: string + bankName: string + bankProvince: string + bankCity: string + bankBranch: string + remark: string +} + +export const ACCOUNT_TYPE_LABEL: Record = { + alipay: '支付宝', + personal: '个人银行卡', + corporate: '对公银行账户' +} + +const SNAPSHOT_FIELDS: (keyof ReceiveAccountSnapshot)[] = [ + 'id', + 'accountType', + 'accountName', + 'accountNo', + 'bankName', + 'bankProvince', + 'bankCity', + 'bankBranch', + 'remark' +] + +function isReceiveAccountType(v: unknown): v is ReceiveAccountType { + return v === 'alipay' || v === 'personal' || v === 'corporate' +} + +export function isReceiveAccountSnapshot(v: unknown): v is ReceiveAccountSnapshot { + if (!v || typeof v !== 'object') return false + const o = v as Record + if (!isReceiveAccountType(o.accountType)) return false + for (const key of SNAPSHOT_FIELDS) { + if (typeof o[key] !== 'string') return false + } + return String(o.id || '').trim() !== '' +} + +function trimSnapshot(v: ReceiveAccountSnapshot): ReceiveAccountSnapshot { + return { + id: String(v.id).trim(), + accountType: v.accountType, + accountName: String(v.accountName).trim(), + accountNo: String(v.accountNo).trim(), + bankName: String(v.bankName).trim(), + bankProvince: String(v.bankProvince).trim(), + bankCity: String(v.bankCity).trim(), + bankBranch: String(v.bankBranch).trim(), + remark: String(v.remark).trim() + } +} + +export function normalizeReceiveAccountModelValue( + raw: unknown +): ReceiveAccountSnapshot[] { + if (Array.isArray(raw)) { + return raw.filter(isReceiveAccountSnapshot).map(trimSnapshot) + } + if (isReceiveAccountSnapshot(raw)) { + return [trimSnapshot(raw)] + } + return [] +} + +export function formatReceiveAccountLine(item: ReceiveAccountSnapshot): string { + const parts: string[] = [ + ACCOUNT_TYPE_LABEL[item.accountType], + item.accountName, + item.accountNo + ] + if (item.accountType === 'personal' || item.accountType === 'corporate') { + if (item.bankName) parts.push(item.bankName) + if (item.bankProvince || item.bankCity) { + parts.push(`${item.bankProvince} / ${item.bankCity}`) + } + if (item.bankBranch) parts.push(item.bankBranch) + } + if (item.remark) parts.push(item.remark) + return parts.filter(Boolean).join(' · ') +} + +export function formatReceiveAccountDisplay(raw: unknown): string { + return normalizeReceiveAccountModelValue(raw) + .map(formatReceiveAccountLine) + .join('\n') +} + +export function optionLabelFromRow(row: ReceiveAccountSnapshot): string { + return [ + ACCOUNT_TYPE_LABEL[row.accountType], + row.accountName, + row.accountNo + ] + .filter(Boolean) + .join(' · ') +} + +export function snapshotFromRow(row: any): ReceiveAccountSnapshot { + const accountType = row?.accountType + return { + id: String(row?.id ?? '').trim(), + accountType: isReceiveAccountType(accountType) ? accountType : 'personal', + accountName: String(row?.accountName ?? '').trim(), + accountNo: String(row?.accountNo ?? '').trim(), + bankName: String(row?.bankName ?? '').trim(), + bankProvince: String(row?.bankProvince ?? '').trim(), + bankCity: String(row?.bankCity ?? '').trim(), + bankBranch: String(row?.bankBranch ?? '').trim(), + remark: String(row?.remark ?? '').trim() + } +}