feat: 完成客户端联调与通用列表组件
This commit is contained in:
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
@@ -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`)
|
||||
|
||||
Reference in New Issue
Block a user