From 0ed913a11435d04cd6348abc145da908be6344ac Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Thu, 10 Sep 2026 16:33:43 +0800 Subject: [PATCH] fix: expose manual plans awaiting pallets --- AGENTS.md | 2 +- src/modules/overseas-warehouse/api/lastMileOrders.test.ts | 2 +- src/modules/overseas-warehouse/api/lastMileOrders.ts | 1 + .../pages/LastMileOrdersView.behavior.test.ts | 8 +++++--- .../overseas-warehouse/pages/LastMileOrdersView.vue | 6 +++--- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8fa0908d..211b3ca3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -73,7 +73,7 @@ | 关键词 | 页面/路由入口 | API 与联查 | |---|---|---| -| 尾程订单控制与柜级入仓计划转换 | `modules/overseas-warehouse/pages/LastMileOrdersView.vue`、`LastMileOrderDetailView.vue` | 柜子工作台按 `sourceContainerBookingId` 消费 `/orders/container-summaries`;服务端分页返回全部稳定来源柜,计划已经齐全的柜仍保留用于接柜仓查询与修改,并按冻结 `plannedArrivalAt` 升序、空值最后排序。详情返回全柜订单且不受列表分页截断;是否展示生成动作只消费 `allPlansReady/pendingPlanCount`,不得在浏览器拼柜或自行推导就绪。确认弹框先调用 `/inbound-plans/container-preview`,按服务端 FBA/一件代发/私人地址分组展示托数、`readiness/blockers`,再把同一 `snapshotVersion/snapshotHash` 原样提交 `/inbound-plans/convert-container`;前端不计算托数、不逐票建计划、不预占托盘,快照冲突后重新获取预览。服务端只为剩余订单逐票生成独立计划并编排真实托盘批量预留/确认,整批原子且重放不得产生第二批资源。单票完整入库计划、暂扣/解除和八行人工节点均从 `api/lastMileOrders.ts` 提交订单版本与幂等键;入仓码只读展示并提交订单冻结值,不允许人工改写,暂扣资格、接柜仓锁定原因和操作能力只消费服务端结果,人工节点一经保存不得回退柜级节点。转仓候选只取 `modules/iam/api/platformIam.ts` 的平台公共 `ACTIVE + FBA` 仓主档;Backend `lastleg-service/` | +| 尾程订单控制与柜级入仓计划转换 | `modules/overseas-warehouse/pages/LastMileOrdersView.vue`、`LastMileOrderDetailView.vue` | 柜子工作台按 `sourceContainerBookingId` 消费 `/orders/container-summaries`;服务端分页返回全部稳定来源柜,计划已经齐全的柜仍保留用于接柜仓查询、修改和补齐真实托盘,并按冻结 `plannedArrivalAt` 升序、空值最后排序。详情返回全柜订单且不受列表分页截断;是否展示生成动作只消费 `pendingPlanCount/resourcePendingPlanCount`,不得在浏览器拼柜或自行推导就绪。确认弹框先调用 `/inbound-plans/container-preview`,按服务端 FBA/一件代发/私人地址分组展示托数、`readiness/blockers`,再把同一 `snapshotVersion/snapshotHash` 原样提交 `/inbound-plans/convert-container`;前端不计算托数、不逐票建计划、不预占托盘,快照冲突后重新获取预览。服务端只为剩余订单逐票生成独立计划,并为已有人工计划补齐真实托盘,整批原子且重放不得产生第二批资源。单票完整入库计划、暂扣/解除和八行人工节点均从 `api/lastMileOrders.ts` 提交订单版本与幂等键;入仓码只读展示并提交订单冻结值,不允许人工改写,暂扣资格、接柜仓锁定原因和操作能力只消费服务端结果,人工节点一经保存不得回退柜级节点。转仓候选只取 `modules/iam/api/platformIam.ts` 的平台公共 `ACTIVE + FBA` 仓主档;Backend `lastleg-service/` | | 入仓单、入仓计划、FBA 预约 | `modules/overseas-warehouse/pages/InboundOrdersView.vue`、`InboundOrderDetailView.vue` | 列表/预约 `modules/overseas-warehouse/api/inboundOrders.ts`,计划列表/详情 `inboundPlans.ts`;Backend `lastleg-service/inboundplan/` | | 排车查询、智能预排与转派送 | `modules/overseas-warehouse/pages/DispatchesView.vue`、`DispatchDetailView.vue`、`components/SmartDispatchDialog.vue` | `modules/overseas-warehouse/api/dispatches.ts`;Backend `lastleg-service/dispatch/`、`delivery/`;覆盖详情、候选、草稿柜、托盘锁、`pre-arrange` 和 `transfer-delivery`。页面能力必须由正式路由、API 调用和测试共同证明 | | 海外出库与派送 | `pages/OutboundsView.vue`、`DeliveryOrdersView.vue`、`DeliveryOrderDetailView.vue` | `api/outbounds.ts`、`deliveryOrders.ts`;一件代发出库、取消、派送列表/详情及退回入口对应 Backend `lastleg-service/delivery/`、`dropship/` | diff --git a/src/modules/overseas-warehouse/api/lastMileOrders.test.ts b/src/modules/overseas-warehouse/api/lastMileOrders.test.ts index 7e348c3e..a3b10563 100644 --- a/src/modules/overseas-warehouse/api/lastMileOrders.test.ts +++ b/src/modules/overseas-warehouse/api/lastMileOrders.test.ts @@ -131,7 +131,7 @@ describe('last-mile order overseas API', () => { const record = { sourceContainerBookingId: '2092873463568597001', containerNo: 'CONT-15', totalOrderCount: 15, inboundCodeCount: 13, missingInboundCodeCount: 2, planCount: 10, plannedInboundCodeCount: 10, - pendingPlanCount: 5, plannedArrivalAt: '2026-09-01T08:00:00', allPlansReady: false, blockingReason: '存在2票缺少入仓码', + pendingPlanCount: 5, resourcePendingPlanCount: 0, plannedArrivalAt: '2026-09-01T08:00:00', allPlansReady: false, blockingReason: '存在2票缺少入仓码', } vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', message: 'success', data: { records: [record], page: '2', size: '10', total: '21', pages: '3' }, diff --git a/src/modules/overseas-warehouse/api/lastMileOrders.ts b/src/modules/overseas-warehouse/api/lastMileOrders.ts index 16bb0080..c07cd5d1 100644 --- a/src/modules/overseas-warehouse/api/lastMileOrders.ts +++ b/src/modules/overseas-warehouse/api/lastMileOrders.ts @@ -182,6 +182,7 @@ export interface ContainerPlanProgressSummaryDto { planCount: number plannedInboundCodeCount: number pendingPlanCount: number + resourcePendingPlanCount: number plannedArrivalAt: string | null allPlansReady: boolean blockingReason: string | null diff --git a/src/modules/overseas-warehouse/pages/LastMileOrdersView.behavior.test.ts b/src/modules/overseas-warehouse/pages/LastMileOrdersView.behavior.test.ts index fbeedd1b..027c9a03 100644 --- a/src/modules/overseas-warehouse/pages/LastMileOrdersView.behavior.test.ts +++ b/src/modules/overseas-warehouse/pages/LastMileOrdersView.behavior.test.ts @@ -52,7 +52,7 @@ const summary = { overseasWarehouseId: '9007199254740995', overseasWarehouseCode: 'LAX01', overseasWarehouseName: '洛杉矶接柜仓', assignmentVersion: 7, canChangeReceivingWarehouse: true, receivingWarehouseLockReason: null, inboundCodeCount: 15, missingInboundCodeCount: 0, planCount: 10, plannedInboundCodeCount: 10, - pendingPlanCount: 5, plannedArrivalAt: '2026-09-01T08:00:00', allPlansReady: false, + pendingPlanCount: 5, resourcePendingPlanCount: 0, plannedArrivalAt: '2026-09-01T08:00:00', allPlansReady: false, blockingReason: '存在5票尚未生成有效入库计划', } const fbaWarehouse = { @@ -398,12 +398,13 @@ describe('LastMileOrdersView pending order and container conversion', () => { expect(wrapper.text().indexOf('CONT-15')).toBeLessThan(wrapper.text().indexOf('CONT-NULL')) }) - it('keeps an all-plans-ready cabinet visible and allows only the server-authorized warehouse change', async () => { + it('keeps an all-plans-ready cabinet available when its real pallets are still pending', async () => { const ready = { ...summary, planCount: summary.inboundCodeCount, plannedInboundCodeCount: summary.inboundCodeCount, pendingPlanCount: 0, + resourcePendingPlanCount: 1, allPlansReady: true, blockingReason: null, } @@ -412,7 +413,8 @@ describe('LastMileOrdersView pending order and container conversion', () => { await openHiddenContainerWorkbench(wrapper) expect(wrapper.text()).toContain('CONT-15') expect(wrapper.text()).toContain('0个入仓码待生成计划') - expect((button(wrapper, '生成入库计划')!.element as HTMLButtonElement).disabled).toBe(true) + expect(wrapper.text()).toContain('1 票待补真实托盘') + expect((button(wrapper, '生成入库计划')!.element as HTMLButtonElement).disabled).toBe(false) expect((button(wrapper, '修改接柜仓')!.element as HTMLButtonElement).disabled).toBe(false) }) diff --git a/src/modules/overseas-warehouse/pages/LastMileOrdersView.vue b/src/modules/overseas-warehouse/pages/LastMileOrdersView.vue index 155275ba..2c00cc93 100644 --- a/src/modules/overseas-warehouse/pages/LastMileOrdersView.vue +++ b/src/modules/overseas-warehouse/pages/LastMileOrdersView.vue @@ -246,13 +246,12 @@ function inboundPlanStatusLabel(value: unknown) { } as Record)[code] || (code ? '未知状态' : '—') } function canGenerateContainerPlans(container: ContainerPlanProgressSummaryDto) { - return Boolean(!container.allPlansReady - && container.containerNo + return Boolean(container.containerNo && container.overseasWarehouseId && container.overseasWarehouseCode && container.overseasWarehouseName && container.assignmentVersion >= 0 - && container.pendingPlanCount > 0) + && (container.pendingPlanCount > 0 || container.resourcePendingPlanCount > 0)) } function containerSnapshotBlockReason(container: ContainerPlanProgressSummaryDto) { if (!container.containerNo) return container.blockingReason || '来源柜真实集装箱号缺失、格式无效或存在漂移' @@ -772,6 +771,7 @@ onMounted(() => { void load() }) 共 {{ container.inboundCodeCount }} 个入仓码 + {{ container.resourcePendingPlanCount }} 票待补真实托盘 查看详情