diff --git a/src/modules/unified-orders/api/coLoadGroups.test.ts b/src/modules/unified-orders/api/coLoadGroups.test.ts index c50e9f18..2aa2e6ec 100644 --- a/src/modules/unified-orders/api/coLoadGroups.test.ts +++ b/src/modules/unified-orders/api/coLoadGroups.test.ts @@ -63,4 +63,20 @@ describe('co-load group API', () => { expect.objectContaining({ orderId: '2093000000000000008', inboundId: '2093000000000000009', inboundCode: 'NYEXX2608310002', fullPackageCount: 10 }), ]) }) + + it('normalizes missing and blank member inbound codes without exposing technical ids as fallbacks', async () => { + const incompleteGroup = { + ...group, + members: [ + { ...group.members[0], inboundCode: undefined }, + { ...group.members[1], inboundCode: null }, + { ...group.members[1], inboundId: 2093000000000000012n, inboundCode: ' ' }, + { ...group.members[1], inboundId: 2093000000000000013n, inboundCode: ' NYEXX2608310003 ' }, + ], + } + vi.spyOn(http, 'post').mockResolvedValue({ code: '200', message: 'ok', data: incompleteGroup }) + const result = await createPlatformCoLoadGroup(['2093000000000000005', '2093000000000000008']) + expect(result.members.map((member) => member.inboundCode)).toEqual(['', '', '', 'NYEXX2608310003']) + expect(result.members.map((member) => member.inboundCode)).not.toContain('2093000000000000012') + }) }) diff --git a/src/modules/unified-orders/api/coLoadGroups.ts b/src/modules/unified-orders/api/coLoadGroups.ts index 5f16fee2..df3844e0 100644 --- a/src/modules/unified-orders/api/coLoadGroups.ts +++ b/src/modules/unified-orders/api/coLoadGroups.ts @@ -6,7 +6,6 @@ export interface CoLoadGroupMember { tenantId: string orderId: string inboundId: string - inboundCode: string fullPackageCount: number } @@ -24,21 +23,31 @@ export interface CoLoadGroup { updatedAt: string } -export interface OrderCoLoadGroupInfo { - orderId: string - group: CoLoadGroup +export interface CoLoadBusinessMember { + inboundCode: string +} + +export interface CoLoadBusinessSummary { + status: CoLoadGroupStatus + memberCount: number + members: CoLoadBusinessMember[] } type RawId = string | number +type RawCoLoadGroupMember = Omit & { + tenantId: RawId + orderId: RawId + inboundId: RawId +} type RawCoLoadGroup = Omit & { groupId: RawId warehouseId: RawId lockedPlanId: RawId | null - members: Array & { tenantId: RawId; orderId: RawId; inboundId: RawId }> + members: RawCoLoadGroupMember[] } -type RawOrderCoLoadGroupInfo = Omit & { - orderId: RawId - group: RawCoLoadGroup +type RawCoLoadBusinessSummary = Omit & { + memberCount: number | string + members: Array<{ inboundCode?: string | null }> } const basePath = '/platform/v1/first-leg/coload-groups' @@ -81,13 +90,17 @@ export async function cancelPlatformCoLoadGroup(groupId: string, expectedVersion return normalizeGroup(unwrapApiResponse(response)) } -export async function batchQueryPlatformCoLoadGroups(orderIds: string[]) { - const response = await http.post, ApiEnvelope>( - `${basePath}/batch-query`, - { orderIds }, +export async function getPlatformCoLoadGroupByInboundCode(inboundCode: string) { + const response = await http.get, ApiEnvelope>( + `${basePath}/by-inbound-code/${encodeURIComponent(inboundCode)}`, ) - return unwrapApiResponse(response).map((item) => ({ - orderId: String(item.orderId), - group: normalizeGroup(item.group), + const raw = unwrapApiResponse(response) + const members = (raw.members || []).map((member) => ({ + inboundCode: typeof member.inboundCode === 'string' ? member.inboundCode.trim() : '', })) + return { + status: raw.status, + memberCount: Number(raw.memberCount), + members, + } satisfies CoLoadBusinessSummary } diff --git a/src/modules/unified-orders/api/unifiedOrders.ts b/src/modules/unified-orders/api/unifiedOrders.ts index 1ff047a0..7011ef89 100644 --- a/src/modules/unified-orders/api/unifiedOrders.ts +++ b/src/modules/unified-orders/api/unifiedOrders.ts @@ -75,6 +75,12 @@ export interface UnifiedOrderRelationSummary { childCount: number } +export interface UnifiedOrderCoLoadGroupSummary { + status: string + memberCount: number + memberInboundCodes: string[] +} + export interface UnifiedOrderResource { orderId: number | string tenantId: number | string @@ -103,6 +109,7 @@ export interface UnifiedOrderResource { loading: UnifiedOrderLoadingSummary | null delivery: UnifiedOrderDeliverySummary | null transport: UnifiedOrderTransportSummary | null + coLoadGroup: UnifiedOrderCoLoadGroupSummary | null createdAt: string | null updatedAt: string | null expectedArrivalAt: string | null @@ -368,6 +375,13 @@ function normalizeRow(raw: UnifiedOrderResource): UnifiedOrderResource { evidenceCount: nullableInteger(raw.loading.evidenceCount), } : null, transport: raw.transport ? { ...raw.transport } : null, + coLoadGroup: raw.coLoadGroup ? { + status: String(raw.coLoadGroup.status || ''), + memberCount: integer(raw.coLoadGroup.memberCount, 0), + memberInboundCodes: (raw.coLoadGroup.memberInboundCodes || []) + .map((value) => typeof value === 'string' ? value.trim() : '') + .filter(Boolean), + } : null, } } diff --git a/src/modules/unified-orders/index.ts b/src/modules/unified-orders/index.ts index bb658ed6..81057d42 100644 --- a/src/modules/unified-orders/index.ts +++ b/src/modules/unified-orders/index.ts @@ -5,13 +5,14 @@ export { type UnifiedOrderResource, } from './api/unifiedOrders' export { - batchQueryPlatformCoLoadGroups, cancelPlatformCoLoadGroup, createPlatformCoLoadGroup, + getPlatformCoLoadGroupByInboundCode, + type CoLoadBusinessMember, + type CoLoadBusinessSummary, type CoLoadGroup, type CoLoadGroupMember, type CoLoadGroupStatus, - type OrderCoLoadGroupInfo, } from './api/coLoadGroups' export { diff --git a/src/modules/unified-orders/pages/UnifiedOrdersView.coLoad.test.ts b/src/modules/unified-orders/pages/UnifiedOrdersView.coLoad.test.ts index abf60f4e..364224ce 100644 --- a/src/modules/unified-orders/pages/UnifiedOrdersView.coLoad.test.ts +++ b/src/modules/unified-orders/pages/UnifiedOrdersView.coLoad.test.ts @@ -102,7 +102,7 @@ describe('UnifiedOrdersView co-load group behavior', () => { expect(wrapper.text()).toContain('同柜组 · 2 票 · 未锁定') expect(wrapper.text()).not.toContain('CLG-9001') await wrapper.get('[aria-label="查看同柜组 · 2 票 · 未锁定成员"]').trigger('click') - expect(wrapper.text()).toContain('3 个入仓码') + expect(wrapper.text()).toContain('3 个成员') expect(wrapper.text()).toContain('13 箱') expect(wrapper.text()).toContain('IN-1') expect(wrapper.text()).toContain('IN-1-B') @@ -116,4 +116,23 @@ describe('UnifiedOrdersView co-load group behavior', () => { expect(cancelPlatformCoLoadGroup).toHaveBeenCalledWith('9001', 0, '计划调整') expect(ElMessageBox.prompt).toHaveBeenCalledWith(expect.stringContaining('不支持单独移除成员'), '取消同柜不可拆组', expect.any(Object)) }) + + it.each([ + ['undefined', undefined], + ['null', null], + ['blank', ' '], + ])('keeps the member dialog readable when a normalized inbound code is %s', async (_case, inboundCode) => { + const incompleteGroup = { + ...group, + members: [{ ...group.members[0], inboundCode: inboundCode as unknown as string }, group.members[1]], + } + vi.mocked(batchQueryPlatformCoLoadGroups).mockResolvedValue(rows.map((row) => ({ orderId: row.orderId, group: incompleteGroup }))) + const wrapper = mountView() + await flushPromises() + await wrapper.get('[aria-label="查看同柜组 · 2 票 · 未锁定成员"]').trigger('click') + expect(wrapper.text()).toContain('同柜组成员入仓码尚未返回,请刷新后重试') + expect(wrapper.text()).not.toContain('CLG-9001') + expect(wrapper.text()).not.toContain('ORD-1') + expect(wrapper.text()).not.toContain('5001') + }) }) diff --git a/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts b/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts index 3fae982f..5ce061d8 100644 --- a/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts +++ b/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts @@ -188,12 +188,21 @@ describe('UnifiedOrdersView contract', () => { expect(source).toContain('v-for="member in coLoadDetailMembers"') expect(source).toContain('入仓码箱数') expect(source).toContain('{{ member.inboundCode }}') + expect(source).toContain('同柜组成员入仓码尚未返回,请刷新后重试') + expect(source).toContain('coLoadDetailHasMissingInboundCodes') expect(source).not.toContain('visibleInboundCode') expect(source).not.toContain('visibleOrderNo') expect(source).not.toContain('订单编码') expect(source).not.toContain('客户 ID') }) + it('names the cross-domain relationship entry as fulfillment details', () => { + expect(source).toContain('>履约详情') + expect(source).toContain('aria-label="查看该入仓码的订单、装柜、尾程与库存关系"') + expect(source).toContain('title="查看该入仓码的订单、装柜、尾程与库存关系"') + expect(source).not.toContain('>关联数据') + }) + it('keeps editable query values separate from the applied list request', () => { expect(source).toContain('const appliedFilters = ref(emptyFilters())') expect(source).toContain('const activeFilters = appliedFilters.value') diff --git a/src/modules/unified-orders/pages/UnifiedOrdersView.vue b/src/modules/unified-orders/pages/UnifiedOrdersView.vue index 20232edd..49e9a1a4 100644 --- a/src/modules/unified-orders/pages/UnifiedOrdersView.vue +++ b/src/modules/unified-orders/pages/UnifiedOrdersView.vue @@ -1,7 +1,7 @@