优化
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import ElementPlus, { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import ElementPlus, { ElInputNumber, ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { AxiosError } from 'axios'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { flushPromises, mount } from '@vue/test-utils'
|
||||
@@ -71,10 +71,28 @@ describe('GlobalSmartLoadingView', () => {
|
||||
expect(listSmartLoadingCandidates).toHaveBeenCalledWith(container.id, container.warehouseId)
|
||||
expect(wrapper.text()).toContain('候选入库单与货物')
|
||||
expect(wrapper.text()).toContain('美森正班海卡包税')
|
||||
expect(wrapper.text()).toContain('ORD-2')
|
||||
expect(wrapper.text()).toContain('CB-1 装柜方案')
|
||||
expect(wrapper.text()).toContain('LP-99')
|
||||
expect(wrapper.text()).toContain('ORD-1')
|
||||
expect(wrapper.text()).toContain('IN-2')
|
||||
expect(wrapper.text()).toContain('MSCU-1 装柜方案')
|
||||
expect(wrapper.text()).not.toContain('LP-99')
|
||||
expect(wrapper.text()).toContain('IN-1')
|
||||
expect(wrapper.text()).not.toContain('ORD-1')
|
||||
expect(wrapper.text()).not.toContain('ORD-2')
|
||||
})
|
||||
|
||||
it('shows one user-facing container number and hides internal manual or split references', async () => {
|
||||
vi.mocked(listContainers).mockResolvedValue({
|
||||
records: [{ ...container, cabinetNo: 'CAB-20260814-01', containerNo: 'SPLIT-814022117898chain1' }],
|
||||
page: 1,
|
||||
size: 100,
|
||||
total: 1,
|
||||
pages: 1,
|
||||
})
|
||||
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.text()).toContain('CAB-20260814-01')
|
||||
expect(wrapper.text()).not.toContain('SPLIT-814022117898chain1')
|
||||
expect(wrapper.text()).not.toContain('LP-99')
|
||||
})
|
||||
|
||||
it('groups containers by channel and reloads candidates when the channel changes', async () => {
|
||||
@@ -83,6 +101,7 @@ describe('GlobalSmartLoadingView', () => {
|
||||
id: '9007199254740998',
|
||||
planId: '9007199254740999',
|
||||
cabinetNo: 'CB-2',
|
||||
containerNo: 'MSCU-2',
|
||||
channelCode: 'HDHK',
|
||||
channelName: '合德海卡包税',
|
||||
}
|
||||
@@ -92,8 +111,9 @@ describe('GlobalSmartLoadingView', () => {
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.findAll('.container-option')).toHaveLength(1)
|
||||
expect(wrapper.text()).toContain('CB-1')
|
||||
expect(wrapper.text()).not.toContain('CB-2')
|
||||
expect(wrapper.text()).toContain('MSCU-1')
|
||||
expect(wrapper.text()).not.toContain('MSCU-2')
|
||||
expect(wrapper.text()).not.toContain('个柜次')
|
||||
|
||||
const tab = wrapper.findAll('[role="tab"]').find((item) => item.text().includes('合德海卡包税'))
|
||||
expect(tab).toBeDefined()
|
||||
@@ -101,8 +121,8 @@ describe('GlobalSmartLoadingView', () => {
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.findAll('.container-option')).toHaveLength(1)
|
||||
expect(wrapper.text()).toContain('CB-2')
|
||||
expect(wrapper.text()).not.toContain('CB-1')
|
||||
expect(wrapper.text()).toContain('MSCU-2')
|
||||
expect(wrapper.text()).not.toContain('MSCU-1')
|
||||
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith(other.id, other.warehouseId)
|
||||
})
|
||||
|
||||
@@ -129,16 +149,14 @@ describe('GlobalSmartLoadingView', () => {
|
||||
expect(wrapper.findAll('button[aria-label="列设置"]')).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('keeps unsupported prototype filters out of the real workbench', async () => {
|
||||
it('keeps only customer, inbound code and destination warehouse filters', async () => {
|
||||
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
|
||||
const statusField = wrapper.findComponent(QueryToolbar).props('fields')
|
||||
.find((field: { key: string }) => field.key === 'status')
|
||||
expect(statusField?.options).toEqual([
|
||||
{ label: '待装柜', value: 'WAIT_LOADING' },
|
||||
{ label: '预装柜中', value: 'EDITING' },
|
||||
{ label: '拣货中', value: 'LOADING' },
|
||||
const fields = wrapper.findComponent(QueryToolbar).props('fields') as Array<{ key: string; options?: Array<{ label: string; value: string }> }>
|
||||
expect(fields.map((field) => field.key)).toEqual(['customerId', 'inboundCode', 'destinationWarehouse'])
|
||||
expect(fields.find((field) => field.key === 'destinationWarehouse')?.options).toEqual([
|
||||
{ label: 'LAX9', value: '9' },
|
||||
])
|
||||
|
||||
expect(wrapper.text()).not.toContain('税率')
|
||||
@@ -152,11 +170,11 @@ describe('GlobalSmartLoadingView', () => {
|
||||
await flushPromises()
|
||||
|
||||
expect(getSmartLoadingPlanByBooking).toHaveBeenCalledWith(container.id)
|
||||
expect(wrapper.text()).toContain('CB-1 装柜方案')
|
||||
expect(wrapper.text()).toContain('MSCU-1 装柜方案')
|
||||
})
|
||||
|
||||
it('does not overwrite the container status when selecting it', async () => {
|
||||
const waiting = { ...container, id: '9007199254740995', planId: '9007199254740996', cabinetNo: 'CB-WAIT', planStatus: 'WAIT_LOADING' as const }
|
||||
it('keeps waiting and editing empty containers without exposing their status labels', async () => {
|
||||
const waiting = { ...container, id: '9007199254740995', planId: '9007199254740996', cabinetNo: 'CB-WAIT', containerNo: null, planStatus: 'WAIT_LOADING' as const }
|
||||
vi.mocked(listContainers).mockResolvedValue({ records: [container, waiting], page: 1, size: 100, total: 2, pages: 1 })
|
||||
vi.mocked(getSmartLoadingPlanByBooking).mockImplementation(async (bookingId) => (
|
||||
bookingId === waiting.id
|
||||
@@ -167,31 +185,27 @@ describe('GlobalSmartLoadingView', () => {
|
||||
await flushPromises()
|
||||
|
||||
const waitingOption = wrapper.findAll('.container-option').find((item) => item.text().includes('CB-WAIT'))!
|
||||
expect(waitingOption.text()).toContain('待装柜')
|
||||
expect(waitingOption.text()).toContain('CB-WAIT')
|
||||
expect(waitingOption.text()).not.toContain('待装柜')
|
||||
|
||||
await waitingOption.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(getSmartLoadingPlanByBooking).toHaveBeenCalledWith(waiting.id)
|
||||
expect(waitingOption.text()).toContain('待装柜')
|
||||
expect(waitingOption.text()).toContain('CB-WAIT')
|
||||
expect(waitingOption.text()).not.toContain('拣货中')
|
||||
})
|
||||
|
||||
it('keeps picking containers editable while hiding the push action', async () => {
|
||||
it('excludes picking containers from the empty-container workbench', async () => {
|
||||
const pushed = { ...container, id: '9007199254740995', planId: '9007199254740996', cabinetNo: 'CB-2', planStatus: 'LOADING' as const }
|
||||
const pickingPlan = { ...plan, bookingId: pushed.id, status: 'LOADING' as const }
|
||||
vi.mocked(listContainers).mockResolvedValue({ records: [pushed], page: 1, size: 100, total: 1, pages: 1 })
|
||||
vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue(pickingPlan)
|
||||
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
|
||||
expect(getSmartLoadingPlanByBooking).toHaveBeenCalledWith(pushed.id)
|
||||
expect(listSmartLoadingCandidates).toHaveBeenCalledWith(pushed.id, pushed.warehouseId)
|
||||
expect(wrapper.text()).toContain('CB-2')
|
||||
expect(wrapper.text()).toContain('拣货中')
|
||||
expect(wrapper.text()).toContain('智能推荐')
|
||||
expect(wrapper.text()).toContain('加入')
|
||||
expect(wrapper.findAll('button').some((item) => item.text().trim() === '推送预装')).toBe(false)
|
||||
expect(getSmartLoadingPlanByBooking).not.toHaveBeenCalled()
|
||||
expect(listSmartLoadingCandidates).not.toHaveBeenCalled()
|
||||
expect(wrapper.findAll('.container-option')).toHaveLength(0)
|
||||
expect(wrapper.text()).not.toContain('CB-2')
|
||||
})
|
||||
|
||||
it('hides completed containers from the smart loading workbench', async () => {
|
||||
@@ -206,6 +220,7 @@ describe('GlobalSmartLoadingView', () => {
|
||||
})
|
||||
|
||||
it('refreshes the latest plan after A0409 without losing the selected container', async () => {
|
||||
const warningMessage = vi.spyOn(ElMessage, 'warning').mockImplementation(() => undefined as never)
|
||||
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue({ ...plan, version: 3 })
|
||||
@@ -224,16 +239,12 @@ describe('GlobalSmartLoadingView', () => {
|
||||
|
||||
expect(recommendSmartLoading).toHaveBeenCalledWith(plan.id, 2)
|
||||
expect(getSmartLoadingPlanByBooking).toHaveBeenCalledTimes(2)
|
||||
expect(wrapper.text()).toContain('版本 3')
|
||||
expect(wrapper.text()).toContain('已刷新最新版本')
|
||||
expect(wrapper.text()).toContain('request-1')
|
||||
expect(warningMessage).toHaveBeenCalledWith('方案已被其他人修改,已刷新最新版本,请重新确认后提交')
|
||||
expect(wrapper.text()).not.toContain('装柜操作失败')
|
||||
expect(wrapper.text()).not.toContain('request-1')
|
||||
})
|
||||
|
||||
it('shows a picking-specific message when a picked order cannot be removed', async () => {
|
||||
const loadingContainer = { ...container, planStatus: 'LOADING' as const }
|
||||
const loadingPlan = { ...plan, status: 'LOADING' as const }
|
||||
vi.mocked(listContainers).mockResolvedValue({ records: [loadingContainer], page: 1, size: 100, total: 1, pages: 1 })
|
||||
vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue(loadingPlan)
|
||||
vi.mocked(removeSmartLoadingItem).mockRejectedValue(new AxiosError(
|
||||
'conflict',
|
||||
'ERR_BAD_REQUEST',
|
||||
@@ -253,15 +264,80 @@ describe('GlobalSmartLoadingView', () => {
|
||||
|
||||
expect(removeSmartLoadingItem).toHaveBeenCalled()
|
||||
expect(errorMessage).toHaveBeenCalledWith('该订单在拣货中不许删除')
|
||||
expect(wrapper.text()).toContain('该订单在拣货中不许删除')
|
||||
expect(wrapper.text()).not.toContain('装柜操作失败')
|
||||
expect(wrapper.text()).not.toContain('该订单在拣货中不许删除')
|
||||
})
|
||||
|
||||
it('removes every item with the latest returned plan version', async () => {
|
||||
const secondItem = { ...plan.items[0], id: '102', inboundDetailId: '4', inboundCode: 'IN-2' }
|
||||
const initialPlan = { ...plan, items: [plan.items[0], secondItem] }
|
||||
const afterFirst = { ...plan, version: 3, items: [secondItem] }
|
||||
const emptyPlan = { ...plan, version: 4, items: [] }
|
||||
vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValueOnce(initialPlan).mockResolvedValue(emptyPlan)
|
||||
vi.mocked(removeSmartLoadingItem).mockResolvedValueOnce(afterFirst).mockResolvedValueOnce(emptyPlan)
|
||||
vi.spyOn(ElMessageBox, 'confirm').mockResolvedValue('confirm' as never)
|
||||
|
||||
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
const removeAllButton = wrapper.findAll('button').find((button) => button.text().includes('全部移除'))
|
||||
expect(removeAllButton).toBeDefined()
|
||||
await removeAllButton!.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(removeSmartLoadingItem).toHaveBeenNthCalledWith(1, plan.id, plan.items[0].id, 2, 1)
|
||||
expect(removeSmartLoadingItem).toHaveBeenNthCalledWith(2, plan.id, secondItem.id, 3, 1)
|
||||
expect(wrapper.text()).toContain('当前柜次暂无已装货物')
|
||||
})
|
||||
|
||||
it('limits adjusted package count to the assigned count plus remaining availability', async () => {
|
||||
vi.mocked(listSmartLoadingCandidates).mockResolvedValue([{ accountId: '1', inboundId: '2', inboundDetailId: '3', orderId: '4', orderNo: 'ORD-1', inboundCode: 'IN-1', warehouseId: '8', channelCode: 'ZBYHK', channelName: '美森正班海卡包税', destinationWarehouseId: '9', destinationWarehouseCode: 'LAX9', destinationWarehouseName: 'LAX9', customerName: '示例企业', goodsName: '服装', availablePackageCount: 4, unitWeightKg: 10, unitVolumeCbm: 0.2 }])
|
||||
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
|
||||
const maxima = wrapper.findAllComponents(ElInputNumber).map((input) => input.props('max'))
|
||||
expect(maxima).toContain(10)
|
||||
})
|
||||
|
||||
it('uses bordered assignment and adjustment actions at narrow widths', () => {
|
||||
const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/GlobalSmartLoadingView.vue'), 'utf8')
|
||||
expect(source).toContain('size="small"')
|
||||
expect(source).toContain('type="danger" plain')
|
||||
expect(source).toContain(':max="adjustmentMax(row)"')
|
||||
expect(source).not.toContain('link type="danger"')
|
||||
expect(source).toContain('@media (max-width: 720px)')
|
||||
expect(source.match(/<DataTable[\s\S]*?\bstripe\b/g)).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('bounds all three workbench panes and keeps their content independently scrollable', () => {
|
||||
const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/GlobalSmartLoadingView.vue'), 'utf8')
|
||||
|
||||
expect(source).toContain('height: clamp(520px, 68vh, 720px); min-height: 0;')
|
||||
expect(source).toContain('.dispatch-pane { display: flex; min-width: 0; min-height: 0; flex-direction: column; }')
|
||||
expect(source).toContain('.candidate-pane :deep(.data-table),.plan-pane :deep(.data-table) { min-height: 0; flex: 1; }')
|
||||
expect(source).toContain('.container-list { display: grid; min-height: 0; flex: 1;')
|
||||
expect(source).toContain('grid-auto-rows: max-content;')
|
||||
expect(source).toContain('overflow-wrap: anywhere;')
|
||||
expect(source).toContain('.candidate-pane,.plan-pane { height: min(68vh, 560px); min-height: 420px; }')
|
||||
expect(source).toContain('.container-pane { max-height: min(58vh, 460px); }')
|
||||
})
|
||||
|
||||
it('uses overflow-aware channel tabs with a compact right-aligned summary', () => {
|
||||
const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/GlobalSmartLoadingView.vue'), 'utf8')
|
||||
|
||||
expect(source).toContain('<el-tabs :model-value="activeChannelCode"')
|
||||
expect(source).toContain('<el-tab-pane v-for="channel in channelTabs"')
|
||||
expect(source).toContain(':label="channel.name"')
|
||||
expect(source).not.toContain('channel.containerCount')
|
||||
expect(source).toContain('class="compact-summary" aria-label="当前渠道装柜统计"')
|
||||
expect(source).toContain('<dt>候选货物</dt>')
|
||||
expect(source).toContain('<dt>空柜</dt>')
|
||||
expect(source).toContain('<dt>已装</dt>')
|
||||
expect(source).toContain('<dt>总重量</dt>')
|
||||
expect(source).toContain('<dt>总体积</dt>')
|
||||
expect(source).toContain('.channel-tabs :deep(.el-tabs__content) { display: none; }')
|
||||
expect(source).not.toContain('class="summary-band"')
|
||||
expect(source).toContain('class="capacity-grid"')
|
||||
expect(source).toContain('智能推荐')
|
||||
expect(source).toContain('推送预装')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user