Merge remote-tracking branch 'origin/release/test' into dev
This commit is contained in:
@@ -95,7 +95,6 @@ function containerPage(records: ContainerBookingResource[] = [container]) {
|
|||||||
function mockContainerSearch(records: ContainerBookingResource[]) {
|
function mockContainerSearch(records: ContainerBookingResource[]) {
|
||||||
vi.mocked(listSmartLoadingWorkbenchContainers).mockImplementation(async (query) => containerPage(records.filter((item) => (
|
vi.mocked(listSmartLoadingWorkbenchContainers).mockImplementation(async (query) => containerPage(records.filter((item) => (
|
||||||
item.planStatus !== 'COMPLETED'
|
item.planStatus !== 'COMPLETED'
|
||||||
&& (!query.warehouseId || item.warehouseId === query.warehouseId)
|
|
||||||
&& query.channelGroupCodes.includes(resolveSmartLoadingChannelGroup(item.channelCode, item.channelName)?.code || '')
|
&& query.channelGroupCodes.includes(resolveSmartLoadingChannelGroup(item.channelCode, item.channelName)?.code || '')
|
||||||
))))
|
))))
|
||||||
}
|
}
|
||||||
@@ -259,7 +258,7 @@ describe('GlobalSmartLoadingView', () => {
|
|||||||
expect(wrapper.text()).not.toContain('美森正班海派')
|
expect(wrapper.text()).not.toContain('美森正班海派')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('moves the shipping warehouse into the query filters', async () => {
|
it('keeps the shipping warehouse as a candidate-only query filter', async () => {
|
||||||
const dongguanContainer = {
|
const dongguanContainer = {
|
||||||
...container,
|
...container,
|
||||||
id: '9007199254740998',
|
id: '9007199254740998',
|
||||||
@@ -277,16 +276,18 @@ describe('GlobalSmartLoadingView', () => {
|
|||||||
|
|
||||||
expect(wrapper.text()).toContain('MSCU-1')
|
expect(wrapper.text()).toContain('MSCU-1')
|
||||||
expect(wrapper.text()).toContain('MSCU-DG')
|
expect(wrapper.text()).toContain('MSCU-DG')
|
||||||
|
const containerRequestCount = vi.mocked(listSmartLoadingWorkbenchContainers).mock.calls.length
|
||||||
|
|
||||||
wrapper.findComponent(QueryToolbar).vm.$emit('search', { warehouseId: '18', customerId: '', inboundCode: '', expectedArrivalRange: [], orderStatus: '' })
|
wrapper.findComponent(QueryToolbar).vm.$emit('search', { warehouseId: '18', customerId: '', inboundCode: '', expectedArrivalRange: [], orderStatus: '' })
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
expect(wrapper.text()).toContain('MSCU-DG')
|
expect(wrapper.text()).toContain('MSCU-DG')
|
||||||
expect(wrapper.text()).not.toContain('MSCU-1')
|
expect(wrapper.text()).toContain('MSCU-1')
|
||||||
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], warehouseId: dongguanContainer.warehouseId, page: 1, size: 20 })
|
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], warehouseId: dongguanContainer.warehouseId, page: 1, size: 20 })
|
||||||
|
expect(listSmartLoadingWorkbenchContainers).toHaveBeenCalledTimes(containerRequestCount)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('keeps the selected channel when the warehouse changes even if that warehouse has no matching container', async () => {
|
it('keeps channel cabinets unchanged when another search field has no matching cabinet', async () => {
|
||||||
const dongguanOvertimeContainer = {
|
const dongguanOvertimeContainer = {
|
||||||
...container,
|
...container,
|
||||||
id: '9007199254740998',
|
id: '9007199254740998',
|
||||||
@@ -302,15 +303,49 @@ describe('GlobalSmartLoadingView', () => {
|
|||||||
mockContainerSearch([container, dongguanOvertimeContainer])
|
mockContainerSearch([container, dongguanOvertimeContainer])
|
||||||
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
const containerRequestCount = vi.mocked(listSmartLoadingWorkbenchContainers).mock.calls.length
|
||||||
|
|
||||||
wrapper.findComponent(QueryToolbar).vm.$emit('search', { warehouseId: '18', customerId: '', inboundCode: '', expectedArrivalRange: [], orderStatus: '' })
|
wrapper.findComponent(QueryToolbar).vm.$emit('search', { warehouseId: '18', customerId: '', inboundCode: '', expectedArrivalRange: [], orderStatus: '' })
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
expect(wrapper.find('.channel-tags .el-checkbox-button.is-checked').text()).toBe('美森正班')
|
expect(wrapper.find('.channel-tags .el-checkbox-button.is-checked').text()).toBe('美森正班')
|
||||||
expect(wrapper.findAll('.container-option')).toHaveLength(0)
|
expect(wrapper.findAll('.container-option')).toHaveLength(1)
|
||||||
|
expect(wrapper.text()).toContain('MSCU-1')
|
||||||
expect(wrapper.text()).not.toContain('MSCU-DG-MAX')
|
expect(wrapper.text()).not.toContain('MSCU-DG-MAX')
|
||||||
expect(listSmartLoadingCandidates).toHaveBeenCalledTimes(2)
|
expect(listSmartLoadingCandidates).toHaveBeenCalledTimes(2)
|
||||||
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], warehouseId: '18', page: 1, size: 20 })
|
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], warehouseId: '18', page: 1, size: 20 })
|
||||||
|
expect(listSmartLoadingWorkbenchContainers).toHaveBeenCalledTimes(containerRequestCount)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('filters candidate details by inbound code without filtering channel cabinets', async () => {
|
||||||
|
const secondContainer = {
|
||||||
|
...container,
|
||||||
|
id: '9007199254740998',
|
||||||
|
planId: '9007199254740999',
|
||||||
|
cabinetNo: 'CB-2',
|
||||||
|
containerNo: 'MSCU-2',
|
||||||
|
}
|
||||||
|
vi.mocked(listContainers).mockResolvedValue({ records: [container, secondContainer], page: 1, size: 100, total: 2, pages: 1 })
|
||||||
|
mockContainerSearch([container, secondContainer])
|
||||||
|
vi.mocked(getSmartLoadingPlanByBooking).mockImplementation(async (bookingId) => ({ ...plan, bookingId }))
|
||||||
|
vi.mocked(listSmartLoadingCandidates)
|
||||||
|
.mockResolvedValueOnce(candidatePage([candidate]))
|
||||||
|
.mockResolvedValueOnce(candidatePage([{ ...candidate, inboundCode: 'NYEXX2609030002' }]))
|
||||||
|
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||||
|
await flushPromises()
|
||||||
|
const containerRequestCount = vi.mocked(listSmartLoadingWorkbenchContainers).mock.calls.length
|
||||||
|
|
||||||
|
wrapper.findComponent(QueryToolbar).vm.$emit('search', {
|
||||||
|
warehouseId: '', customerId: '', inboundCode: 'NYEXX2609030002', expectedArrivalRange: [], orderStatus: '',
|
||||||
|
})
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(wrapper.get('.candidate-pane').text()).toContain('NYEXX2609030002')
|
||||||
|
expect(wrapper.findAll('.container-option')).toHaveLength(2)
|
||||||
|
expect(wrapper.text()).toContain('MSCU-1')
|
||||||
|
expect(wrapper.text()).toContain('MSCU-2')
|
||||||
|
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], inboundCode: 'NYEXX2609030002', page: 1, size: 20 })
|
||||||
|
expect(listSmartLoadingWorkbenchContainers).toHaveBeenCalledTimes(containerRequestCount)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sends the active name-only customer selector to the server candidate query', () => {
|
it('sends the active name-only customer selector to the server candidate query', () => {
|
||||||
@@ -336,6 +371,7 @@ describe('GlobalSmartLoadingView', () => {
|
|||||||
.mockResolvedValueOnce(candidatePage([{ ...candidate, inboundId: '51', inboundCode: 'IN-MATCH', orderStatusSnapshot: 'WAIT_SPLIT', expectedArrivalAt: '2026-09-11T08:00:00' }]))
|
.mockResolvedValueOnce(candidatePage([{ ...candidate, inboundId: '51', inboundCode: 'IN-MATCH', orderStatusSnapshot: 'WAIT_SPLIT', expectedArrivalAt: '2026-09-11T08:00:00' }]))
|
||||||
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
const containerRequestCount = vi.mocked(listSmartLoadingWorkbenchContainers).mock.calls.length
|
||||||
|
|
||||||
wrapper.getComponent(QueryToolbar).vm.$emit('search', {
|
wrapper.getComponent(QueryToolbar).vm.$emit('search', {
|
||||||
customerId: '', inboundCode: '', orderStatus: 'WAIT_SPLIT', expectedArrivalRange: ['2026-09-10', '2026-09-12'],
|
customerId: '', inboundCode: '', orderStatus: 'WAIT_SPLIT', expectedArrivalRange: ['2026-09-10', '2026-09-12'],
|
||||||
@@ -347,7 +383,8 @@ describe('GlobalSmartLoadingView', () => {
|
|||||||
expect(candidates).not.toContain('IN-WRONG-STATUS')
|
expect(candidates).not.toContain('IN-WRONG-STATUS')
|
||||||
expect(candidates).not.toContain('IN-WRONG-DATE')
|
expect(candidates).not.toContain('IN-WRONG-DATE')
|
||||||
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], expectedArrivalStart: '2026-09-10', expectedArrivalEnd: '2026-09-12', orderStatus: 'WAIT_SPLIT', page: 1, size: 20 })
|
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], expectedArrivalStart: '2026-09-10', expectedArrivalEnd: '2026-09-12', orderStatus: 'WAIT_SPLIT', page: 1, size: 20 })
|
||||||
expect(listSmartLoadingWorkbenchContainers).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], expectedArrivalStart: '2026-09-10', expectedArrivalEnd: '2026-09-12', orderStatus: 'WAIT_SPLIT', page: 1, size: 200 })
|
expect(listSmartLoadingWorkbenchContainers).toHaveBeenCalledTimes(containerRequestCount)
|
||||||
|
expect(listSmartLoadingWorkbenchContainers).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], page: 1, size: 200 })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('paginates large inbound candidate results with twenty rows by default', async () => {
|
it('paginates large inbound candidate results with twenty rows by default', async () => {
|
||||||
|
|||||||
@@ -219,19 +219,19 @@ const candidateColumns: DataTableColumn[] = [
|
|||||||
{ key: 'customerName', prop: 'customerName', label: '客户', minWidth: 70 },
|
{ key: 'customerName', prop: 'customerName', label: '客户', minWidth: 70 },
|
||||||
{ key: 'availablePackageCount', prop: 'availablePackageCount', label: '可用箱数', width: 80 },
|
{ 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: 100, slotName: 'unitGrossWeight' },
|
{ key: 'unitGrossWeightKg', label: '单箱毛重', width: 80, slotName: 'unitGrossWeight' },
|
||||||
{ key: 'totalGrossWeightKg', label: '总重量', width: 90, slotName: 'candidateTotalWeight' },
|
{ key: 'totalGrossWeightKg', label: '重量', width: 90, slotName: 'candidateTotalWeight' },
|
||||||
{ key: 'averageUnitVolumeCbm', label: '平均单箱体积', width: 100, slotName: 'averageUnitVolume' },
|
{ key: 'averageUnitVolumeCbm', label: '单箱体积', width: 80, slotName: 'averageUnitVolume' },
|
||||||
{ key: 'totalVolumeCbm', label: '总体积', width: 90, slotName: 'candidateTotalVolume' },
|
{ key: 'totalVolumeCbm', label: '体积', width: 90, slotName: 'candidateTotalVolume' },
|
||||||
]
|
]
|
||||||
const itemColumns: DataTableColumn[] = [
|
const itemColumns: DataTableColumn[] = [
|
||||||
{ key: 'actions', label: '操作', width: 90, fixed: 'left', slotName: 'actions' },
|
{ key: 'actions', label: '操作', width: 80, 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: 'packageCount', label: '分配箱数', width: 140, slotName: 'packageCount' },
|
{ key: 'packageCount', label: '分配箱数', width: 100, slotName: 'packageCount' },
|
||||||
{ key: 'grossWeightKg', label: '毛重', width: 110, slotName: 'weight' },
|
{ key: 'grossWeightKg', label: '毛重', width: 80, slotName: 'weight' },
|
||||||
{ key: 'volumeCbm', label: '体积', width: 105, slotName: 'volume' },
|
{ key: 'volumeCbm', label: '体积', width: 80, slotName: 'volume' },
|
||||||
]
|
]
|
||||||
|
|
||||||
function formatNumber(value: number, digits = 3) {
|
function formatNumber(value: number, digits = 3) {
|
||||||
@@ -306,6 +306,14 @@ function candidateQueryParams(): Parameters<typeof listSmartLoadingCandidates>[0
|
|||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function containerQueryParams(page = 1): Parameters<typeof listSmartLoadingWorkbenchContainers>[0] {
|
||||||
|
return {
|
||||||
|
channelGroupCodes: [...selectedChannelCodes.value],
|
||||||
|
page,
|
||||||
|
size: 200,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loadCandidateData() {
|
async function loadCandidateData() {
|
||||||
if (!selectedChannelCodes.value.length) return
|
if (!selectedChannelCodes.value.length) return
|
||||||
const request = ++candidateRequest
|
const request = ++candidateRequest
|
||||||
@@ -357,9 +365,9 @@ async function loadContainerData(preserved: Record<string, number> = {}) {
|
|||||||
if (!selectedChannelCodes.value.length) return
|
if (!selectedChannelCodes.value.length) return
|
||||||
const request = ++containerRequest
|
const request = ++containerRequest
|
||||||
try {
|
try {
|
||||||
const firstPage = await listSmartLoadingWorkbenchContainers({ ...candidateQueryParams(), page: 1, size: 200 })
|
const firstPage = await listSmartLoadingWorkbenchContainers(containerQueryParams())
|
||||||
const remainingPages = firstPage.pages > 1
|
const remainingPages = firstPage.pages > 1
|
||||||
? await Promise.all(Array.from({ length: firstPage.pages - 1 }, (_, index) => listSmartLoadingWorkbenchContainers({ ...candidateQueryParams(), page: index + 2, size: 200 })))
|
? await Promise.all(Array.from({ length: firstPage.pages - 1 }, (_, index) => listSmartLoadingWorkbenchContainers(containerQueryParams(index + 2))))
|
||||||
: []
|
: []
|
||||||
if (request !== containerRequest) return
|
if (request !== containerRequest) return
|
||||||
containers.value = [firstPage, ...remainingPages].flatMap((page) => page.records)
|
containers.value = [firstPage, ...remainingPages].flatMap((page) => page.records)
|
||||||
@@ -431,7 +439,7 @@ async function selectChannels(codes: string[]) {
|
|||||||
async function applyFilters(model: QueryModel) {
|
async function applyFilters(model: QueryModel) {
|
||||||
appliedQuery.value = { ...model }
|
appliedQuery.value = { ...model }
|
||||||
candidatePage.value = 1
|
candidatePage.value = 1
|
||||||
await loadWorkbenchData()
|
await loadCandidateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeCandidatePage(page: number) {
|
async function changeCandidatePage(page: number) {
|
||||||
|
|||||||
Reference in New Issue
Block a user