feat: 完成客户端联调与通用列表组件

This commit is contained in:
2026-08-01 12:17:33 +08:00
parent be7675954a
commit beb86d53e7
31 changed files with 1326 additions and 378 deletions
+35
View File
@@ -0,0 +1,35 @@
export async function copyText(value: string) {
if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {
try {
await navigator.clipboard.writeText(value)
return
} catch {
// In insecure development contexts the Clipboard API may exist but reject.
}
}
if (typeof document === 'undefined' || !document.body) {
throw new Error('Clipboard is unavailable')
}
const textarea = document.createElement('textarea')
textarea.value = value
textarea.readOnly = true
textarea.setAttribute('aria-hidden', 'true')
Object.assign(textarea.style, {
position: 'fixed',
inset: '0 auto auto -9999px',
opacity: '0',
pointerEvents: 'none',
})
document.body.appendChild(textarea)
textarea.select()
try {
if (typeof document.execCommand !== 'function' || !document.execCommand('copy')) {
throw new Error('Clipboard copy failed')
}
} finally {
textarea.remove()
}
}
+17 -1
View File
@@ -50,7 +50,7 @@ function validDraft() {
destinationType: 'FBA',
amazonWarehouseCode: 'ONT8',
shipmentId: 'FBA-001',
items: [{ ...createEmptyCargoItem('cargo-1'), cargoNameCn: '家居用品', pieces: 100, grossWeightKg: 1200, volumeCbm: 3.5, containerType: '40HQ', containerCount: 1 }],
items: [{ ...createEmptyCargoItem('cargo-1'), sku: 'SKU-001', upc: '012345678905', cargoNameCn: '家居用品', pieces: 100, grossWeightKg: 1200, volumeCbm: 3.5, containerType: '40HQ', containerCount: 1 }],
}
}
@@ -97,6 +97,22 @@ test('requires enabled-party snapshots and order addresses before submission', (
assert.ok(errors.includes('请填写本单收货地址'))
})
test('requires FBA reference, warehouse, shipment, SKU and UPC fields', () => {
const draft = validDraft()
draft.referenceNo = ''
draft.amazonWarehouseCode = ''
draft.shipmentId = ''
draft.items[0].sku = ''
draft.items[0].upc = ''
const errors = validateFirstLegOrderDraft(draft)
assert.ok(errors.includes('FBA 订单请填写客户参考号'))
assert.ok(errors.includes('FBA 订单请填写 Amazon 仓库编码'))
assert.ok(errors.includes('FBA 订单请填写 Shipment ID'))
assert.ok(errors.includes('第 1 条货物缺少客户 SKU'))
assert.ok(errors.includes('第 1 条货物缺少 UPC'))
})
test('does not require container details for non-FCL cargo', () => {
const draft = validDraft()
draft.transportMode = 'AIR'
+14 -1
View File
@@ -41,6 +41,7 @@ export function createEmptyCargoItem(id = `cargo-${Date.now()}`): FirstLegCargoI
return {
id,
sku: '',
upc: '',
cargoNameCn: '',
cargoNameEn: '',
pieces: 1,
@@ -63,20 +64,32 @@ export function validateFirstLegOrderDraft(draft: FirstLegOrderDraft) {
if (!draft.origin.trim()) errors.push('请填写起运地')
if (!draft.destination.trim()) errors.push('请填写目的地')
if (!draft.destinationCountryCode.trim()) errors.push('请填写目的国两位代码')
if (!/^[A-Za-z]{2}$/.test(draft.destinationCountryCode.trim())) errors.push('请输入两位英文字母的目的国代码')
if (!draft.destinationWarehouseName.trim()) errors.push('请填写目的仓名称')
if (!draft.channelCode.trim() || !draft.channelName.trim()) errors.push('请填写渠道编码和渠道名称')
if (!draft.receivingWarehouseId) errors.push('请选择平台收货仓')
if (!draft.shipperPartyId || !draft.shipperPartySnapshot || !draft.shipper.trim()) errors.push('请选择发货单位')
if (draft.shipperPartySnapshot && !draft.shipperPartySnapshot.contactName.trim()) errors.push('请填写发货联系人')
if (draft.shipperPartySnapshot && !draft.shipperPartySnapshot.phone.trim()) errors.push('请填写发货联系电话')
if (draft.shipperPartySnapshot && !draft.shipperPartySnapshot.address.trim()) errors.push('请填写本单发货地址')
if (!draft.consigneePartyId || !draft.consigneePartySnapshot || !draft.consignee.trim()) errors.push('请选择收货单位')
if (draft.consigneePartySnapshot && !draft.consigneePartySnapshot.contactName.trim()) errors.push('请填写收货联系人')
if (draft.consigneePartySnapshot && !draft.consigneePartySnapshot.phone.trim()) errors.push('请填写收货联系电话')
if (draft.consigneePartySnapshot && !draft.consigneePartySnapshot.address.trim()) errors.push('请填写本单收货地址')
if (draft.items.length === 0) errors.push('请至少添加一条货物明细')
if (draft.destinationType === 'FBA') {
if (!draft.referenceNo.trim()) errors.push('FBA 订单请填写客户参考号')
if (!draft.amazonWarehouseCode.trim()) errors.push('FBA 订单请填写 Amazon 仓库编码')
if (!draft.shipmentId.trim()) errors.push('FBA 订单请填写 Shipment ID')
}
draft.items.forEach((item, index) => {
const line = `第 ${index + 1} 条货物`
if (!item.cargoNameCn.trim()) errors.push(`${line}缺少中文品名`)
if (!item.packageType.trim()) errors.push(`${line}缺少包装类型`)
if (draft.destinationType === 'FBA' && !item.sku.trim()) errors.push(`${line}缺少客户 SKU`)
if (draft.destinationType === 'FBA' && !item.upc.trim()) errors.push(`${line}缺少 UPC`)
if (!Number.isInteger(item.pieces) || item.pieces <= 0) errors.push(`${line}件数必须为正整数`)
if (item.grossWeightKg <= 0) errors.push(`${line}毛重必须大于 0`)
if (item.volumeCbm <= 0) errors.push(`${line}体积必须大于 0`)