diff --git a/src/modules/ocean-bookings/PROTOTYPE_MATRIX.md b/src/modules/ocean-bookings/PROTOTYPE_MATRIX.md index e97ae2f5..31b16ab7 100644 --- a/src/modules/ocean-bookings/PROTOTYPE_MATRIX.md +++ b/src/modules/ocean-bookings/PROTOTYPE_MATRIX.md @@ -2,14 +2,14 @@ 业务依据为用户提供的《订舱信息页面说明.docx》及页面截图;本轮确认:放舱后仅补实货量、客服手工录入、保留现有提单确认件,正式提单从外部附件接收。样式使用 `docs/Admin高密度界面规范.md` 的详情与基本信息、蓝白主题及既有公共密度。用户后续提供现页与产品稿对比,确认现页缺少层次、重点且间距过大;订舱页以该产品稿为局部视觉依据:紧凑页头、蓝色圆点连线流程、编号区块、细线小标题、浅底三方卡片及右下主打印按钮。可编辑输入、下拉和文本域使用白底、清晰边框与文字,悬停/聚焦使用蓝色反馈;灰底和禁止光标仅用于真实禁用状态,校验错误仍保留组件错误色。 -流程条根据已保存订舱、当前未保存修改、放舱状态及实货量推进:当前步骤蓝底,已完成节点勾选,待处理灰色。第一步的“已保存”不代替放舱完整性校验;打印节点仅在本次页面成功生成对应数据的 PDF 预览后显示“已预览”,失败或只点击按钮不推进,也不声称实际打印完成。预览标记随本次页面保留,刷新后按服务端保存/放舱/实值恢复进度,打印仍可重新预览;单据消费的数据改变后,该单据重新进入待预览。 +流程条根据已保存订舱、当前未保存修改、放舱状态及实货量推进:当前步骤蓝底,已通过阶段勾选,待处理灰色。第一步的“已保存”不代替放舱完整性校验;打印节点仅在本次页面成功生成对应数据的 PDF 预览后显示“已预览”,失败或只点击按钮不产生预览事实,也不声称实际打印完成。预览标记随本次页面保留;刷新后按服务端保存/放舱/实值恢复进度,已放舱时托运单阶段保持通过,提示“可重新预览 / 打印”,避免前面灰色、后面完成的断开。放舱前托运单数据改变须重新预览;提单确认件始终要求已保存实值和对应 PDF 成功预览后才完成。 -| 页面/路由 | 操作 | 参考承载与布局 | 当前实现 | 人工结论 | +| 页面/路由 | 操作 | 参考承载与布局 | 当前实现 | 页面核对 | |---|---|---|---|---| -| `/ocean-bookings/new`、`/ocean-bookings/:bookingId` | 草稿新增、维护 | 独立页面;左主资料、右三方并排,下方放舱资料 | 独立页面;按产品稿重排视觉层级,保留仓库、渠道、预计到港、多柜型和附件;港代码与港名成组、委实成对输入,新增保存留在详情 | 待人工截图确认 | -| `/ocean-bookings/:bookingId` | 已放舱补实 | 客服补录实际货量 | 运输及预报只读,实值可按编辑权限补录,原因必填并版本审计 | 待人工截图确认 | -| `/ocean-bookings/:bookingId` | 托运单、提单确认件 | 两个作业入口,A4单据预览 | 两张业务卡片底部右侧的蓝色主按钮,分别直达现有PDF预览;读已保存委/实数据,缺失显示“—” | 待人工截图确认 | +| `/ocean-bookings/new`、`/ocean-bookings/:bookingId` | 草稿新增、维护 | 独立页面;左主资料、右三方并排,下方放舱资料 | 独立页面;按产品稿重排视觉层级,保留仓库、渠道、预计到港、多柜型和附件;港代码与港名成组、委实成对输入,新增保存留在详情 | 已核对新增保存、初始步骤、控件状态与仓库渠道联动;完整长字段展示待人工确认 | +| `/ocean-bookings/:bookingId` | 已放舱补实 | 客服补录实际货量 | 运输及预报只读,实值可按编辑权限补录,原因必填并版本审计 | 已核对放舱、原因校验、补实保存和历史;最终 TEST #698 回验实值保存后立即回显,无需刷新 | +| `/ocean-bookings/:bookingId` | 托运单、提单确认件 | 两个作业入口,A4单据预览 | 两张业务卡片底部右侧的蓝色主按钮,分别直达现有PDF预览;读已保存委/实数据,缺失显示“—” | 弹框开关/重开、PDF 生成与数据映射已核对;内嵌 PDF 空白,显示未通过 | 人工按 1920×1080、100% 缩放核对三方长名称/地址、两类货量、保存失败与版本冲突、冻结/无编辑权限,以及两类 PDF 预览的打开、关闭和重开。自动检查结果在交付中单独报告,不能代替人工截图。 -2026-10-22 用户明确授权 AI 操作 TEST 页面后,已实际核对新增页:1920×1080 下初始仅第 1 步高亮、后续待处理;白底编辑控件、蓝色聚焦边框与真实灰底禁用状态可区分;船公司下拉及仓库—渠道联动可用。截图保存在本机 `C:/Users/BY-OY/.codex/booking-ui-acceptance-20261022/booking-new-progress.png`。保存未通过:独立测试请求返回 S0500,服务日志与只读结构核查确认 TEST 缺少订舱货物/关系方字段且冻结触发器仍为旧版。完整保存、放舱、补实和两类 PDF 预览仍待数据库结构同步后验收,不将本次局部页面核对记为完整流程通过。环境事实以部署主契约“订舱页面 TEST 验收阻断”为准。 +2026-10-22 用户明确授权 AI 操作 TEST 页面并单独授权结构 SQL 后,已接续同一测试订舱 `OB202610220011` 完成保存、确认放舱、手工补实及两类 PDF 请求的页面核对,委实分离、版本与原因历史正确。发现并修复数字控件过期禁用辅助标记和保存后的输入缓存;两份定向测试 23 项通过,最终版本经 TEST #698 发布并回验:修正件数为 481 后无需刷新,输入显示与服务器版本 5 一致,毛重和体积保持,委值仍为 500。截图及脱敏证据在本机 `C:/Users/BY-OY/.codex/booking-ui-acceptance-20261022/`;两类 PDF 可下载且外部渲染正常,但内置浏览器的内嵌显示为空白,不能记为完整打印显示通过。环境事实以部署主契约“订舱 TEST 结构同步与页面验收”为准。 diff --git a/src/modules/ocean-bookings/workflow.test.ts b/src/modules/ocean-bookings/workflow.test.ts index da166483..ee1d1838 100644 --- a/src/modules/ocean-bookings/workflow.test.ts +++ b/src/modules/ocean-bookings/workflow.test.ts @@ -45,6 +45,8 @@ describe('ocean booking workflow milestones', () => { const saved = detail() saved.status = 'RELEASED' let steps = oceanBookingWorkflow(saved, false, false, {}) + expect(steps.map(step => step.state)).toEqual(['complete', 'complete', 'complete', 'current']) + expect(steps[1]).toMatchObject({ state: 'complete', status: '可重新预览 / 打印' }) expect(steps[2]).toMatchObject({ state: 'complete', status: '已放舱' }) expect(steps[3]).toMatchObject({ state: 'current', status: '待补齐实值' }) saved.actualPackageCount = 480 @@ -72,6 +74,14 @@ describe('ocean booking workflow milestones', () => { expect(steps[3]).toMatchObject({ state: 'current', status: '可预览 / 打印' }) saved.declaredPackageCount = 510 steps = oceanBookingWorkflow(saved, false, false, previews) - expect(steps[1]?.state).toBe('pending') + expect(steps[1]).toMatchObject({ state: 'complete', status: '可重新预览 / 打印' }) + }) + + it('requires a fresh preview when draft print data changes before release', () => { + const saved = detail() + const previews = { SHIPPING_INSTRUCTION: oceanBookingPrintSignature(saved, 'SHIPPING_INSTRUCTION') } + saved.declaredPackageCount = 510 + expect(oceanBookingWorkflow(saved, false, false, previews).map(step => step.state)) + .toEqual(['complete', 'current', 'pending', 'pending']) }) }) diff --git a/src/modules/ocean-bookings/workflow.ts b/src/modules/ocean-bookings/workflow.ts index 492ee32e..9a9c607d 100644 --- a/src/modules/ocean-bookings/workflow.ts +++ b/src/modules/ocean-bookings/workflow.ts @@ -36,6 +36,9 @@ export function oceanBookingWorkflow( .every(value => value != null && Number(value) > 0)) const previewed = (type: OceanBookingPrintType) => Boolean(detail && previews[type] === oceanBookingPrintSignature(detail, type)) const instructionPreviewed = saved && previewed('SHIPPING_INSTRUCTION') + // 已放舱代表已进入后续作业;刷新清除预览标记时,不让先前阶段倒退。 + // 阶段通过不代表有打印记录,仍用状态文案区分本次是否预览。 + const instructionPassed = released || instructionPreviewed const confirmationPreviewed = saved && released && actualComplete && !actualDirty && previewed('BILL_OF_LADING_CONFIRMATION') const current = !saved ? 0 : !released ? instructionPreviewed ? 2 : 1 : confirmationPreviewed ? -1 : 3 const step = (index: number, label: string, complete: boolean, status: string): OceanBookingWorkflowStep => ({ @@ -43,7 +46,7 @@ export function oceanBookingWorkflow( }) return [ step(0, '填写并保存订舱信息', saved, saved ? '已保存' : detail ? '修改待保存' : '待填写并保存'), - step(1, '托运单预览 / 打印', instructionPreviewed, instructionPreviewed ? '已预览' : saved ? '可预览 / 打印' : '待保存资料'), + step(1, '托运单预览 / 打印', instructionPassed, instructionPreviewed ? '已预览' : released ? '可重新预览 / 打印' : saved ? '可预览 / 打印' : '待保存资料'), step(2, '补齐资料并确认放舱', released, released ? '已放舱' : saved ? '待确认放舱' : '待补齐资料'), step(3, '补实并预览提单确认件', confirmationPreviewed, !released ? '待放舱' : actualDirty ? '实值待保存' : !actualComplete ? '待补齐实值' : confirmationPreviewed ? '已预览' : '可预览 / 打印'), ]