feat(web-admin): add mp CRM quote card query helpers.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
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), '—')
|
||||
})
|
||||
})
|
||||
@@ -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 || '—'
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user