优化
This commit is contained in:
@@ -101,6 +101,8 @@ describe('GlobalSmartLoadingView', () => {
|
|||||||
expect(wrapper.text()).toContain('IN-2')
|
expect(wrapper.text()).toContain('IN-2')
|
||||||
expect(wrapper.text()).not.toContain('ORD-1')
|
expect(wrapper.text()).not.toContain('ORD-1')
|
||||||
expect(wrapper.text()).not.toContain('ORD-2')
|
expect(wrapper.text()).not.toContain('ORD-2')
|
||||||
|
expect(wrapper.get('.candidate-pane').text()).toContain('120 kg')
|
||||||
|
expect(wrapper.get('.candidate-pane').text()).toContain('2.4 m³')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('uses the top-level container channel snapshot without expecting a nested snapshot', async () => {
|
it('uses the top-level container channel snapshot without expecting a nested snapshot', async () => {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ const editable = computed(() => plan.value?.canEdit === true)
|
|||||||
const assignable = computed(() => plan.value?.canAssign === true)
|
const assignable = computed(() => plan.value?.canAssign === true)
|
||||||
const selectedPlanStatus = computed(() => selectedContainer.value?.planStatus || null)
|
const selectedPlanStatus = computed(() => selectedContainer.value?.planStatus || null)
|
||||||
const assignedInboundIds = computed(() => new Set((plan.value?.items || []).map((item) => item.inboundId)))
|
const assignedInboundIds = computed(() => new Set((plan.value?.items || []).map((item) => item.inboundId)))
|
||||||
type SmartLoadingCandidateRow = SmartLoadingCandidate & { sourceCandidates: SmartLoadingCandidate[]; memberInboundCodes: string[]; memberOrderSummaries: string[]; memberOrderCount: number; inboundFragmentCount: number }
|
type SmartLoadingCandidateRow = SmartLoadingCandidate & { sourceCandidates: SmartLoadingCandidate[]; memberInboundCodes: string[]; memberOrderSummaries: string[]; memberOrderCount: number; inboundFragmentCount: number; totalGrossWeightKg: number; totalVolumeCbm: number }
|
||||||
function memberOrderSummaries<T extends { orderId: string; orderNo?: string | null; inboundCode?: string | null }>(members: T[]) {
|
function memberOrderSummaries<T extends { orderId: string; orderNo?: string | null; inboundCode?: string | null }>(members: T[]) {
|
||||||
const orders = new Map<string, { label: string; inboundCodes: string[] }>()
|
const orders = new Map<string, { label: string; inboundCodes: string[] }>()
|
||||||
for (const member of members) {
|
for (const member of members) {
|
||||||
@@ -104,12 +104,20 @@ function groupMemberLabel(group: SmartLoadingPlanCoLoadGroup) {
|
|||||||
? `${group.memberOrderCount} 票`
|
? `${group.memberOrderCount} 票`
|
||||||
: `${group.memberOrderCount} 票 · ${group.inboundFragmentCount} 个入仓片段`
|
: `${group.memberOrderCount} 票 · ${group.inboundFragmentCount} 个入仓片段`
|
||||||
}
|
}
|
||||||
|
function candidateTotalGrossWeight(candidate: SmartLoadingCandidate) {
|
||||||
|
return Number(candidate.unitGrossWeightKg || 0) * Number(candidate.availablePackageCount || 0)
|
||||||
|
}
|
||||||
|
function candidateTotalVolume(candidate: SmartLoadingCandidate) {
|
||||||
|
return candidate.availableVolumeCbm == null
|
||||||
|
? Number(candidate.averageUnitVolumeCbm || 0) * Number(candidate.availablePackageCount || 0)
|
||||||
|
: Number(candidate.availableVolumeCbm)
|
||||||
|
}
|
||||||
const displayedCandidates = computed<SmartLoadingCandidateRow[]>(() => {
|
const displayedCandidates = computed<SmartLoadingCandidateRow[]>(() => {
|
||||||
const rows: SmartLoadingCandidateRow[] = []
|
const rows: SmartLoadingCandidateRow[] = []
|
||||||
const groups = new Map<string, SmartLoadingCandidate[]>()
|
const groups = new Map<string, SmartLoadingCandidate[]>()
|
||||||
for (const candidate of candidates.value) {
|
for (const candidate of candidates.value) {
|
||||||
if (!candidate.coLoadGroupId) {
|
if (!candidate.coLoadGroupId) {
|
||||||
rows.push({ ...candidate, sourceCandidates: [candidate], memberInboundCodes: [candidate.inboundCode || '入仓码暂缺'], memberOrderSummaries: memberOrderSummaries([candidate]), memberOrderCount: 1, inboundFragmentCount: 1 })
|
rows.push({ ...candidate, sourceCandidates: [candidate], memberInboundCodes: [candidate.inboundCode || '入仓码暂缺'], memberOrderSummaries: memberOrderSummaries([candidate]), memberOrderCount: 1, inboundFragmentCount: 1, totalGrossWeightKg: candidateTotalGrossWeight(candidate), totalVolumeCbm: candidateTotalVolume(candidate) })
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
groups.set(candidate.coLoadGroupId, [...(groups.get(candidate.coLoadGroupId) || []), candidate])
|
groups.set(candidate.coLoadGroupId, [...(groups.get(candidate.coLoadGroupId) || []), candidate])
|
||||||
@@ -128,6 +136,8 @@ const displayedCandidates = computed<SmartLoadingCandidateRow[]>(() => {
|
|||||||
memberOrderSummaries: memberOrderSummaries(members),
|
memberOrderSummaries: memberOrderSummaries(members),
|
||||||
memberOrderCount: new Set(members.map((member) => member.orderId)).size,
|
memberOrderCount: new Set(members.map((member) => member.orderId)).size,
|
||||||
inboundFragmentCount: Number(first.memberCount || members.length),
|
inboundFragmentCount: Number(first.memberCount || members.length),
|
||||||
|
totalGrossWeightKg: members.reduce((sum, member) => sum + candidateTotalGrossWeight(member), 0),
|
||||||
|
totalVolumeCbm: members.reduce((sum, member) => sum + candidateTotalVolume(member), 0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return rows
|
return rows
|
||||||
@@ -241,13 +251,15 @@ function preferredContainerId() {
|
|||||||
|
|
||||||
const candidateColumns: DataTableColumn[] = [
|
const candidateColumns: DataTableColumn[] = [
|
||||||
{ key: 'actions', label: '操作', width: 92, fixed: 'left', slotName: 'actions' },
|
{ key: 'actions', label: '操作', width: 92, fixed: 'left', slotName: 'actions' },
|
||||||
{ key: 'inboundCode', prop: 'inboundCode', label: '入仓码', minWidth: 190, fixed: 'left', showOverflowTooltip: true },
|
{ key: 'inboundCode', prop: 'inboundCode', label: '入仓码', minWidth: 140, fixed: 'left', showOverflowTooltip: true },
|
||||||
{ key: 'coLoadGroup', label: '同柜不可拆', minWidth: 210, slotName: 'coLoadGroup' },
|
{ key: 'coLoadGroup', label: '同柜', minWidth: 80, slotName: 'coLoadGroup' },
|
||||||
{ key: 'customerName', prop: 'customerName', label: '客户', minWidth: 140 },
|
{ key: 'customerName', prop: 'customerName', label: '客户', minWidth: 70 },
|
||||||
{ key: 'availablePackageCount', prop: 'availablePackageCount', label: '可用箱数', width: 100 },
|
{ key: 'availablePackageCount', prop: 'availablePackageCount', label: '可用箱数', width: 80 },
|
||||||
{ key: 'cartonIdentityStatus', label: '箱号归属', width: 105, slotName: 'cartonIdentityStatus' },
|
// { key: 'cartonIdentityStatus', label: '箱号归属', width: 105, slotName: 'cartonIdentityStatus' },
|
||||||
{ key: 'unitGrossWeightKg', label: '平均单箱毛重', width: 135, slotName: 'unitGrossWeight' },
|
{ key: 'unitGrossWeightKg', label: '平均单箱毛重', width: 100, slotName: 'unitGrossWeight' },
|
||||||
{ key: 'averageUnitVolumeCbm', label: '平均单箱体积', width: 145, slotName: 'averageUnitVolume' },
|
{ key: 'totalGrossWeightKg', label: '总重量', width: 90, slotName: 'candidateTotalWeight' },
|
||||||
|
{ key: 'averageUnitVolumeCbm', label: '平均单箱体积', width: 100, slotName: 'averageUnitVolume' },
|
||||||
|
{ key: 'totalVolumeCbm', label: '总体积', width: 90, slotName: 'candidateTotalVolume' },
|
||||||
]
|
]
|
||||||
const itemColumns: DataTableColumn[] = [
|
const itemColumns: DataTableColumn[] = [
|
||||||
{ key: 'actions', label: '操作', width: 170, fixed: 'left', slotName: 'actions' },
|
{ key: 'actions', label: '操作', width: 170, fixed: 'left', slotName: 'actions' },
|
||||||
@@ -627,7 +639,9 @@ onMounted(() => { void load(); void loadCustomers() })
|
|||||||
</template>
|
</template>
|
||||||
<template #coLoadGroup="{ row }"><div v-if="row.coLoadGroupId" class="candidate-group"><el-tag size="small" type="warning">{{ row.groupNo }} · {{ row.memberOrderCount }} 票 · {{ row.inboundFragmentCount }} 个入仓片段</el-tag><span v-for="summary in row.memberOrderSummaries" :key="summary">{{ summary }}</span><span>整组 {{ row.groupTotalBoxes }} 箱,必须全量进入同一柜</span><small v-if="row.blockReason" class="candidate-block">{{ row.blockReason }}</small><small v-else-if="row.locked">该组已锁定,不能重复分配</small></div><span v-else>普通单票</span></template>
|
<template #coLoadGroup="{ row }"><div v-if="row.coLoadGroupId" class="candidate-group"><el-tag size="small" type="warning">{{ row.groupNo }} · {{ row.memberOrderCount }} 票 · {{ row.inboundFragmentCount }} 个入仓片段</el-tag><span v-for="summary in row.memberOrderSummaries" :key="summary">{{ summary }}</span><span>整组 {{ row.groupTotalBoxes }} 箱,必须全量进入同一柜</span><small v-if="row.blockReason" class="candidate-block">{{ row.blockReason }}</small><small v-else-if="row.locked">该组已锁定,不能重复分配</small></div><span v-else>普通单票</span></template>
|
||||||
<template #unitGrossWeight="{ row }">{{ formatNumber(Number(row.unitGrossWeightKg || 0), 1) }} kg</template>
|
<template #unitGrossWeight="{ row }">{{ formatNumber(Number(row.unitGrossWeightKg || 0), 1) }} kg</template>
|
||||||
|
<template #candidateTotalWeight="{ row }">{{ formatNumber(Number(row.totalGrossWeightKg || 0), 1) }} kg</template>
|
||||||
<template #averageUnitVolume="{ row }">{{ formatNumber(Number(row.averageUnitVolumeCbm || 0)) }} m³</template>
|
<template #averageUnitVolume="{ row }">{{ formatNumber(Number(row.averageUnitVolumeCbm || 0)) }} m³</template>
|
||||||
|
<template #candidateTotalVolume="{ row }">{{ formatNumber(Number(row.totalVolumeCbm || 0)) }} m³</template>
|
||||||
<template #cartonIdentityStatus><el-tag size="small" type="info" effect="plain">未核验</el-tag></template>
|
<template #cartonIdentityStatus><el-tag size="small" type="info" effect="plain">未核验</el-tag></template>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const detail = {
|
|||||||
},
|
},
|
||||||
order: {
|
order: {
|
||||||
order: { version: 7, receivingWarehouseId: '700000000000000001', channelCode: 'OLD', channelName: '原渠道', customerRemark: '原备注' },
|
order: { version: 7, receivingWarehouseId: '700000000000000001', channelCode: 'OLD', channelName: '原渠道', customerRemark: '原备注' },
|
||||||
cargoes: [{ itemNo: 1, cargoName: '台灯', packageCount: 2, totalQuantity: 20, lengthCm: 40, widthCm: 30, heightCm: 20, grossWeightKg: 18, volumeCbm: 0.048, currency: 'USD', material: '铝', usage: '照明' }],
|
cargoes: [{ itemNo: 1, cargoName: '台灯', packageCount: 2, totalQuantity: 20, lengthCm: 40, widthCm: 30, heightCm: 20, grossWeightKg: 18, volumeCbm: 0.048, currency: 'USD', material: '铝', productUsage: '照明' }],
|
||||||
parties: [], internalNotes: [], statusHistory: [],
|
parties: [], internalNotes: [], statusHistory: [],
|
||||||
},
|
},
|
||||||
timeline: [],
|
timeline: [],
|
||||||
@@ -68,7 +68,13 @@ describe('OrderDeclarationEditorDialog', () => {
|
|||||||
|
|
||||||
expect(ElMessageBox.confirm).toHaveBeenCalledWith(expect.stringContaining('原箱码继续有效,无需更换已打印箱唛'), '确认变更渠道', expect.any(Object))
|
expect(ElMessageBox.confirm).toHaveBeenCalledWith(expect.stringContaining('原箱码继续有效,无需更换已打印箱唛'), '确认变更渠道', expect.any(Object))
|
||||||
expect(ElMessageBox.confirm).toHaveBeenCalledWith(expect.stringContaining('纸面上的旧渠道文字不会自动变化'), '确认变更渠道', expect.any(Object))
|
expect(ElMessageBox.confirm).toHaveBeenCalledWith(expect.stringContaining('纸面上的旧渠道文字不会自动变化'), '确认变更渠道', expect.any(Object))
|
||||||
expect(updatePlatformUnifiedOrderDeclaration).toHaveBeenCalledWith('208', '90001', expect.objectContaining({ expectedVersion: 7, estimatedVolumeCbm: 0.625, channelCode: 'NEW', channelName: '新渠道' }))
|
expect(updatePlatformUnifiedOrderDeclaration).toHaveBeenCalledWith('208', '90001', expect.objectContaining({
|
||||||
|
expectedVersion: 7,
|
||||||
|
estimatedVolumeCbm: 0.625,
|
||||||
|
channelCode: 'NEW',
|
||||||
|
channelName: '新渠道',
|
||||||
|
cargoes: [expect.objectContaining({ itemNo: 1, usage: '照明' })],
|
||||||
|
}))
|
||||||
expect(ElMessage.success).toHaveBeenCalledWith(expect.stringContaining('订单已标记为“曾变更渠道”'))
|
expect(ElMessage.success).toHaveBeenCalledWith(expect.stringContaining('订单已标记为“曾变更渠道”'))
|
||||||
expect(wrapper.emitted('updated')).toHaveLength(1)
|
expect(wrapper.emitted('updated')).toHaveLength(1)
|
||||||
expect(wrapper.emitted('update:modelValue')).toContainEqual([false])
|
expect(wrapper.emitted('update:modelValue')).toContainEqual([false])
|
||||||
@@ -83,11 +89,13 @@ describe('OrderDeclarationEditorDialog', () => {
|
|||||||
expect(wrapper.find('.cargo-table').exists()).toBe(true)
|
expect(wrapper.find('.cargo-table').exists()).toBe(true)
|
||||||
expect(wrapper.text()).toContain('箱数 / 数量')
|
expect(wrapper.text()).toContain('箱数 / 数量')
|
||||||
expect(wrapper.text()).toContain('材质 / 用途')
|
expect(wrapper.text()).toContain('材质 / 用途')
|
||||||
|
expect(wrapper.text()).toContain('铝 / 照明')
|
||||||
expect(wrapper.text()).toContain('2 箱 / 20')
|
expect(wrapper.text()).toContain('2 箱 / 20')
|
||||||
|
|
||||||
const editButton = wrapper.findAll('button').find((button) => button.text() === '编辑')!
|
const editButton = wrapper.findAll('button').find((button) => button.text() === '编辑')!
|
||||||
await editButton.trigger('click')
|
await editButton.trigger('click')
|
||||||
expect(wrapper.find('input[aria-label="币种"]').attributes('readonly')).toBeDefined()
|
expect(wrapper.find('input[aria-label="币种"]').attributes('readonly')).toBeDefined()
|
||||||
|
expect(wrapper.findAllComponents({ name: 'ElInput' }).some((input) => input.props('modelValue') === '照明')).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('preserves the editor when the versioned update fails', async () => {
|
it('preserves the editor when the versioned update fails', async () => {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ function resetForm() {
|
|||||||
hsCode: text(row, 'hsCode'), customsHsCode: text(row, 'customsHsCode'),
|
hsCode: text(row, 'hsCode'), customsHsCode: text(row, 'customsHsCode'),
|
||||||
unitsPerPackage: optionalNumber(row, 'unitsPerPackage'),
|
unitsPerPackage: optionalNumber(row, 'unitsPerPackage'),
|
||||||
unitDeclaredValue: optionalNumber(row, 'unitDeclaredValue'), declaredValue: optionalNumber(row, 'declaredValue'),
|
unitDeclaredValue: optionalNumber(row, 'unitDeclaredValue'), declaredValue: optionalNumber(row, 'declaredValue'),
|
||||||
currency: text(row, 'currency'), material: text(row, 'material'), usage: text(row, 'usage'),
|
currency: text(row, 'currency'), material: text(row, 'material'), usage: text(row, 'productUsage'),
|
||||||
brand: text(row, 'brand'), cargoRemark: text(row, 'cargoRemark') || text(row, 'remark'),
|
brand: text(row, 'brand'), cargoRemark: text(row, 'cargoRemark') || text(row, 'remark'),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user