- 派送单号
- {{ show(detail.order.deliveryNo) }}
- 状态
- {{ statusLabels[detail.order.status] || detail.order.status }}
- - 仓库
- {{ show(detail.order.overseasWarehouseName) }}
- 运单号
- {{ show(detail.order.waybillNo) }}
- - 派送人
- {{ show(detail.order.carrierName) }}
- 派送时间
- {{ formatOverseasDateTime(detail.order.dispatchedAt || detail.order.plannedDeliveryAt) }}
- - 提货方式
- {{ pickupLabels[detail.order.pickupMethod || ''] || show(detail.order.pickupMethod) }}
- 装车类型
- {{ loadingLabels[detail.order.loadingType || ''] || show(detail.order.loadingType) }}
- - 派送方式
- {{ methodLabels[detail.order.deliveryMethod || ''] || show(detail.order.deliveryMethod) }}
- 司机/车队
- {{ show(detail.order.driverName) }}
+ - 仓库
- {{ show(detail.order.overseasWarehouseName) }}
- 目的 FBA 仓
- {{ show(detail.order.destinationWarehouseCode || detail.order.destinationWarehouseName) }}
+ - 运单号
- {{ show(detail.order.waybillNo) }}
- 派送人
- {{ show(detail.order.carrierName) }}
+ - 派送时间
- {{ formatOverseasDateTime(detail.order.dispatchedAt || detail.order.plannedDeliveryAt) }}
- 提货方式
- {{ pickupLabels[detail.order.pickupMethod || ''] || show(detail.order.pickupMethod) }}
+ - 装车类型
- {{ loadingLabels[detail.order.loadingType || ''] || show(detail.order.loadingType) }}
- 派送方式
- {{ methodLabels[detail.order.deliveryMethod || ''] || show(detail.order.deliveryMethod) }}
+ - 司机/车队
- {{ show(detail.order.driverName) }}
- 车牌号
- {{ show(detail.order.vehiclePlate) }}
- 总箱数
- {{ quantity(detail.order.packageCount, '箱') }}
- 总重量
- {{ quantity(detail.order.totalWeightKg, 'kg') }}
- 总体积
- {{ quantity(detail.order.totalVolumeCbm, 'm³') }}
- 预计到达时间
- {{ formatOverseasDateTime(detail.order.expectedArrivalAt) }}
- 客户确认
- {{ customerConfirmation() }}
diff --git a/src/modules/overseas-warehouse/pages/DeliveryOrdersView.test.ts b/src/modules/overseas-warehouse/pages/DeliveryOrdersView.test.ts
index d71e4e3e..df6205b1 100644
--- a/src/modules/overseas-warehouse/pages/DeliveryOrdersView.test.ts
+++ b/src/modules/overseas-warehouse/pages/DeliveryOrdersView.test.ts
@@ -1,6 +1,6 @@
import ElementPlus from 'element-plus'
import { defineComponent, h, type PropType } from 'vue'
-import { DOMWrapper, flushPromises, mount } from '@vue/test-utils'
+import { flushPromises, mount } from '@vue/test-utils'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { getDeliveryOrder, listDeliveryOrders, listDeliveryReturnInboundOptions, markDeliveryReturn } from '../api/deliveryOrders'
import { updateDeliveryOrderStatus } from '../api/customerVisits'
@@ -54,10 +54,10 @@ describe('DeliveryOrdersView permissions and commands', () => {
await wrapper.findAll('button').find(button => button.text().includes('编辑状态'))!.trigger('click')
await flushPromises()
- await wrapper.find('[data-dialog="编辑派送状态"] select').setValue('DELIVERED')
+ await wrapper.find('[data-dialog="编辑派送状态"] select').setValue('DELIVERING')
await wrapper.find('[data-dialog="编辑派送状态"] .dialog-confirm').trigger('click')
await flushPromises()
- expect(updateDeliveryOrderStatus).toHaveBeenCalledWith('DEL/1', '100', { status: 'DELIVERED', expectedVersion: 7, remark: undefined })
+ expect(updateDeliveryOrderStatus).toHaveBeenCalledWith('DEL/1', '100', { status: 'DELIVERING', expectedVersion: 7, remark: undefined })
await wrapper.findAll('button').find(button => button.text().includes('标记退货'))!.trigger('click')
await flushPromises()
@@ -86,7 +86,7 @@ describe('DeliveryOrdersView permissions and commands', () => {
wrapper.unmount()
})
- it('maps delivering separately from completion and blocks duplicate or conflicted submission', async () => {
+ it('excludes manual completion and blocks duplicate or conflicted status submission', async () => {
canPermission.mockReturnValue(true)
const wrapper = mountView()
await flushPromises()
@@ -94,7 +94,7 @@ describe('DeliveryOrdersView permissions and commands', () => {
await flushPromises()
const select = wrapper.find('[data-dialog="编辑派送状态"] select')
expect(select.find('option[value="DELIVERING"]').text()).toBe('派送中')
- expect(select.find('option[value="DELIVERED"]').text()).toBe('派送完成')
+ expect(select.find('option[value="DELIVERED"]').exists()).toBe(false)
expect(select.find('option[value="WAIT_DELIVERY"]').exists()).toBe(false)
await select.setValue('DELIVERING')
await wrapper.find('[data-dialog="编辑派送状态"] textarea').setValue('123')
@@ -114,7 +114,7 @@ describe('DeliveryOrdersView permissions and commands', () => {
expect(updateDeliveryOrderStatus).toHaveBeenCalledTimes(1)
vi.mocked(getDeliveryOrder).mockResolvedValue({ order: { ...row, version: 8, allowedActions: ['COMPLETE_DELIVERY'] }, skus: [], fees: [], operations: [] })
await state.refreshStatus(); await flushPromises()
- expect(select.findAll('option').map(option => option.attributes('value'))).toEqual(['DELIVERED'])
+ expect(select.findAll('option')).toHaveLength(0)
wrapper.unmount()
})
@@ -192,37 +192,27 @@ describe('DeliveryOrdersView permissions and commands', () => {
wrapper.unmount()
})
- it('selects completion through the real dialog and select, then retries a conflict with the refreshed version', async () => {
+ it('hides status editing when completion is the only server action', async () => {
canPermission.mockImplementation(code => code.endsWith(':status'))
vi.mocked(getDeliveryOrder).mockResolvedValue({ order: { ...row, version: 7, status: 'DELIVERING', allowedActions: ['COMPLETE_DELIVERY'] }, skus: [], fees: [], operations: [] })
- vi.mocked(updateDeliveryOrderStatus).mockRejectedValueOnce({ isAxiosError: true, response: { status: 409, data: { code: 'A0409', message: '版本冲突' } } })
- const wrapper = mount(DeliveryOrdersView, { attachTo: document.body, global: { plugins: [ElementPlus], stubs: { ...commonPhase5Stubs, AppDialog: false, ElInput: false, ElSelect: false, ElOption: false } } })
- const body = new DOMWrapper(document.body)
- try {
- await flushPromises()
- await wrapper.findAll('button').find(button => button.text().includes('编辑状态'))!.trigger('click')
- await flushPromises()
- const dialog = body.find('[role="dialog"][aria-label="编辑派送状态"]')
- const save = () => dialog.findAll('button').find(button => button.text() === '保存状态')!
- expect(save().attributes('disabled')).toBeDefined()
- await dialog.find('.el-select__wrapper').trigger('click')
- await flushPromises()
- const options = body.findAll('.el-select-dropdown__item')
- expect(options.map(option => option.text())).toEqual(['派送完成'])
- await options[0]!.trigger('click')
- await dialog.find('textarea').setValue('已交付')
- await save().trigger('click'); await flushPromises()
- expect(updateDeliveryOrderStatus).toHaveBeenLastCalledWith('DEL/1', '100', { status: 'DELIVERED', expectedVersion: 7, remark: '已交付' })
- expect(save().attributes('disabled')).toBeDefined()
- expect(dialog.text()).toContain('请刷新最新状态并重新确认')
- vi.mocked(getDeliveryOrder).mockResolvedValue({ order: { ...row, version: 8, status: 'DELIVERING', allowedActions: ['COMPLETE_DELIVERY'] }, skus: [], fees: [], operations: [] })
- await dialog.findAll('button').find(button => button.text().includes('重新加载'))!.trigger('click')
- await flushPromises()
- expect((dialog.find('textarea').element as HTMLTextAreaElement).value).toBe('已交付')
- await save().trigger('click'); await flushPromises()
- expect(updateDeliveryOrderStatus).toHaveBeenLastCalledWith('DEL/1', '100', { status: 'DELIVERED', expectedVersion: 8, remark: '已交付' })
- expect(listDeliveryOrders).toHaveBeenCalledTimes(2)
- } finally { wrapper.unmount() }
+ vi.mocked(listDeliveryOrders).mockResolvedValue({ records: [{ ...row, status: 'DELIVERING', allowedActions: ['COMPLETE_DELIVERY'] }], page: 1, size: 10, total: 1, pages: 1 })
+ const wrapper = mountView(); await flushPromises()
+ expect(wrapper.find('[data-testid="data-table"]').text()).not.toContain('编辑状态')
+ expect(getDeliveryOrder).not.toHaveBeenCalled()
+ expect(updateDeliveryOrderStatus).not.toHaveBeenCalled()
+ wrapper.unmount()
+ })
+
+ it('shows the destination FBA warehouse that identifies each split delivery', async () => {
+ vi.mocked(listDeliveryOrders).mockResolvedValue({ records: [{ ...row, destinationWarehouseCode: 'ACY2', destinationWarehouseName: 'Amazon ACY2' }], page: 1, size: 10, total: 1, pages: 1 })
+ const table = defineComponent({
+ props: { data: Array as PropType