feat(web-admin): add mp CRM quote card query helpers.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuzilongandCursor committed 2026-10-15 15:49:11 +08:00
1 parent 121e431f68
commit 007eb2233d
2 files changed
+228

No files matched your search

@@ -0,0 +1,132 @@
// web-admin/src/utils/mp-crm-quote-card.test.ts
import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import {
MP_QUOTE_MANAGE_TABS,
MP_QUOTE_APPROVE_TABS,
buildQuoteListQuery,
buildQuoteCard,
formatQuoteMoney,
quoteTypeLabel,
quoteTypeTagType
} from './mp-crm-quote-card'
describe('tabs', () => {
it('manage has all/submitted/accepted; approve has submitted/accepted', () => {
assert.deepEqual(
MP_QUOTE_MANAGE_TABS.map((x) => x.value),
['all', 'submitted', 'accepted']
)
assert.deepEqual(
MP_QUOTE_APPROVE_TABS.map((x) => x.value),
['submitted', 'accepted']
)
})
})
describe('buildQuoteListQuery', () => {
it('manage all excludes invalid and trims keyword', () => {
assert.deepEqual(
buildQuoteListQuery({
mode: 'manage',
view: 'all',
pageNum: 1,
pageSize: 20,
keyword: ' 酸 ',
currentUserId: 'u1'
}),
{
pageNum: 1,
pageSize: 20,
keyword: '酸',
excludeStatus: 'invalid'
}
)
})
it('manage submitted sets status only', () => {
const q = buildQuoteListQuery({
mode: 'manage',
view: 'submitted',
pageNum: 2,
pageSize: 10,
keyword: '',
currentUserId: 'u1'
})
assert.equal(q.status, 'submitted')
assert.equal(q.excludeStatus, undefined)
assert.equal('pendingApprovalUserId' in q, false)
assert.equal('keyword' in q, false)
})
it('manage accepted sets status accepted', () => {
const q = buildQuoteListQuery({
mode: 'manage',
view: 'accepted',
pageNum: 1,
pageSize: 20,
keyword: '',
currentUserId: 'u1'
})
assert.equal(q.status, 'accepted')
assert.equal('approvedByUserId' in q, false)
})
it('approve submitted uses pendingApprovalUserId', () => {
const q = buildQuoteListQuery({
mode: 'approve',
view: 'submitted',
pageNum: 1,
pageSize: 20,
keyword: '',
currentUserId: 'u9'
})
assert.equal(q.status, 'submitted')
assert.equal(q.pendingApprovalUserId, 'u9')
})
it('approve accepted uses approvedByUserId', () => {
const q = buildQuoteListQuery({
mode: 'approve',
view: 'accepted',
pageNum: 1,
pageSize: 20,
keyword: 'x',
currentUserId: 'u9'
})
assert.equal(q.approvedByUserId, 'u9')
assert.equal(q.keyword, 'x')
assert.equal('status' in q && q.status !== undefined, false)
})
})
describe('buildQuoteCard', () => {
it('maps fields and money', () => {
const card = buildQuoteCard({
id: 'q1',
quoteNo: 'BJ001',
quoteTitle: '硫酸报价',
customerName: '甲公司',
quoteType: 'sales',
finalAmount: 1234.5,
status: 'draft',
quoteDate: '2026-10-01'
})
assert.equal(card.id, 'q1')
assert.equal(card.quoteNo, 'BJ001')
assert.equal(card.quoteTypeLabel, '销售')
assert.equal(card.quoteTypeTagType, 'success')
assert.equal(card.amountText, '¥1,234.50')
assert.equal(card.status, 'draft')
})
})
describe('quoteType helpers', () => {
it('maps purchase/sales', () => {
assert.equal(quoteTypeLabel('purchase'), '采购')
assert.equal(quoteTypeTagType('purchase'), 'warning')
assert.equal(quoteTypeLabel('sales'), '销售')
assert.equal(formatQuoteMoney(1000), '¥1,000.00')
assert.equal(formatQuoteMoney(undefined), '—')
})
})
+96
View File
@@ -0,0 +1,96 @@
export type MpQuoteMode = 'manage' | 'approve'
export type MpQuoteView = 'all' | 'submitted' | 'accepted'
export const MP_QUOTE_MANAGE_TABS: Array<{ value: MpQuoteView; label: string }> = [
{ value: 'all', label: '全部' },
{ value: 'submitted', label: '待审批' },
{ value: 'accepted', label: '已审批' }
]
export const MP_QUOTE_APPROVE_TABS: Array<{ value: Exclude<MpQuoteView, 'all'>; label: string }> = [
{ value: 'submitted', label: '待审批' },
{ value: 'accepted', label: '已审批' }
]
export function quoteTypeLabel(type?: string): string {
if ((type || '').trim() === 'purchase') return '采购'
return '销售'
}
export function quoteTypeTagType(type?: string): 'success' | 'warning' {
if ((type || '').trim() === 'purchase') return 'warning'
return 'success'
}
export function formatQuoteMoney(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 buildQuoteListQuery(input: {
mode: MpQuoteMode
view: MpQuoteView
pageNum: number
pageSize: number
keyword: string
currentUserId: string
}): Record<string, unknown> {
const params: Record<string, unknown> = {
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 === 'submitted') {
params.status = 'submitted'
} else {
params.status = 'accepted'
}
return params
}
// approve
if (input.view === 'submitted') {
params.status = 'submitted'
params.pendingApprovalUserId = input.currentUserId
} else {
params.approvedByUserId = input.currentUserId
}
return params
}
export function buildQuoteCard(row: {
id: string | number
quoteNo?: string
quoteTitle?: string
customerName?: string
quoteType?: string
finalAmount?: number
totalAmount?: number
status?: string
quoteDate?: string
}) {
const amount =
row.finalAmount !== undefined && row.finalAmount !== null
? row.finalAmount
: row.totalAmount
return {
id: String(row.id),
quoteNo: row.quoteNo || '—',
quoteTitle: row.quoteTitle || '—',
customerName: row.customerName || '—',
quoteType: row.quoteType || 'sales',
quoteTypeLabel: quoteTypeLabel(row.quoteType),
quoteTypeTagType: quoteTypeTagType(row.quoteType),
amountText: formatQuoteMoney(amount),
status: row.status || '',
quoteDate: row.quoteDate || '—'
}
}