@@ -2,7 +2,7 @@ import { flushPromises, shallowMount } from '@vue/test-utils'
import { beforeEach , describe , expect , it , vi } from 'vitest'
import { ElMessageBox } from 'element-plus'
import { ApiResponseError } from '@/shared/api/http'
import { listPlatformUnifiedOrders } from '@/modules/unified-orders/api/unifiedOrders'
import { listPlatformUnifiedOrders , type UnifiedOrderResource } from '@/modules/unified-orders/api/unifiedOrders'
import { cancelPlatformCoLoadGroup , createPlatformCoLoadGroup , getPlatformCoLoadGroupByInboundCode } from '@/modules/unified-orders/api/coLoadGroups'
import UnifiedOrdersView from './UnifiedOrdersView.vue'
@@ -21,7 +21,7 @@ vi.mock('@/modules/unified-orders/api/coLoadGroups', () => ({
cancelPlatformCoLoadGroup : vi.fn ( ) , createPlatformCoLoadGroup : vi.fn ( ) , getPlatformCoLoadGroupByInboundCode : vi.fn ( ) ,
} ) )
const rows = [ '5001' , '5002' ] . map ( ( orderId , index ) = > ( {
const rows : UnifiedOrderResource [ ] = [ '5001' , '5002' ] . map ( ( orderId , index ) = > ( {
orderId , tenantId : ` 600 ${ index } ` , orderNo : ` ORD- ${ index + 1 } ` , mainStatus : 'WAIT_SPLIT' as const , nextAction : null ,
relation : null , internalOrderStatus : 'WAIT_SPLIT' , customerId : ` 600 ${ index } ` , customerName : ` 客户 ${ index + 1 } ` ,
channelCode : 'NY_EXX' , channelName : '纽约渠道' , receivingWarehouseId : '8' , receivingWarehouseName : '义乌仓' , destinationWarehouseId : '9' , destinationWarehouseName : 'ONT8' ,
@@ -38,7 +38,7 @@ function mountView() {
AdminPage : { template : '<main><slot /></main>' } ,
ListPageLayout : { template : '<section><slot name="toolbar" /><slot name="state" /><slot /></section>' } ,
QueryToolbar : { template : '<div />' } ,
DataTable : { name : 'DataTable' , props : [ 'data' ] , emits : [ 'selection-change' ] , template : '<section><slot name="toolbar-actions" /><button data-testid="select" @click="$emit(\'selection-change\', data)">勾选两票</button><template v-for="row in data" :key="row.orderId"><slot name="actions" :row="row" /><slot name="inboundCode" :row="row" /></template></section>' } ,
DataTable : { name : 'DataTable' , props : [ 'data' , 'columns' ] , emits : [ 'selection-change' ] , template : '<section><slot name="toolbar-actions" /><button data-testid="select" @click="$emit(\'selection-change\', data)">勾选两票</button><template v-for="row in data" :key="row.orderId"><slot name="actions" :row="row" /><slot name="inboundCode" :row="row" /></template></section>' } ,
AppDialog : { name : 'AppDialog' , props : [ 'modelValue' , 'confirmText' , 'confirmDisabled' , 'confirmLoading' ] , emits : [ 'confirm' , 'update:modelValue' ] , methods : { close() { this . $emit ( 'update:modelValue' , false ) } } , template : '<section v-if="modelValue"><slot /><slot name="footer" :close="close" :submitting="confirmLoading"><button data-testid="dialog-confirm" :disabled="confirmDisabled" @click="$emit(\'confirm\')">{{ confirmText }}</button></slot></section>' } ,
ApiErrorMeta : { props : [ 'details' ] , template : '<div>{{ details.code }} {{ details.requestId }} {{ details.traceId }}</div>' } ,
CopyButton : { props : [ 'value' , 'label' ] , template : '<button :data-copy="value">复制 ID</button>' } ,
@@ -76,28 +76,42 @@ describe('UnifiedOrdersView co-load group behavior', () => {
it . each ( [
[ '平台收货仓不同' , [ { . . . rows [ 0 ] , receivingWarehouseId : '8' , receivingWarehouseName : '义乌仓' } , { . . . rows [ 1 ] , receivingWarehouseId : '9' , receivingWarehouseName : '东莞仓' } ] , '所选订单的平台收货仓不同:IN-1(仓库:义乌仓;渠道:纽约渠道)、IN-2(仓库:东莞仓;渠道:纽约渠道),不能设为同柜组' ] ,
[ '渠道不同' , [ { . . . rows [ 0 ] , channelCode : 'NY_EXX' , channelName : '纽约渠道' } , { . . . rows [ 1 ] , channelCode : 'LA_SEA' , channelName : '洛杉矶渠道' } ] , '所选订单的渠道不同:IN-1(仓库:义乌仓;渠道:纽约渠道)、IN-2(仓库:义乌仓;渠道:洛杉矶渠道),不能设为同柜组' ] ,
[ '已有同柜组' , [ rows [ 0 ] , { . . . rows [ 1 ] , coLoadGroup : { status : 'ACTIVE' , memberCount : 2 , memberInboundCodes : [ 'IN-2' , 'IN-3' ] } } ] , '所选订单中已有同柜组 ,请先解除原同柜组' ] ,
] ) ( 'blocks create immedi ately when %s' , async ( _case , selectedRows , reason ) = > {
[ '已有同柜组' , [ rows [ 0 ] , { . . . rows [ 1 ] , coLoadGroup : { status : 'ACTIVE' , memberCount : 2 , memberInboundCodes : [ 'IN-2' , 'IN-3' ] } } ] , '以下入仓码已有同柜组:IN-2(仓库:义乌仓;渠道:纽约渠道) ,请先解除原同柜组' ] ,
] ) ( 'blocks a bypassed invalid cre ate when %s without rendering qualification errors ' , async ( _case , selectedRows , reason ) = > {
vi . mocked ( listPlatformUnifiedOrders ) . mockResolvedValue ( { records : selectedRows , page : 1 , size : 20 , total : 2 , pages : 1 } )
const wrapper = mountView ( )
await flushPromises ( )
await wrapper . get ( '[data-testid="select"]' ) . trigger ( 'click' )
const createButton = wrapper . findAll ( 'button' ) . find ( ( button ) = > button . text ( ) . includes ( '设为同柜不可拆组' ) ) !
expect ( createButton . attributes ( 'disabled' ) ) . toBeDefined ( )
expect ( wrapper . text ( ) ) . toContain ( reason )
expect ( wrapper . text ( ) ) . not . toContain ( reason )
await createButton . trigger ( 'click' )
expect ( createPlatformCoLoadGroup ) . not . toHaveBeenCalled ( )
} )
it ( 'keeps zero-selection and one-selection silent while the create button stays disabled' , async ( ) = > {
const wrapper = mountView ( )
await flushPromises ( )
expect ( wrapper . text ( ) ) . not . toContain ( '请至少勾选 2 票订单后再设为同柜组' )
expect ( wrapper . findAll ( 'button' ) . find ( ( button ) = > button . text ( ) . includes ( '设为同柜不可拆组' ) ) ! . attributes ( 'disabled' ) ) . toBeDefined ( )
; ( wrapper . vm as unknown as { handleOrderSelectionChange : ( selected : typeof rows ) = > void } ) . handleOrderSelectionChange ( [ rows [ 0 ] ] )
await wrapper . vm . $nextTick ( )
expect ( wrapper . text ( ) ) . not . toContain ( '当前仅选择 1 票' )
expect ( wrapper . findAll ( 'button' ) . find ( ( button ) = > button . text ( ) . includes ( '设为同柜不可拆组' ) ) ! . attributes ( 'disabled' ) ) . toBeDefined ( )
expect ( wrapper . text ( ) ) . not . toContain ( '5001' )
expect ( wrapper . text ( ) ) . not . toContain ( '7000' )
} )
it . each ( [
[ '平台收货仓' , [ { . . . rows [ 0 ] , receivingWarehouseId : null , receivingWarehouseName : null } , rows [ 1 ] ] , '以下入仓码缺少平台收货仓:IN-1(仓库:未配置仓库;渠道:纽约渠道),请刷新后重试' ] ,
[ '渠道' , [ { . . . rows [ 0 ] , channelCode : null , channelName : null } , rows [ 1 ] ] , '以下入仓码缺少渠道:IN-1(仓库:义乌仓;渠道:未配置渠道),请刷新后重试' ] ,
] ) ( 'lists the affected inbound code and display names when %s is missing' , async ( _case , selectedRows , reason ) = > {
] ) ( 'keeps a bypassed missing-field selection disabled and silent when %s is missing' , async ( _case , selectedRows , reason ) = > {
vi . mocked ( listPlatformUnifiedOrders ) . mockResolvedValue ( { records : selectedRows , page : 1 , size : 20 , total : 2 , pages : 1 } )
const wrapper = mountView ( )
await flushPromises ( )
await wrapper . get ( '[data-testid="select"]' ) . trigger ( 'click' )
expect ( wrapper . text ( ) ) . toContain ( reason )
expect ( wrapper . text ( ) ) . not . toContain ( reason )
expect ( createPlatformCoLoadGroup ) . not . toHaveBeenCalled ( )
} )
@@ -118,10 +132,37 @@ describe('UnifiedOrdersView co-load group behavior', () => {
const wrapper = mountView ( )
await flushPromises ( )
await wrapper . get ( '[data-testid="select"]' ) . trigger ( 'click' )
expect ( wrapper . text ( ) ) . toContain ( '所选订单的渠道不同:IN-1(仓库:义乌仓;渠道:纽约渠道)、IN-2(仓库:义乌仓;渠道:纽约渠道),不能设为同柜组' )
expect ( wrapper . findAll ( 'button' ) . find ( ( button ) = > button . text ( ) . includes ( '设为同柜不可拆组' ) ) ! . attributes ( 'disabled' ) ) . toBeDefined ( )
expect ( wrapper . text ( ) ) . not . toContain ( '所选订单的渠道不同' )
expect ( createPlatformCoLoadGroup ) . not . toHaveBeenCalled ( )
} )
it ( 'keeps every row selectable for shared batch actions while only disabling invalid co-load creation' , async ( ) = > {
const selectedRows : UnifiedOrderResource [ ] = [
{ . . . rows [ 0 ] , mainStatus : 'PENDING_REVIEW' , nextAction : 'APPROVE_ORDER' , receivingWarehouseId : '8' } ,
{ . . . rows [ 1 ] , mainStatus : 'PENDING_REVIEW' , nextAction : 'APPROVE_ORDER' , receivingWarehouseId : '9' } ,
{ . . . rows [ 1 ] , orderId : '5003' , inboundCode : 'IN-3' , mainStatus : 'PENDING_REVIEW' , nextAction : 'APPROVE_ORDER' , receivingWarehouseId : '10' , channelCode : 'LA_SEA' } ,
]
vi . mocked ( listPlatformUnifiedOrders ) . mockResolvedValue ( { records : selectedRows , page : 1 , size : 20 , total : 3 , pages : 1 } )
const wrapper = mountView ( )
await flushPromises ( )
const table = wrapper . findComponent ( { name : 'DataTable' } )
const selectable = ( table . props ( 'columns' ) as Array < { key : string ; selectable ? : ( row : UnifiedOrderResource ) = > boolean } > ) . find ( ( column ) = > column . key === 'selection' ) ! . selectable !
const missingChannel = { . . . rows [ 1 ] , channelCode : null , channelName : null }
const grouped = { . . . rows [ 1 ] , coLoadGroup : { status : 'ACTIVE' , memberCount : 2 , memberInboundCodes : [ 'IN-2' , 'IN-3' ] } }
expect ( selectedRows . every ( ( row ) = > selectable ( row ) ) ) . toBe ( true )
expect ( selectable ( missingChannel ) ) . toBe ( true )
expect ( selectable ( grouped ) ) . toBe ( true )
await table . vm . $emit ( 'selection-change' , selectedRows )
await flushPromises ( )
expect ( wrapper . findAll ( 'button' ) . find ( ( button ) = > button . text ( ) . includes ( '批量审核通过' ) ) ! . attributes ( 'disabled' ) ) . toBeUndefined ( )
expect ( wrapper . findAll ( 'button' ) . find ( ( button ) = > button . text ( ) . includes ( '批量审核通过' ) ) ! . text ( ) ) . toContain ( '( 3) ' )
expect ( wrapper . findAll ( 'button' ) . find ( ( button ) = > button . text ( ) . includes ( '设为同柜不可拆组' ) ) ! . attributes ( 'disabled' ) ) . toBeDefined ( )
expect ( wrapper . text ( ) ) . not . toContain ( '平台收货仓不同' )
expect ( wrapper . text ( ) ) . not . toContain ( '渠道不同' )
} )
it ( 'uses inbound codes as the only row identifier and shows an explicit pending state' , async ( ) = > {
vi . mocked ( listPlatformUnifiedOrders ) . mockResolvedValue ( { records : [ rows [ 0 ] , { . . . rows [ 1 ] , inboundCode : null } ] , page : 1 , size : 20 , total : 2 , pages : 1 } )
const wrapper = mountView ( )