All checks were successful
Build and Deploy Front / deploy (push) Successful in 5m56s
- 支付弹窗(PC/H5)支持选券与批量支付体验优化,运单管理复用我的订单支付弹窗;立即支付仅允许待支付订单 - 订单详情费用明细展示优惠券抵扣/会员折扣负数行与「含优惠」;价格配置与手工加费过滤抵扣费用项 - 申报明细新增产品标识编码/非标产品标识编码/标准产品标识编码(PC/H5 下单、改单、详情、开放接口文档、公式目录、Excel 模板) - 9610 页「批量申报」改为「创建9610订单」:选运单并补充出口资质备案、电商平台 - 店铺订单批量按钮按动作独立 loading,获取面单限并发并显示进度 - 另含:国家管理、登录门户切换、监控与工作台、公告弹窗、nginx/vite 配置等改动
295 lines
12 KiB
TypeScript
295 lines
12 KiB
TypeScript
/** 订单详情与下单页字段对齐:共享字段定义与格式化。 */
|
||
|
||
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,
|
||
}));
|
||
}
|