front/src/views/order/components/orderDetailFieldConfig.ts
zzh b178a2a35d
All checks were successful
Build and Deploy Front / deploy (push) Successful in 5m56s
feat: 支付选券、优惠入应收展示、申报产品标识编码、创建9610订单等
- 支付弹窗(PC/H5)支持选券与批量支付体验优化,运单管理复用我的订单支付弹窗;立即支付仅允许待支付订单
- 订单详情费用明细展示优惠券抵扣/会员折扣负数行与「含优惠」;价格配置与手工加费过滤抵扣费用项
- 申报明细新增产品标识编码/非标产品标识编码/标准产品标识编码(PC/H5 下单、改单、详情、开放接口文档、公式目录、Excel 模板)
- 9610 页「批量申报」改为「创建9610订单」:选运单并补充出口资质备案、电商平台
- 店铺订单批量按钮按动作独立 loading,获取面单限并发并显示进度
- 另含:国家管理、登录门户切换、监控与工作台、公告弹窗、nginx/vite 配置等改动
2026-10-19 16:34:06 +08:00

295 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** 订单详情与下单页字段对齐:共享字段定义与格式化。 */
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<string, string[]> = {
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<string, any> | 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<string, any> | 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<string, any>,
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<string, any>) {
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<string, any>[]) {
return (rows || []).map((row) => normalizeDeclarationItemRow(row));
}
export function buildDeclarationPayloadFromRows(rows: Record<string, any>[]) {
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,
}));
}