This commit is contained in:
zlwu committed 2026-08-27 19:38:01 +08:00
1 parent 4611dbc2b2
commit ebf006eeff
46 files changed
+36802 -20974

No files matched your search

@@ -40,7 +40,11 @@ export function mapPlanProductToFormRow(item: PlanProduct, index: number): PlanF
.map(row => ({
brandId: String(row.brandId || ''),
brandName: String(row.brandName || ''),
qty: Number(row.qty || 0)
qty: Number(row.qty || 0),
price:
row.unitPrice != null && Number.isFinite(Number(row.unitPrice))
? Number(row.unitPrice)
: undefined
}))
.filter(row => Number.isFinite(row.qty) && row.qty > 0)
return {
@@ -28,8 +28,7 @@ function isTruthyHazardFlag(value: unknown) {
}
export function resolveProductHazardFlags(product: HazardFlagProduct) {
const isToxic =
isTruthyHazardFlag(product.isToxic) || isTruthyHazardFlag(product.is_toxic)
const isToxic = isTruthyHazardFlag(product.isToxic) || isTruthyHazardFlag(product.is_toxic)
const isExplosive =
isTruthyHazardFlag(product.isExplosive) || isTruthyHazardFlag(product.is_explosive)
return { isToxic, isExplosive }
@@ -70,7 +69,7 @@ export function getProductCertUrl(product: PlanProduct, key: HazardCertSlotKey):
export function splitProductCertUrls(raw?: string): string[] {
return String(raw || '')
.split(',')
.map(item => item.trim())
.map((item) => item.trim())
.filter(Boolean)
}
@@ -86,7 +85,7 @@ export function isProductCertSlotFilled(product: PlanProduct, key: HazardCertSlo
export function isProductCertComplete(product: PlanProduct): boolean {
const slots = getRequiredCertSlots(product)
if (!slots.length) return true
return slots.every(slot => isProductCertSlotFilled(product, slot.key))
return slots.every((slot) => isProductCertSlotFilled(product, slot.key))
}
/** 产品名称后追加易制毒/易制爆标识:毒、爆,或「毒 爆」 */
@@ -101,19 +100,17 @@ export function formatPlProductNameWithHazardMarks(product: HazardFlagProduct) {
}
/** 从 CRM 产品主数据读取易制毒/易制爆标识(覆盖计划产品快照字段) */
export async function enrichPlanProductsHazardFromCrm<T extends HazardFlagProduct & { productId: string }>(
products: T[]
): Promise<T[]> {
export async function enrichPlanProductsHazardFromCrm<
T extends HazardFlagProduct & { productId: string }
>(products: T[]): Promise<T[]> {
if (!products.length) return products
const lookupIds = [
...new Set(products.map(product => product.productId).filter(Boolean))
]
const lookupIds = [...new Set(products.map((product) => product.productId).filter(Boolean))]
if (!lookupIds.length) return products
const hazardMap = new Map<string, { isToxic: number; isExplosive: number; taxRate?: number }>()
await Promise.all(
lookupIds.map(async productId => {
lookupIds.map(async (productId) => {
try {
const res = await fetchProductDetail({ id: productId })
const data = (res as { data?: Record<string, unknown> }).data ?? res
@@ -130,7 +127,7 @@ export async function enrichPlanProductsHazardFromCrm<T extends HazardFlagProduc
})
)
return products.map(product => {
return products.map((product) => {
const fromCrm = hazardMap.get(product.productId)
if (!fromCrm) return product
return {
@@ -143,11 +140,11 @@ export async function enrichPlanProductsHazardFromCrm<T extends HazardFlagProduc
}
export function findMissingHazardCerts(products: PlanProduct[]) {
return products.filter(p => isHazardProduct(p) && !isProductCertComplete(p))
return products.filter((p) => isHazardProduct(p) && !isProductCertComplete(p))
}
export function planHasHazardProducts(products: PlanProduct[] | undefined) {
return (products ?? []).some(p => isHazardProduct(p))
return (products ?? []).some((p) => isHazardProduct(p))
}
export function isHazardCertReady(plan: { hazardCertReady?: number } | null | undefined) {
@@ -179,8 +176,8 @@ export function buildMissingHazardCertReadyMessage(
function formatMissingCertLabels(product: PlanProduct): string {
const missing = getRequiredCertSlots(product)
.filter(slot => !isProductCertSlotFilled(product, slot.key))
.map(slot => slot.label)
.filter((slot) => !isProductCertSlotFilled(product, slot.key))
.map((slot) => slot.label)
return missing.join('、')
}
@@ -188,15 +185,12 @@ export function buildMissingHazardCertMessage(products: PlanProduct[]) {
const missing = findMissingHazardCerts(products)
if (!missing.length) return ''
const details = missing
.map(p => `「${p.productName}」须补充:${formatMissingCertLabels(p)}`)
.map((p) => `「${p.productName}」须补充:${formatMissingCertLabels(p)}`)
.join(';')
return `以下产品证书尚未齐全:${details}`
}
export const HAZARD_CERT_REQUIREMENT_LINES = [
'易制毒:购买证、运输证',
'易制爆:合法证明'
] as const
export const HAZARD_CERT_REQUIREMENT_LINES = ['易制毒:购买证、运输证', '易制爆:合法证明'] as const
export const HAZARD_CERT_READY_CONFIRM_HINT =
'计划内产品仅分为易制毒、易制爆或普通产品,同一产品不会兼具两种危化属性。' +
@@ -213,3 +207,23 @@ export function buildHazardCertReadyConfirmMessage(): string {
'确认后可安排运输;之后仍可在本页补充上传附件。'
].join('<br>')
}
/** 批量证书齐备确认弹窗正文 */
export function buildBatchHazardCertReadyConfirmMessage(count: number): string {
return [
`确认将所选 ${count} 条运输计划标记为危化品证书已齐备?`,
'',
...HAZARD_CERT_REQUIREMENT_LINES,
'',
'确认后可安排运输;之后仍可在本页补充上传附件。'
].join('<br>')
}
/** 批量取消证书齐备确认弹窗正文 */
export function buildBatchHazardCertUnmarkConfirmMessage(count: number): string {
const prefix =
count === 1
? '确认取消该计划的证书齐备状态?'
: `确认取消所选 ${count} 条运输计划的证书齐备状态?`
return `${prefix}取消后将无法安排运输。`
}