Files
shanxia2.0/web-admin/src/composables/usePlToxicProductCertCheck.ts
T
2026-07-05 10:07:24 +08:00

128 lines
4.4 KiB
TypeScript

import { fetchProductDetail } from '@/api/crm/product'
import type { PlanProduct } from '@/api/pl'
export type HazardFlagProduct = {
productId?: string
productName?: string
isToxic?: number
isExplosive?: number
is_toxic?: number
is_explosive?: number
}
function isTruthyHazardFlag(value: unknown) {
return value === 1 || value === true || value === '1'
}
export function resolveProductHazardFlags(product: HazardFlagProduct) {
const isToxic =
isTruthyHazardFlag(product.isToxic) || isTruthyHazardFlag(product.is_toxic)
const isExplosive =
isTruthyHazardFlag(product.isExplosive) || isTruthyHazardFlag(product.is_explosive)
return { isToxic, isExplosive }
}
export function isHazardProduct(product: Pick<PlanProduct, 'isToxic' | 'isExplosive'>) {
const flags = resolveProductHazardFlags(product)
return flags.isToxic || flags.isExplosive
}
export function getHazardProductLabel(product: Pick<PlanProduct, 'isToxic' | 'isExplosive'>) {
const flags = resolveProductHazardFlags(product)
if (flags.isExplosive) return '易制爆'
if (flags.isToxic) return '易制毒'
return ''
}
/** 产品名称后追加易制毒/易制爆标识:毒、爆,或「毒 爆」 */
export function formatPlProductNameWithHazardMarks(product: HazardFlagProduct) {
const name = product.productName || ''
const { isToxic, isExplosive } = resolveProductHazardFlags(product)
const marks: string[] = []
if (isToxic) marks.push('毒')
if (isExplosive) marks.push('爆')
if (!marks.length) return name
return `${name}${marks.join(' ')}`
}
/** 从 CRM 产品主数据读取易制毒/易制爆标识(覆盖计划产品快照字段) */
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))
]
if (!lookupIds.length) return products
const hazardMap = new Map<string, { isToxic: number; isExplosive: number; taxRate?: number }>()
await Promise.all(
lookupIds.map(async productId => {
try {
const res = await fetchProductDetail({ id: productId })
const data = (res as { data?: Record<string, unknown> }).data ?? res
const row = data as Record<string, unknown>
const rawTaxRate = row.taxRate ?? row.tax_rate
hazardMap.set(productId, {
isToxic: Number(row.isToxic ?? row.is_toxic ?? 0),
isExplosive: Number(row.isExplosive ?? row.is_explosive ?? 0),
taxRate: rawTaxRate != null && rawTaxRate !== '' ? Number(rawTaxRate) : undefined
})
} catch {
// 单条产品查询失败时跳过
}
})
)
return products.map(product => {
const fromCrm = hazardMap.get(product.productId)
if (!fromCrm) return product
return {
...product,
isToxic: fromCrm.isToxic,
isExplosive: fromCrm.isExplosive,
taxRate: product.taxRate ?? fromCrm.taxRate
}
})
}
export function findMissingHazardCerts(products: PlanProduct[]) {
return products.filter(
p => isHazardProduct(p) && (!p.purchaseCertUrl?.trim() || !p.transportCertUrl?.trim())
)
}
export function planHasHazardProducts(products: PlanProduct[] | undefined) {
return (products ?? []).some(p => isHazardProduct(p))
}
export function isHazardCertReady(plan: { hazardCertReady?: number } | null | undefined) {
return Number(plan?.hazardCertReady ?? 0) === 1
}
/** 含危化品且尚未人工确认证书齐备时,阻断安排运输 */
export function shouldBlockTransportForHazardCert(
plan: { hazardCertReady?: number; products?: PlanProduct[] } | null | undefined,
products?: PlanProduct[]
) {
const prods = products ?? plan?.products
if (!planHasHazardProducts(prods)) return false
return !isHazardCertReady(plan)
}
export function buildMissingHazardCertReadyMessage(
plan: { hazardCertReady?: number; products?: PlanProduct[] } | null | undefined,
products?: PlanProduct[]
) {
if (!shouldBlockTransportForHazardCert(plan, products)) return ''
return '该计划危化品证书尚未确认齐备'
}
export function buildMissingHazardCertMessage(products: PlanProduct[]) {
const missing = findMissingHazardCerts(products)
if (!missing.length) return ''
const names = missing.map(p => `「${p.productName}」`).join('、')
return `以下产品须上传购买证和合法使用证明:${names}`
}