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('
{ 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() }) - + @@ -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) - + @@ -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%; }