diff --git a/AGENTS.md b/AGENTS.md index 92732c75..4cf85648 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,11 +46,11 @@ | 消息中心 | `modules/notifications/` | Backend `iam/.../notification/`;仅顶部消息中心,不进入左侧菜单 | | 订单列表、详情、商品图片与入库费用 | `modules/unified-orders/`、`modules/first-leg-orders/`;平台商品图片由 `modules/unified-orders/api/unifiedOrders.ts` 按客户与 fileId 下载 | `order/`、`firstleg/`、Finance;图片读取归 `file/` 的 `PlatformProductImageController`。Order 状态为 `SUBMITTED` 时统一列表必须保持 `PENDING_REVIEW/APPROVE_ORDER`,不得被已存在的 Firstleg 准备中入库投影覆盖 | | 客户原始申报资料编辑与渠道变更 | `modules/unified-orders/components/OrderDeclarationEditorDialog.vue`、`api/unifiedOrders.ts`、`pages/UnifiedOrdersView.vue` | 使用订单版本和货物 `itemNo` 整体提交,不允许增删货物行;只编辑客户申报快照,不覆盖仓库/PDA 实测、测量审核或计费事实。渠道变化需二次确认并由 Backend `order/` 联查 `firstleg/` 的分柜、同柜、装柜与重新计价门禁;国内收货仓或中转仓变化必须重新下单 | -| 入库、测量、客户箱规策略与计价主数据 | `modules/inbounds/measurement/`、`modules/fba-pricing/`、`modules/dimension-config/`、`modules/customers/components/CustomerBillingRulesPanel.vue`、`modules/fee-items/` | 客户固定四档箱规,默认计算方式为 `ADD/MULTIPLY`;测量行可选实际尺寸、箱规尺寸策略或客户默认尺寸系数,保存后以 Backend `firstleg/` 返回的外箱尺寸、体积重和计费基数为准,不在页面独立重算 | +| 入库、测量、称重库位状态、客户箱规策略与计价主数据 | `modules/inbounds/measurement/`、`modules/inbounds/weight/components/WeightOcrPanel.vue`、`modules/fba-pricing/`、`modules/dimension-config/`、`modules/customers/components/CustomerBillingRulesPanel.vue`、`modules/fee-items/` | 客户固定四档箱规,默认计算方式为 `ADD/MULTIPLY`;测量行可选实际尺寸、箱规尺寸策略或客户默认尺寸系数,保存后以 Backend `firstleg/` 返回的外箱尺寸、体积重和计费基数为准,不在页面独立重算。称重页在每张图片卡片只展示服务端 `locationCode/slotStatus/sharedOverflow`,不渲染或自行推导整票预留引导;删除图片须提示槽位仍归本票保留,不得按图片数组下标推导托盘或库位 | | 财务与柜级公共费用分摊 | `modules/finance/`,继续读该目录 `AGENTS.md`;柜费入口 `modules/loading-lists/components/ContainerFeesPanel.vue`、`api/containerFees.ts` | `finance/`、`firstleg/`、`file/`、`docs/财务管理/`;跨客户公共柜费只按服务端柜内客户/订单事实分摊,金额必须守恒,创建与审核、驳回、调整、作废均整组原子处理 | | 货柜、排柜、预装/装柜清单、真实柜号后补与整柜报关 | `modules/container-loading/`、`modules/loading-lists/`;预装详情 `pages/PreloadPlanDetailView.vue`,货柜详情 `pages/ContainerDetailView.vue`,资料/PDA 证据 `components/ContainerOverviewPanel.vue`,报关 `components/ContainerCustomsPanel.vue`、`api/platformContainerCustoms.ts` | 创建柜次时自动生成唯一预装计划,加入入仓码即同步进入该计划,页面不提供创建计划或推送预装操作。预装详情先调用 `/loading-plans/{planId}/lifecycle`。订舱关联和预装确认允许真实集装箱号为空;首次补录可在 `EDITING/LOADING` 进行,PDA 最终完成前必须补齐;已有柜号纠正只允许 `EDITING` 且任务未领取、无物理作业事实。整柜报关逐资料完成,全买单柜使用 `complete-all-buy` | | 合柜报关 / 同柜不可拆组 | `modules/unified-orders/api/coLoadGroups.ts`、`pages/UnifiedOrdersView.vue`;装柜消费 `modules/container-loading/pages/SmartLoadingWorkbenchView.vue` | 前端只提交订单 ID;Backend `firstleg/loading/coload/` 展开并冻结每票全部可用入仓片段。成员数是入仓片段数,不等于订单票数;只要求同国内仓、同渠道,允许跨客户及不同目的仓港;分配、移除、取消均整组处理 | -| 全局智能装柜工作台、入仓码候选与箱数分配 | `modules/container-loading/components/SmartLoadingDialog.vue` 内嵌 `pages/GlobalSmartLoadingView.vue`,柜次页 `SmartLoadingWorkbenchView.vue`,以及 `smartLoadingChannelGroups.ts`、`api/platformContainerLoading.ts`;全局页当前不注册独立路由 | Backend `firstleg/` 的 `/inbound-candidates`、`/containers`、`/inbound-assignments`、`/pending-review-assignments`、`/group-assignments`、`/unpicked-items`。候选状态多选覆盖待审核、待测量、待分柜、装柜中,状态只用于筛选展示,按钮资格以服务端 `canAssign` 为准;待审核/待测量可提前占位但不得提前确认预装或启动 PDA。人工加入允许跨渠道,智能推荐仍按柜次渠道。柜次容量和限重取服务端字段;同柜组作为单卡整组分页、分配和移除,任一成员已拣时整组保留 | +| 全局智能装柜工作台、入仓码候选与箱数分配 | `modules/container-loading/components/SmartLoadingDialog.vue` 内嵌 `pages/GlobalSmartLoadingView.vue`,柜次页 `SmartLoadingWorkbenchView.vue`,以及 `smartLoadingChannelGroups.ts`、`smartLoadingItems.ts`、`api/platformContainerLoading.ts`;全局页当前不注册独立路由 | Backend `firstleg/` 的 `/inbound-candidates`、`/containers`、`/inbound-assignments`、`/pending-review-assignments`、`/group-assignments`、`/unpicked-items`。候选状态多选覆盖待审核、待测量、待分柜、装柜中,状态只用于筛选展示,按钮资格以服务端 `canAssign` 为准;待审核/待测量可提前占位但不得提前确认预装或启动 PDA。计划箱数编辑上限、已用和未用展示只消费服务端 `totalPackageCount/remainingPackageCount`,不得从候选页或本地规格重新拼算。人工加入允许跨渠道,智能推荐仍按柜次渠道。柜次容量和限重取服务端字段;同柜组作为单卡整组分页、分配和移除,任一成员已拣时整组保留 | | 三期订舱资料、打印、关联候选与出仓前船期 | `modules/ocean-bookings/` 的 `components/OceanBookingDocumentsPanel.vue`、`OceanBookingPrintDialog.vue`,以及 `modules/container-loading/`、`modules/port-schedules/` | 订舱草稿按当前版本维护资料,放舱后资料与表单只读;打印只对 `RELEASED` 开放。`platformOceanBookings.ts` 的 `/link-candidates` 只消费服务端分页,`containerCount` 是柜型需求 `quantity` 总和;Backend `firstleg/oceanbooking/`、`file/`、`print/`、`firstleg/portschedule/` | | 订舱级拖车预约 | `modules/trucking/api/platformTrucking.ts` 的 `/candidates`、`components/TruckAppointmentForm.vue`、`pages/TruckAppointmentCreateView.vue`、`TruckAppointmentsView.vue` | 表单只选择服务端返回的 `RELEASED` 订舱与拖车供应商,不选择或提交客户、柜次、装柜计划或真实集装箱号;提单号和仓库由订舱冻结事实带入。一个订舱最多一张非终态拖车单,重复创建转入现有单继续编辑;PDA 完成不自动推进拖车。附件为平台作用域且不重复提单文件;Backend `TruckAppointmentService`、`truck-appointments-v1.yaml` | | 历史报关协同与国内出仓 | `modules/customs/`、`modules/outbound-dispatch/` | `modules/customs/` 是历史报关案件/清单/代理提交与回执入口;装柜完成后的整柜退税/买单资料从货柜详情进入,不在旧模块复制;Backend `firstleg/outbound/dispatch/`、`firstleg/customs/`、`file/` | diff --git a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts index 59fbba3c..ce48d116 100644 --- a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts +++ b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts @@ -925,7 +925,8 @@ describe('GlobalSmartLoadingView', () => { const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/GlobalSmartLoadingView.vue'), 'utf8') expect(source).toContain(' { expect(card.get('.weight-card__facts').text()).toContain('库位A01 · 待上架') }) - it('renders the authoritative whole-inbound reservation summary and an empty reserved slot', async () => { + it('keeps whole-inbound reservation guidance out of the panel and shows location on each weight card', async () => { vi.mocked(getWeightWorkspace).mockResolvedValue({ ...workspace, palletLocationGuide: { @@ -260,13 +260,9 @@ describe('WeightOcrPanel confirmation behavior', () => { const wrapper = mountPanel() await flushPromises() - const guide = wrapper.get('.putaway-guide') - expect(guide.text()).toContain('整票预留库位') - expect(guide.text()).toContain('A01 / A02 / A03') - expect(guide.text()).toContain('预留槽位数3') - expect(guide.text()).toContain('实际托数2') - expect(guide.text()).toContain('预留空位数1') - expect(guide.text()).toContain('A03预留空位本票预留空位') + expect(wrapper.find('.putaway-guide').exists()).toBe(false) + expect(wrapper.text()).not.toContain('整票上架引导') + expect(wrapper.get('.weight-card__facts').text()).toContain('库位A01 · 待上架') }) it('does not render a full-width placeholder when no whole-inbound guide exists', async () => { @@ -296,7 +292,7 @@ describe('WeightOcrPanel confirmation behavior', () => { expect(wrapper.text()).toContain('A0 临时溢出位') expect(wrapper.get('.weight-card__facts').text()).toContain('库位A0 · 待上架 · A0 临时溢出位') - expect(wrapper.get('.putaway-guide__slots li').classes()).toContain('is-overflow') + expect(wrapper.find('.putaway-guide').exists()).toBe(false) }) it.each([ @@ -372,8 +368,7 @@ describe('WeightOcrPanel confirmation behavior', () => { ) expect(getWeightWorkspace).toHaveBeenCalledTimes(2) expect(wrapper.findAll('.weight-card')).toHaveLength(0) - expect(wrapper.get('.putaway-guide').text()).toContain('预留空位数1') - expect(wrapper.get('.putaway-guide').text()).toContain('A01预留空位本票预留空位') + expect(wrapper.find('.putaway-guide').exists()).toBe(false) }) it('keeps the image and server workspace visible when deletion fails', async () => { diff --git a/src/modules/inbounds/weight/components/WeightOcrPanel.test.ts b/src/modules/inbounds/weight/components/WeightOcrPanel.test.ts index 8d88590c..0a02185f 100644 --- a/src/modules/inbounds/weight/components/WeightOcrPanel.test.ts +++ b/src/modules/inbounds/weight/components/WeightOcrPanel.test.ts @@ -35,14 +35,12 @@ describe('WeightOcrPanel contract', () => { expect(source).toContain('货物重量') expect(source).toContain('palletTareWeightKg') expect(source).toContain('netWeightKg') - expect(source).toContain('slot.palletSequence') expect(source).toContain('row.locationCode') expect(source).toContain('row.sharedOverflow') expect(source).toContain('putawayStatusLabel(row.slotStatus)') - expect(source).toContain('workspace.palletLocationGuide.reservedSlotCount') - expect(source).toContain('workspace.palletLocationGuide.actualPalletCount') - expect(source).toContain('workspace.palletLocationGuide.reservedEmptySlotCount') - expect(source).toContain('本票预留空位') + expect(source).not.toContain('class="putaway-guide"') + expect(source).not.toContain('整票上架引导') + expect(source).not.toContain('整票预留库位') expect(source).not.toContain('尚未分配整票预留库位') expect(source).not.toContain('class="weight-card__putaway"') expect(source).toContain('
库位
] || '未分配' } -function putawayStatusType(status: WeightResultResource['slotStatus']) { - if (status === 'TRANSFERRED') return 'success' - if (status === 'BOUND') return 'warning' - if (status === 'RELEASED') return 'info' - return 'info' -} - -function guideSlotStatusType(status: WeightPutawaySlotStatus) { - return putawayStatusType(status) -} - function hasWeightDraftChanged(row: WeightResultResource) { const draft = weightDrafts.value[row.id] if (!draft) return false @@ -557,37 +545,6 @@ defineExpose({ reload: loadWorkspace })