From 688eddfa77bb2e4ff17dc2320ec17da5637b65ce Mon Sep 17 00:00:00 2001
From: ouyangxq <775153912@qq.com>
Date: Fri, 4 Sep 2026 14:17:36 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../pages/GlobalSmartLoadingView.test.ts | 53 +++++++++++++++++--
.../pages/GlobalSmartLoadingView.vue | 23 ++++++--
.../pages/SmartLoadingWorkbenchView.vue | 6 ++-
3 files changed, 75 insertions(+), 7 deletions(-)
diff --git a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts
index 2d58fb54..59fbba3c 100644
--- a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts
+++ b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts
@@ -255,6 +255,37 @@ describe('GlobalSmartLoadingView', () => {
expect(wrapper.text()).toContain('柜子数量2 个')
})
+ it('selects only the double-clicked channel as a shortcut', async () => {
+ const other = {
+ ...container,
+ id: '9007199254740998',
+ planId: '9007199254740999',
+ cabinetNo: 'CB-2',
+ containerNo: 'MSCU-2',
+ channelCode: 'HDHK',
+ channelName: '合德海卡包税',
+ }
+ vi.mocked(listContainers).mockResolvedValue({ records: [container, other], page: 1, size: 100, total: 2, pages: 1 })
+ mockContainerSearch([container, other])
+ vi.mocked(getSmartLoadingPlanByBooking).mockImplementation(async (bookingId) => ({ ...plan, bookingId }))
+ const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
+ await flushPromises()
+
+ const hedeChannel = wrapper.findAllComponents(ElCheckboxButton).find((item) => item.text() === '合德')!
+ await hedeChannel.find('input').setValue(true)
+ await flushPromises()
+ expect(wrapper.findAll('.channel-tags .el-checkbox-button.is-checked')).toHaveLength(2)
+
+ await hedeChannel.trigger('dblclick')
+ await flushPromises()
+
+ expect(wrapper.findAll('.channel-tags .el-checkbox-button.is-checked').map((item) => item.text())).toEqual(['合德'])
+ expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith(expect.objectContaining({ channelGroupCodes: ['HEDE'] }))
+ expect(listSmartLoadingWorkbenchContainers).toHaveBeenLastCalledWith({ channelGroupCodes: ['HEDE'], page: 1, size: 200 })
+ expect(wrapper.text()).toContain('MSCU-2')
+ expect(wrapper.text()).not.toContain('MSCU-1')
+ })
+
it('merges detailed pricing channels into the same confirmed display group', async () => {
const parcelContainer = {
...container,
@@ -523,9 +554,12 @@ describe('GlobalSmartLoadingView', () => {
expect(assignSmartLoadingGroup).not.toHaveBeenCalled()
})
- it('keeps the package count editor inside its table cell without overflow ellipsis', () => {
+ it('shows the package summary first and opens the editor from an icon', () => {
const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/GlobalSmartLoadingView.vue'), 'utf8')
- expect(source).toContain('
0"')
+ expect(source).toContain('v-if="editingQuantityId === row.id"')
expect(source).toContain(':controls="false"')
expect(source).toContain('@blur="adjust(row)" @keyup.enter="adjust(row)"')
expect(source).not.toContain(' {
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
await flushPromises()
+ await wrapper.find('[aria-label="调整箱数"]').trigger('click')
+ await flushPromises()
const quantityInput = wrapper.findAllComponents(ElInputNumber).find((input) => input.props('modelValue') === 6)
expect(quantityInput?.props('controls')).toBe(false)
quantityInput?.vm.$emit('update:modelValue', 4)
@@ -809,6 +845,8 @@ describe('GlobalSmartLoadingView', () => {
expect(wrapper.text()).toContain('已拣 3 箱')
expect(wrapper.findAll('.row-actions .el-button--danger')).toHaveLength(0)
+ await wrapper.find('[aria-label="调整箱数"]').trigger('click')
+ await flushPromises()
const quantityInput = wrapper.findAllComponents(ElInputNumber).find((input) => input.props('modelValue') === 6)
expect(quantityInput?.props('min')).toBe(3)
expect(wrapper.findAll('button').some((button) => button.text().includes('移除未拣'))).toBe(false)
@@ -832,11 +870,20 @@ describe('GlobalSmartLoadingView', () => {
expect(wrapper.findAll('button').some((button) => button.text().includes('加入'))).toBe(false)
})
- it('limits adjusted package count to the assigned count plus remaining availability', async () => {
+ it('uses the server supplied total package count as the adjustment maximum', async () => {
vi.mocked(listSmartLoadingCandidates).mockResolvedValue(candidatePage([{ accountId: '1', inboundId: '2', orderId: '4', orderNo: 'ORD-1', inboundCode: 'IN-1', warehouseId: '8', channelCode: 'ZBYHK', channelName: '美森正班海卡包税', destinationWarehouseId: '9', destinationWarehouseCode: 'LAX9', destinationWarehouseName: 'LAX9', customerName: '示例企业', goodsSummary: '服装', availablePackageCount: 4, unitGrossWeightKg: 10, unitNetWeightKg: 9, averageUnitVolumeCbm: 0.2, availableVolumeCbm: 0.8, coLoadGroupId: null, groupNo: null, memberCount: null, groupTotalBoxes: null, locked: null, blockReason: null }]))
+ vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue({
+ ...plan,
+ items: [{ ...plan.items[0], totalPackageCount: 10, remainingPackageCount: 4 }],
+ })
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
await flushPromises()
+ expect(wrapper.text()).toContain('使用:6')
+ expect(wrapper.text()).toContain('未用:4')
+ expect(wrapper.text()).not.toContain('共 10 箱')
+ await wrapper.find('[aria-label="调整箱数"]').trigger('click')
+ await flushPromises()
const maxima = wrapper.findAllComponents(ElInputNumber).map((input) => input.props('max'))
expect(maxima).toContain(10)
})
diff --git a/src/modules/container-loading/pages/GlobalSmartLoadingView.vue b/src/modules/container-loading/pages/GlobalSmartLoadingView.vue
index 42b9d1af..f0f5be9f 100644
--- a/src/modules/container-loading/pages/GlobalSmartLoadingView.vue
+++ b/src/modules/container-loading/pages/GlobalSmartLoadingView.vue
@@ -235,7 +235,7 @@ const itemColumns: DataTableColumn[] = [
{ key: 'inboundCode', prop: 'inboundCode', label: '入仓码', minWidth: 140, fixed: 'left', showOverflowTooltip: true },
{ key: 'coLoadGroup', label: '同柜', minWidth: 80, slotName: 'coLoadGroup' },
{ key: 'customerName', prop: 'customerName', label: '客户', minWidth: 70, slotName: 'customerName' },
- { key: 'packageCount', label: '分配箱数', width: 100, slotName: 'packageCount' },
+ { key: 'packageCount', label: '分配箱数', width: 140, slotName: 'packageCount' },
{ key: 'grossWeightKg', label: '毛重', width: 90, slotName: 'weight' },
{ key: 'volumeCbm', label: '体积', width: 90, slotName: 'volume' },
]
@@ -445,6 +445,12 @@ async function selectChannels(codes: string[]) {
candidatePage.value = 1
await loadWorkbenchData()
}
+async function selectOnlyChannel(code: string) {
+ if (selectedChannelCodes.value.length === 1 && selectedChannelCodes.value[0] === code) return
+ selectedChannelCodes.value = [code]
+ candidatePage.value = 1
+ await loadWorkbenchData()
+}
async function applyFilters(model: QueryModel) {
appliedQuery.value = {
...model,
@@ -629,7 +635,14 @@ onMounted(() => { void load(); void loadCustomers() })
渠道
- {{ channel.name }}
+ {{ channel.name }}
- 候选明细
- {{ candidateTotal }} 条
@@ -767,7 +780,7 @@ onMounted(() => { void load(); void loadCustomers() })
删除
- 共 {{ row.totalPackageCount || row.packageCount }} 箱已用 {{ row.packageCount }} 箱未用 {{ row.remainingPackageCount ?? 0 }} 箱
+ 使用:{{ row.packageCount }} 未用:{{ row.remainingPackageCount }}
{{ formatNumber(Number(row.grossWeightKg || 0), 1) }} kg
{{ formatNumber(Number(row.volumeCbm || 0)) }} m³
@@ -851,6 +864,10 @@ onMounted(() => { void load(); void loadCustomers() })
.readonly-status-card p { max-width: 460px; margin: 0; color: var(--cc-muted); line-height: 1.6; }
.meter-title { justify-content: space-between; margin-bottom: 8px; font-size: 12px; }
.package-count-editor { display: grid; min-width: 0; gap: 4px; }
+.package-count-summary { display: grid; gap: 3px; line-height: 1.35; }
+.package-count-used { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
+.package-count-summary strong { font-size: 13px; font-weight: 600; }
+.package-count-summary small { color: var(--cc-muted); font-size: 12px; }
.plan-pane :deep(.package-count-editor .el-input-number) { width: 100%; min-width: 0; }
.assign-dialog p { margin: 0 0 10px; }
.assign-dialog :deep(.el-input-number) { width: 100%; }
diff --git a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue
index bca47fc1..1d9a010b 100644
--- a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue
+++ b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue
@@ -374,7 +374,7 @@ onMounted(load)
{{ row.productNameZh || '未命名货物' }}{{ row.skuCode || '无 SKU' }}
- 共 {{ row.totalPackageCount || row.packageCount }} 箱已用 {{ row.packageCount }} 箱未用 {{ row.remainingPackageCount ?? 0 }} 箱
+ 使用:{{ row.packageCount }} 未用:{{ row.remainingPackageCount }}
{{ formatNumber(Number(row.volumeCbm || 0)) }} m³{{ formatNumber(Number(row.grossWeightKg || 0),1) }} kg
@@ -415,6 +415,10 @@ onMounted(load)
.meter-title { justify-content: space-between; gap: 12px; margin-bottom: 10px; font-size: 13px; }
.row-actions { min-width: 150px; }
.package-count-editor { display: grid; min-width: 0; gap: 4px; }
+.package-count-summary { display: grid; gap: 3px; line-height: 1.35; }
+.package-count-used { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
+.package-count-summary strong { font-size: 13px; font-weight: 600; }
+.package-count-summary small { color: var(--cc-muted); font-size: 12px; }
.workbench :deep(.package-count-editor .el-input-number) { width: 100%; min-width: 0; }
.assign-dialog p { margin: 0 0 10px; }
.assign-dialog :deep(.el-input-number) { width: 100%; }