/** 订单详情与下单页字段对齐:共享字段定义与格式化。 */ export interface OrderDetailFieldDef { key: string; labelKey: string; } export const ORDER_DETAIL_EXTRA_BASIC_FIELDS: OrderDetailFieldDef[] = [ { key: 'quantity', labelKey: 'order.myOrders.drawer.quantity' }, { key: 'exportCustomsMode', labelKey: 'order.myOrders.drawer.exportCustomsMode' }, { key: 'inboundMethod', labelKey: 'order.myOrders.drawer.inboundMethod' }, { key: 'pickupNo', labelKey: 'order.myOrders.drawer.pickupNo' }, { key: 'pickupTime', labelKey: 'order.myOrders.drawer.pickupTime' }, { key: 'carrierWaybillNo', labelKey: 'order.myOrders.drawer.carrierWaybillNo' }, { key: 'fulfillmentType', labelKey: 'order.myOrders.drawer.fulfillmentType' }, { key: 'fulfillProgress', labelKey: 'order.myOrders.drawer.fulfillProgress' }, { key: 'domesticTrackingNos', labelKey: 'order.myOrders.drawer.domesticTrackingNos' }, { key: 'additionalServices', labelKey: 'order.myOrders.drawer.additionalServices' }, ]; export const ORDER_DETAIL_VALUE_FIELD_MAP: Record = { quantity: ['quantity', 'Quantity'], exportCustomsMode: ['exportCustomsMode', 'ExportCustomsMode'], inboundMethod: ['inboundMethod', 'InboundMethod'], pickupNo: ['pickupNo', 'PickupNo'], pickupTime: ['pickupTime', 'PickupTime'], carrierWaybillNo: ['carrierWaybillNo', 'CarrierWaybillNo'], fulfillmentType: ['fulfillmentType', 'FulfillmentType'], fulfillmentSource: ['fulfillmentSource', 'FulfillmentSource'], fulfillProgress: ['fulfillProgress', 'FulfillProgress'], domesticTrackingNos: ['domesticTrackingNos', 'DomesticTrackingNos'], declaredCurrency: ['declaredCurrency', 'DeclaredCurrency'], declaredSum: ['declaredSum', 'DeclaredSum'], additionalServices: ['additionalServices', 'AdditionalServices'], downstreamSupplierName: ['downstreamSupplierName', 'DownstreamSupplierName'], downstreamSupplierCode: ['downstreamSupplierCode', 'DownstreamSupplierCode'], }; export interface OrderDetailFieldGroup { key: string; labelKey: string; fields: string[]; } export function mergeOrderBasicFields( baseFields: OrderDetailFieldDef[], ): OrderDetailFieldDef[] { const existing = new Set(baseFields.map((f) => f.key)); const extras = ORDER_DETAIL_EXTRA_BASIC_FIELDS.filter((f) => !existing.has(f.key)); return [...baseFields, ...extras]; } export function patchOrderBasicFieldGroups( groups: OrderDetailFieldGroup[], options?: { includeChannel?: boolean }, ): OrderDetailFieldGroup[] { const includeChannel = options?.includeChannel !== false; return groups.map((group) => { if (group.key === 'product') { const fields = [ 'productCode', 'productName', ...(includeChannel ? (['channelCode', 'channelName', 'downstreamSupplierName', 'downstreamSupplierCode'] as const) : []), 'warehouse', 'consigneeCountry', 'consigneeCountryName', 'cargoAttribute', 'quantity', 'exportCustomsMode', 'inboundMethod', 'pickupNo', 'pickupTime', 'carrierWaybillNo', 'fulfillmentType', 'fulfillProgress', 'domesticTrackingNos', ]; return { ...group, fields }; } if (group.key === 'flags') { return { ...group, fields: [...group.fields, 'additionalServices'] }; } return group; }); } export function pickOrderDetailRawValue(order: Record | null | undefined, key: string) { if (!order) return undefined; const keys = ORDER_DETAIL_VALUE_FIELD_MAP[key] || [key]; for (const k of keys) { if (order[k] != null && order[k] !== '') { return order[k]; } } return undefined; } export interface DictRowLike { dictCode?: string | null; dictName?: string | null; } export interface OrderDetailFormatContext { t: (key: string, ...args: any[]) => string; resolveOrderStatusCode: (order: Record | null | undefined) => string | null; getOrderStatusMeta: (code: string | null) => { labelKey: string } | null | undefined; exportCustomsDict?: DictRowLike[]; additionalServiceDict?: DictRowLike[]; } export function parseAdditionalServiceCodes(raw: unknown): string[] { if (Array.isArray(raw)) { return raw.map((x) => String(x ?? '').trim()).filter(Boolean); } if (raw == null || raw === '') return []; const s = String(raw).trim(); if (!s) return []; try { const parsed = JSON.parse(s); if (Array.isArray(parsed)) { return parsed.map((x) => String(x ?? '').trim()).filter(Boolean); } } catch { /* ignore */ } return s .split(/[,,]/) .map((x) => x.trim()) .filter(Boolean); } function dictLabel(rows: DictRowLike[] | undefined, code: string) { const hit = rows?.find((r) => String(r.dictCode ?? '').trim() === code); return hit?.dictName || code; } export function formatOrderDetailExtendedValue( key: string, val: unknown, order: Record, ctx: OrderDetailFormatContext, ): string | null { const { t } = ctx; if (val == null || val === '') return null; if (key === 'exportCustomsMode') { const code = String(val).trim(); return dictLabel(ctx.exportCustomsDict, code); } if (key === 'inboundMethod') { const code = String(val).trim(); const labelKey = `order.myOrders.drawer.inboundMethod.${code}`; const translated = t(labelKey); return translated !== labelKey ? translated : code; } if (key === 'fulfillmentType') { const code = String(val).trim() || 'direct'; if (code === 'warehouse') { return t('order.fulfillOrders.badge'); } return t('order.waybillManage.fulfillmentType.direct'); } if (key === 'fulfillmentSource') { const code = String(val).trim(); const labelKey = `order.fulfillOrders.source.${code}`; const translated = t(labelKey); return translated !== labelKey ? translated : code; } if (key === 'fulfillProgress') { const code = String(val).trim(); const labelKey = `order.fulfillOrders.progress.${code}`; const translated = t(labelKey); return translated !== labelKey ? translated : code; } if (key === 'additionalServices') { const codes = parseAdditionalServiceCodes(val); if (!codes.length) return null; return codes.map((code) => dictLabel(ctx.additionalServiceDict, code)).join('、'); } if (key === 'declaredSum') { const n = Number(val); if (!Number.isFinite(n)) return String(val); const currency = String(pickOrderDetailRawValue(order, 'declaredCurrency') ?? '').trim(); return currency ? `${currency} ${n.toFixed(2)}` : n.toFixed(2); } if (key === 'pickupTime' || key === 'createTime' || key === 'updateTime') { return String(val); } if (key === 'quantity') { return String(val); } return String(val); } export const ORDER_DETAIL_DECLARATION_COLUMNS = [ { key: 'cnName', labelKey: 'order.myOrders.drawer.declarationCnName', width: 120 }, { key: 'enName', labelKey: 'order.myOrders.drawer.declarationEnName', width: 120 }, { key: 'sku', labelKey: 'order.myOrders.drawer.declarationSku', width: 100 }, { key: 'unit', labelKey: 'order.myOrders.drawer.declarationUnit', width: 60 }, { key: 'unitPrice', labelKey: 'order.myOrders.drawer.declarationUnitPrice', width: 80 }, { key: 'unitWeight', labelKey: 'order.myOrders.drawer.declarationUnitWeight', width: 80 }, { key: 'quantity', labelKey: 'order.myOrders.drawer.declarationQuantity', width: 60 }, { key: 'amount', labelKey: 'order.myOrders.drawer.declarationAmount', width: 80 }, { key: 'weight', labelKey: 'order.myOrders.drawer.declarationWeight', width: 80 }, { key: 'imHsCode', labelKey: 'order.myOrders.drawer.declarationImHsCode', width: 100 }, { key: 'exHsCode', labelKey: 'order.myOrders.drawer.declarationExHsCode', width: 100 }, { key: 'declareElement', labelKey: 'order.myOrders.drawer.declarationDeclareElement', width: 160 }, { key: 'productId', labelKey: 'order.myOrders.drawer.declarationProductId', width: 130 }, { key: 'nonStdProductId', labelKey: 'order.myOrders.drawer.declarationNonStdProductId', width: 140 }, { key: 'stdProductId', labelKey: 'order.myOrders.drawer.declarationStdProductId', width: 140 }, { key: 'skuImage', labelKey: 'order.myOrders.drawer.declarationSkuImage', width: 56 }, { key: 'category', labelKey: 'order.myOrders.drawer.declarationCategory', width: 80 }, { key: 'brand', labelKey: 'order.myOrders.drawer.declarationBrand', width: 80 }, { key: 'brandType', labelKey: 'order.myOrders.drawer.declarationBrandType', width: 80 }, { key: 'isMagnetic', labelKey: 'order.myOrders.drawer.declarationIsMagnetic', width: 80 }, { key: 'distribution', labelKey: 'order.myOrders.drawer.declarationDistribution', width: 100 }, { key: 'material', labelKey: 'order.myOrders.drawer.declarationMaterial', width: 80 }, { key: 'enMaterial', labelKey: 'order.myOrders.drawer.declarationEnMaterial', width: 100 }, { key: 'purpose', labelKey: 'order.myOrders.drawer.declarationPurpose', width: 80 }, { key: 'attributes', labelKey: 'order.myOrders.drawer.declarationAttributes', width: 80 }, { key: 'originCountry', labelKey: 'order.myOrders.drawer.declarationOriginCountry', width: 80 }, { key: 'salesLink', labelKey: 'order.myOrders.drawer.declarationSalesLink', width: 120 }, { key: 'model', labelKey: 'order.myOrders.drawer.declarationModel', width: 80 }, { key: 'specifications', labelKey: 'order.myOrders.drawer.declarationSpecifications', width: 80 }, { key: 'comment', labelKey: 'order.myOrders.drawer.declarationComment', width: 120 }, ] as const; export function normalizeDeclarationItemRow(row: Record) { const imHsCode = row.imHsCode ?? row.ImHsCode ?? row.hsCode ?? row.HsCode ?? row.exHsCode ?? row.ExHsCode ?? ''; const exHsCode = row.exHsCode ?? row.ExHsCode ?? row.hsCode ?? row.HsCode ?? row.imHsCode ?? row.ImHsCode ?? ''; return { ...row, imHsCode, exHsCode, declareElement: row.declareElement ?? row.DeclareElement ?? '', productId: row.productId ?? row.ProductId ?? '', nonStdProductId: row.nonStdProductId ?? row.NonStdProductId ?? '', stdProductId: row.stdProductId ?? row.StdProductId ?? '', hsCode: row.hsCode ?? row.HsCode ?? exHsCode ?? imHsCode ?? '', isMagnetic: !!row.isMagnetic, }; } export function cloneDeclarationItemRows(rows: Record[]) { return (rows || []).map((row) => normalizeDeclarationItemRow(row)); } export function buildDeclarationPayloadFromRows(rows: Record[]) { return rows.map((row) => ({ cnName: row.cnName || undefined, enName: row.enName || undefined, sku: row.sku || undefined, unit: row.unit || undefined, unitPrice: row.unitPrice != null ? Number(row.unitPrice) : undefined, unitWeight: row.unitWeight != null ? Number(row.unitWeight) : undefined, quantity: row.quantity != null ? Number(row.quantity) : undefined, amount: row.amount != null ? Number(row.amount) : undefined, weight: row.weight != null ? Number(row.weight) : undefined, imHsCode: row.imHsCode || row.exHsCode || row.hsCode || undefined, exHsCode: row.exHsCode || row.imHsCode || row.hsCode || undefined, declareElement: row.declareElement || undefined, productId: row.productId || undefined, nonStdProductId: row.nonStdProductId || undefined, stdProductId: row.stdProductId || undefined, skuImage: row.skuImage || undefined, category: row.category || undefined, brand: row.brand || undefined, brandType: row.brandType || undefined, isMagnetic: !!row.isMagnetic, distribution: row.distribution || undefined, material: row.material || undefined, enMaterial: row.enMaterial || undefined, purpose: row.purpose || undefined, attributes: row.attributes || undefined, originCountry: row.originCountry || undefined, salesLink: row.salesLink || undefined, model: row.model || undefined, specifications: row.specifications || undefined, comment: row.comment || undefined, })); }