feat(detail-page-structure-progress-actions): 统一详情处理进度与操作区
这个提交包含在:
@@ -489,3 +489,74 @@ const label = status === "draft" ? "草稿" : status;
|
||||
{["reviewed", "failed"].includes(batch.status) ? <PaymentRegistrationFields /> : null}
|
||||
{needsBankReceipt ? <UploadReceipt /> : canRegister ? <RegisterPaid /> : null}
|
||||
```
|
||||
|
||||
## Scenario: Shared Payment Processing Projection
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: adding or changing payment-stage labels, status projection, receipt/order guidance, reimbursement progress or payment-batch detail progress.
|
||||
- This is a read-only cross-layer projection. It does not add workflow tasks, alter the payment write state machine or relax receipt/maker-checker gates.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Shared service: `server/src/services/paymentProcessingProgress.js`.
|
||||
- Builder: `buildPaymentProcessingSemantics({ status, createdAt, reviewedAt, executedAt, cancelledAt, cancelledReason, requiresBankReceipt, receiptCount, paymentOrderExportCount })`.
|
||||
- Channel helpers: `resolveItemPaymentChannel(batch, item)` and `requiresBankReceipt(batch)`.
|
||||
- Payment detail: `GET /api/payment-batches/:id` returns `processingProgress.stages[]`; list responses do not return this field.
|
||||
- Stage states: `completed | current | pending | exception | terminated`.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- The shared service is the only runtime source for payment stage keys, labels and `draft|reviewed|executed|failed|cancelled` state projection. Reimbursement and payment-batch routes only assemble their own DTO view, resolve actor names and add permission-gated links.
|
||||
- Reimbursement keeps its single-item `paymentBatchItem` view; payment detail keeps the whole-batch view. Do not replace these with one database-aware DTO builder, and do not add route-local status branches after calling the shared builder.
|
||||
- `requiresBankReceipt` is shared with the execute guard and resolves the effective item channel, including the legacy null-channel reimbursement fallback to `bank`. Receipt count alone must never decide whether a receipt is required.
|
||||
- A reviewed non-bank batch is current at `付款完成` with guidance to register completion. It must not mention uploading a bank receipt or generating a bank order.
|
||||
- A reviewed bank batch with no active receipt distinguishes no order vs order generated; an active receipt changes guidance to registration. Payment-order count affects copy only when `requiresBankReceipt=true`.
|
||||
- `failed` uses `exception`. A cancellation before review makes the review stage `exception` and payment stage `terminated`; a cancellation after review completes review and makes payment `exception`. `terminated` is a neutral stopped state, not pending, completed or failed.
|
||||
- `actorSource=creator|reviewer|executor|canceller` is an internal semantic reference. The shared service never queries employees; each response assembler resolves only a nullable actor name and never exposes actor IDs inside progress.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Unknown/missing status -> created remains completed and downstream stages remain pending; do not guess a current or completed business fact.
|
||||
- `reviewed + requiresBankReceipt=false` -> current payment guidance is registration only, regardless of receipt/order counts.
|
||||
- `reviewed + requiresBankReceipt=true + receiptCount=0 + exportCount=0` -> guide offline payment and receipt upload.
|
||||
- Same with `exportCount>0` -> say the bank order was generated and wait for payment/receipt; do not imply money moved.
|
||||
- `reviewed + requiresBankReceipt=true + receiptCount>0` -> guide registration completion.
|
||||
- `cancelled + reviewedAt=null` -> review `exception`, payment `terminated`; `cancelled + reviewedAt!=null` -> review `completed`, payment `exception`.
|
||||
- Missing actor row or timestamp -> corresponding name/time is null; the detail response still succeeds.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: both pages import the same semantic builder, while the reimbursement route selects two payment stages and the payment route returns all three.
|
||||
- Base: a cash batch without a receipt shows `等待财务登记付款完成` and exposes the permitted registration action.
|
||||
- Bad: a route adds `if (batch.status === "reviewed")` to rewrite stage state/detail, or a client infers receipt requirements from `receiptCount===0`.
|
||||
- Bad: a cancelled batch shows a later `待处理` node, or a cash batch tells finance to upload a bank receipt.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Pure table-driven unit tests cover all five statuses, both cancellation positions, bank/non-bank channels, order count, receipt count and actorSource.
|
||||
- A structural test extracts both route assembler functions and rejects route-local payment status matrices or duplicate `付款复核` / `付款完成` label definitions.
|
||||
- Route tests assert actor name/time projection, list/detail field separation and absence of snapshot, bank ciphertext and actor IDs inside progress.
|
||||
- PC/mobile E2E uses synthetic responses for all five states, verifies `terminated`, bank/non-bank copy, one visible primary action per viewport and upload-to-register in-place switching.
|
||||
- Reimbursement E2E asserts the four-block order and that submit, print, remind, withdraw and delete retain their state/permission, reason/confirmation, request and refresh contracts after action-panel migration.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```js
|
||||
if (batch.status === "reviewed" && receiptCount === 0) {
|
||||
paymentStage.detail = "请上传银行回单";
|
||||
}
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```js
|
||||
const semantics = buildPaymentProcessingSemantics({
|
||||
status: batch.status,
|
||||
requiresBankReceipt: requiresBankReceipt(batch),
|
||||
receiptCount: batch._count?.receipt_attachments ?? 0,
|
||||
paymentOrderExportCount: batch.payment_order_export_count ?? 0,
|
||||
});
|
||||
```
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{"file":".trellis/spec/hyb-oa/approval-workflow.md","reason":"只读复核五状态、取消终止态和 maker-checker 语义未漂移"}
|
||||
{"file":".trellis/spec/hyb-oa/security-privacy.md","reason":"复核新增付款进度 DTO 不扩大银行敏感信息披露"}
|
||||
{"file":".trellis/spec/hyb-oa/project-governance.md","reason":"状态机相关变更的只读 reviewer 与交付门禁"}
|
||||
@@ -0,0 +1,109 @@
|
||||
# 详情页结构统一与付款处理时间线设计
|
||||
|
||||
## 1. 设计边界
|
||||
|
||||
本任务不合并报销 workflow 与付款批次状态机,只建立共享的只读付款阶段投影,并在两个业务视角中组装各自 DTO。数据库、付款写接口、权限和审计均保持不变。
|
||||
|
||||
前端复用现有详情工作区、时间线、固定底栏、确认弹窗和按钮组件。项目声明的 `frontend-design` skill 当前不可用,本轮不发明新的视觉体系;规划阶段已使用可用的 `ui-ux-pro-max` 检查 sticky 遮挡、异步反馈、派生状态和移动端安全区原则,最终以仓库既有成熟详情模式为实现依据。
|
||||
|
||||
## 2. 服务端共享语义层
|
||||
|
||||
新增一个无数据库依赖的付款进度服务模块,例如 `server/src/services/paymentProcessingProgress.js`。模块导出:
|
||||
|
||||
- 唯一的阶段定义:`payment_batch_created / 批次创建`、`payment_batch_review / 付款复核`、`payment_and_receipt / 付款完成`。
|
||||
- 唯一状态集合:`completed | current | pending | exception | terminated`。
|
||||
- `buildPaymentProcessingSemantics(input)`:输入批次状态、复核/执行/取消时间、取消原因、`requiresBankReceipt`、回单数和制单次数,返回三个阶段的 state、result、detail、comment、actorSource 与 occurredAt。
|
||||
|
||||
`actorSource` 只使用 `creator/reviewer/executor/canceller` 这类内部语义引用,不在共享层查询姓名,也不产生页面链接。状态矩阵:
|
||||
|
||||
| 批次事实 | 批次创建 | 付款复核 | 付款完成 |
|
||||
| --- | --- | --- | --- |
|
||||
| draft | completed | current | pending |
|
||||
| reviewed,需要回单、无回单、未制单 | completed | completed | current:等待线下付款并上传回单 |
|
||||
| reviewed,需要回单、无回单、已制单 | completed | completed | current:已生成制单,等待付款并上传回单 |
|
||||
| reviewed,需要回单、已有回单 | completed | completed | current:等待登记付款完成 |
|
||||
| reviewed,不需要回单 | completed | completed | current:等待登记付款完成 |
|
||||
| executed | completed | completed | completed |
|
||||
| failed | completed | completed | exception |
|
||||
| cancelled,`reviewedAt=null` | completed | exception(取消) | terminated |
|
||||
| cancelled,`reviewedAt!=null` | completed | completed | exception(取消) |
|
||||
|
||||
取消节点使用取消人、取消时间与原因;失败节点使用最后执行人和执行时间。语义函数不猜测缺失人员,时间戳缺失时保持 null。
|
||||
|
||||
`requiresBankReceipt` 必须复用付款执行门禁的渠道判断:只要仍待处理/失败的批次项中存在有效付款渠道为 `bank` 的项目即为 true。路由不得为时间线再发明一套渠道判断;最小实现是提取并共享现有 `requiresBankReceipt` 计算函数。只有该值为 true 时,制单次数才参与阶段文案。
|
||||
|
||||
## 3. 两个视图组装层
|
||||
|
||||
### 3.1 报销详情
|
||||
|
||||
`buildProcessingProgress` 继续组装提交与真实 workflow task。付款部分调用共享语义函数并只选择 `payment_batch_review`、`payment_and_receipt`:
|
||||
|
||||
- 通过已有 `paymentActorNames` 把 actorSource 对应 ID 解析为姓名。
|
||||
- 按现有权限决定 `targetHref`。
|
||||
- 无付款批次时保留“待财务安排付款”的报销专属投影。
|
||||
- 历史 `paid` 且无批次时继续用报销 `paid_by/paid_at` 完成最后阶段。
|
||||
|
||||
报销组装层不得重新按 batch status 写 switch/if;批次存在时的 state、result 和基础 detail 一律来自共享语义。
|
||||
|
||||
### 3.2 付款批次详情
|
||||
|
||||
付款批次详情 DTO 新增 `processingProgress.stages[]`,使用共享语义的三个阶段:
|
||||
|
||||
- `mapBatch` 列表响应保持轻量,不额外查姓名。
|
||||
- `mapBatchForResponse` 仅为详情及写操作返回结果收集 created/reviewed/executed/cancelled actor ID,以一次 `employee.findMany` 解析姓名,然后组装 progress。
|
||||
- API 类型拆成列表基础类型与带必需 `processingProgress` 的详情类型,避免把详情字段伪装成所有列表项都存在。
|
||||
- progress 只含姓名和时间,不增加员工号、角色、账号、快照或相邻批次信息。
|
||||
|
||||
服务端结构测试直接导入共享阶段定义/构建器,并验证两个路由没有各自状态矩阵,防止未来再次分叉。
|
||||
|
||||
## 4. 共享时间线组件
|
||||
|
||||
将 `ReimbursementProcessingProgress` 改名并移动到共享 patterns/common 目录,例如 `ProcessingProgress.tsx`。保持单个 `stages.map`:
|
||||
|
||||
- 组件自带通用 `ProcessingStage` / `ProcessingProgress` 类型,报销与付款 API 类型复用或结构兼容。
|
||||
- props 参数化 `ariaLabel`、`testId`、`mobile` 与目标链接文案;报销仍显示“查看所在付款批次”,付款批次本身不生成自指链接。
|
||||
- 新增 terminated 的中性图标、灰色连接/节点与“已终止”,不使用红色异常或绿色完成视觉。
|
||||
- current/exception/comment 继续展开 detail;pending/terminated 不显示会误导为下一步的说明。
|
||||
|
||||
## 5. 页面结构
|
||||
|
||||
### 5.1 报销 PC
|
||||
|
||||
- hero 仅保留标题和状态;现有 primary/secondary business actions 迁入右侧 `BusinessDetailActionPanel`。
|
||||
- `BusinessDetailMain` 顺序为概况、处理进度、明细、材料。
|
||||
- `BusinessDetailAside` 承载一个操作面板;提交、打印、催办、撤回、删除等继续使用现有权限、mutation 和确认逻辑。
|
||||
- 删除 `ReimbursementActions` 的独立卡片实现及三个进度锚点;不复制动作。
|
||||
|
||||
### 5.2 报销移动端
|
||||
|
||||
只移动现有处理进度 section 到概况后;明细、材料随后,底部操作 section 与现有固定提交栏保持末尾/safe-area 合同。
|
||||
|
||||
### 5.3 付款批次响应式详情
|
||||
|
||||
- `BusinessDetailMain` 为概况、处理进度、明细、回单;旧 `payment-batch-current-processing` 事实卡删除。
|
||||
- `BusinessDetailAside` 在 `lg+` 显示 `BusinessDetailActionPanel`。
|
||||
- 同一 `paymentActionModel` 从权限、批次状态、制单次数、回单查询和 mutation 状态派生唯一 primary、secondary、more action;PC 面板和移动端只负责渲染。
|
||||
- `<lg` 使用现有 `mobile-sticky-action-surface`:一个 primary,其他动作进入“更多”。有固定栏时给页面增加安全底部 padding;无可执行动作时不渲染空栏。
|
||||
- 上传回单后通过既有 query 刷新让 action model 从“上传银行回单”切到“登记付款完成”。持续可见操作区就是就近入口;回单 section 不再额外复制一个同名按钮。
|
||||
|
||||
## 6. 共享断点
|
||||
|
||||
把 `detail-workspace-grid` 的双栏断点与 `BusinessDetailActionPanel` sticky 同步从 `xl` 降到 `lg`;同步清理 `WorkflowTaskDetailPage` 的 `xl:top-*` 覆盖,避免同一组件存在冲突断点。
|
||||
|
||||
回归 `AssetRegistryPage` 与 `WorkflowTaskDetailPage`:右栏最小宽度、焦点菜单 z-index、sticky top offset 和页面滚动均不得回退。sticky 元素不设置超过视口的固定高度,不能遮挡主内容或底部操作。
|
||||
|
||||
## 7. 测试与验收数据
|
||||
|
||||
- 纯函数表驱动测试锁定五状态、取消时间戳分支、需要/不需要回单、制单/回单文案和 actorSource。
|
||||
- 报销路由保留既有动态 workflow task 测试并将五种 batch 状态期望改为共享语义。
|
||||
- 付款批次详情路由测试断言三阶段、actor name/time、无敏感字段;列表不额外依赖 progress。
|
||||
- Playwright 通过 synthetic API fixtures 覆盖五状态,不写生产数据;断言每个 viewport 只有一个可见主操作而非全 DOM 只有一个按钮。
|
||||
- 报销动作 E2E 逐项覆盖:draft 提交与删除、reviewing 催办与撤回、paid 打印,并核对权限隐藏、原因/确认交互、mutation 请求及刷新后的状态;操作区迁移不能降低既有写操作证据强度。
|
||||
- 生产验收只观察真实存在的 draft/reviewed;后三态无真实数据是已知限制,不阻塞交付。
|
||||
|
||||
## 8. 兼容、发布与回滚
|
||||
|
||||
- API 是加字段的向后兼容变化,无迁移;旧前端忽略 progress,新前端部署必须与新增 DTO 同批发布。
|
||||
- 回滚只需恢复旧路由投影与页面布局,付款写状态和数据不受影响。
|
||||
- 面向用户测试仍需单独批准部署,跑标准聚合体检、公网构建标识/ready 检查后才通知。
|
||||
- 下一笔制单是否进入网银由“存在明确仅校验步骤”决定;无该步骤时只执行离线验证和人工付款。
|
||||
@@ -0,0 +1,3 @@
|
||||
{"file":".trellis/spec/hyb-oa/backend-fastify-prisma.md","reason":"服务端只读 DTO、路由和聚焦验证合同"}
|
||||
{"file":".trellis/spec/hyb-oa/approval-workflow.md","reason":"报销端到端处理投影、付款复核与状态机边界"}
|
||||
{"file":".trellis/spec/hyb-oa/security-privacy.md","reason":"付款详情 DTO 与银行资料最小披露边界"}
|
||||
@@ -0,0 +1,74 @@
|
||||
# 详情页结构统一与付款处理时间线实施计划
|
||||
|
||||
## 1. 开发前
|
||||
|
||||
- [x] 用户审查并明确批准本 PRD、设计和实施清单后,运行 `task.py start`;批准前不修改产品代码。
|
||||
- [x] 使用 `trellis-before-dev` 读取 backend、frontend、hyb-oa 相关规约与当前任务合同。
|
||||
- [x] 记录基线:聚焦报销/付款路由测试、前端 typecheck/build 和相关 Playwright 当前结果。
|
||||
|
||||
## 2. 服务端语义与 DTO
|
||||
|
||||
- [x] 先提取与执行门禁同源的 `requiresBankReceipt` 渠道判断,再新增共享付款阶段语义模块及表驱动单元测试,覆盖五状态、取消前后复核、需要/不需要回单、制单/回单分支和 actorSource。
|
||||
- [x] 报销 `buildProcessingProgress` 改为消费共享语义,保留无批次、权限链接和历史 paid 兼容;更新既有详情路由测试。
|
||||
- [x] 付款批次详情组装 actor names 与三阶段 `processingProgress`;列表映射保持轻量,新增隐私负向断言。
|
||||
- [x] 更新客户端付款详情 API 类型,明确列表/详情字段边界。
|
||||
|
||||
## 3. 共享前端组件
|
||||
|
||||
- [x] 将报销专用进度组件收敛为共享组件,参数化无障碍名称、testid、目标链接文案并增加 terminated 状态。
|
||||
- [x] 更新 PC/移动报销调用方与相关 fixture,保持动态阶段数量和链接权限行为。
|
||||
- [x] 将详情工作区双栏、操作面板 sticky 及页面覆盖断点统一为 `lg`,先回归资产与审批任务详情。
|
||||
|
||||
## 4. 报销详情
|
||||
|
||||
- [x] PC 迁移到标准 Main/Aside 操作区,主内容按概况、处理进度、明细、材料排列;移除 hero 动作重复、旧手写动作卡和三个进度锚点。
|
||||
- [x] 移动端把处理进度移到概况之后,保持操作 section 在底部和现有 safe-area 固定提交动作。
|
||||
- [x] 补 PC/移动四段顺序、锚点删除和无重复主操作回归;逐项覆盖提交、打印、催办、撤回、删除的权限/状态可见性、原因/确认、请求与刷新结果。
|
||||
|
||||
## 5. 付款批次详情
|
||||
|
||||
- [x] 建立单一派生 `paymentActionModel`,沿用现有权限、原因、确认、loading 和 mutation handler。
|
||||
- [x] 主内容改为概况、共享三阶段时间线、明细、回单,删除“当前处理”事实卡及页面内状态文案矩阵。
|
||||
- [x] `lg+` 使用标准粘性操作面板;移动端使用 safe-area 固定底栏,一个 primary 加“更多”。
|
||||
- [x] 验证上传回单成功后原地切换为“登记付款完成”,没有第二个同名主按钮。
|
||||
- [x] 更新既有付款 E2E locator,使其按当前 viewport/操作区作用域断言;合成覆盖全部五状态和需要/不需要回单渠道,非银行批次不得出现回单/制单引导。
|
||||
|
||||
## 6. 文档与稳定规约
|
||||
|
||||
- [x] 确认管理员手册已区分“制单离线验证”和“使用制单付款”,无安全仅校验环节时仍人工付款。
|
||||
- [x] 将共享付款进度的稳定状态/终止态合同更新到 `.trellis/spec/hyb-oa/approval-workflow.md`;不把页面实现细节复制到业务文档。
|
||||
- [x] 如未发现新的稳定通用规则,不新建额外文档。
|
||||
|
||||
## 7. 验证与只读审查
|
||||
|
||||
- [x] `cd server && node --check src/services/paymentProcessingProgress.js && node --check src/routes/reimbursements.js && node --check src/routes/paymentBatches.js`
|
||||
- [x] 运行新增纯函数测试、`reimbursements.detail.test.js` 和付款批次聚焦路由测试。
|
||||
- [x] `cd server && npm run prisma:validate`
|
||||
- [x] `cd client && npm run typecheck && npm run build`
|
||||
- [x] 运行相关 Playwright:报销 PC/移动详情、付款批次五状态/动作确认、资产与审批任务详情 `lg` 回归。
|
||||
- [x] 因涉及付款状态投影,启动只读 reviewer 审查状态语义、权限/隐私、双视角 DTO 和 PC/移动动作一致性;reviewer 不修改代码。
|
||||
- [x] 修正 findings 后重跑受影响检查,再执行 `bash scripts/check-minimal.sh`(若耗时门禁适用)。
|
||||
- [x] `node scripts/qa/check-process-contract.mjs --baseline --json`
|
||||
- [x] `node scripts/qa/audit-docs.mjs --check-registry`
|
||||
- [x] `node scripts/qa/check-trellis-governance.mjs`
|
||||
- [x] `git diff --check`
|
||||
|
||||
## 8. 提交、部署与验收
|
||||
|
||||
- [x] 质量检查通过后按 Trellis finish 流程更新必要 spec/docs,使用中文 commit message 并引用 `detail-page-structure-progress-actions`。
|
||||
- [x] 未经单独批准不部署;批准后走标准部署聚合体检、公网 ready/build 检查。
|
||||
- [x] 公网通过后只通知用户验收真实可见状态;记录生产缺少 executed/failed/cancelled 的限制,后续真实 executed 仅作补充观察。
|
||||
|
||||
## 验证记录(2026-08-03)
|
||||
|
||||
- `bash scripts/check-minimal.sh` 在固定 BIFF8 Python 依赖环境下通过:服务端 177 个测试文件、1213 个用例全部通过,Prisma、前端 typecheck/build 与其余聚合步骤通过。
|
||||
- 聚焦服务端共享语义、报销详情、付款详情与制单回归通过;普通付款进度 DTO 无账号、密文、原始快照或 actor ID。
|
||||
- 聚焦 Playwright 覆盖报销动作、付款五状态、银行/非银行渠道、PC/移动唯一主操作、上传后原地切换和 `lg` sticky 合同。审查 finding 修复后,制单可用且未导出时仍以“上传银行回单”为主操作,首次制单进入“更多”。
|
||||
- 只读 reviewer 首轮发现“制单被误设为强制主路径”的 High finding;修复及 PC/移动回归后复核 `PASS`,reviewer 未修改代码。
|
||||
- 文档审计 `errors=0`,保留仓库既有的 22 个未注册文档 warning;Trellis、流程、敏感内容与 `git diff --check` 门禁通过。
|
||||
|
||||
## 回滚点
|
||||
|
||||
- 服务端共享投影与前端 DTO/UI 同一提交批次回滚,避免新前端依赖旧 DTO。
|
||||
- 若共享 `lg` 断点导致现有资产/审批详情无法接受,先修正共享列宽和 top offset;不得用页面私有断点重新制造第二事实源。
|
||||
- 本任务无迁移、无生产数据回填、无付款状态写入,代码回滚不需要数据库操作。
|
||||
@@ -0,0 +1,111 @@
|
||||
# 详情页结构统一与付款处理时间线
|
||||
|
||||
## Goal
|
||||
|
||||
让员工、审批人和财务在报销详情与付款批次详情中按同一认知顺序查看“当前到哪、谁处理、下一步做什么”,并让高频主操作在 PC 和移动端持续可达,不再因页面不同而重新理解同一付款事实或来回滚动。
|
||||
|
||||
## Background
|
||||
|
||||
- 报销详情 PC 当前顺序为“概况 → 明细 → 材料 → 处理进度”,移动端同样要滚过不定长材料后才能看到进度;PC 还有三个用于跳转到底部进度的入口,其中 `#reimbursement-workflow-progress-panel` 没有目标元素,另两个入口在进度前移后也不再有价值。
|
||||
- 报销详情把付款批次状态投影为时间线,付款批次详情却在“当前处理”事实卡中独立维护另一套状态、责任与下一步文案。同一付款事实已有两种表达和两条判定路径。
|
||||
- 报销进度从单笔 `paymentBatchItem` 视角说明“这一笔在批次中的位置”;付款批次详情从整个 `paymentBatch` 视角说明“整批走到哪”。两者不能共用一个大 DTO 构建函数,但付款阶段标签和状态判定必须同源。
|
||||
- PC 报销详情使用顶部 hero 动作加底部手写“可执行动作”卡;付款批次详情把动作放在顶部摘要卡。项目已有 `BusinessDetailActionPanel`,但其工作区和 sticky 均只在 `xl` 生效。移动端已有 safe-area 固定底部操作模式。
|
||||
- 当前生产没有真实 `executed` 付款批次;这不应阻塞任务完成,五种状态由合成数据自动化覆盖,生产只验收届时真实存在的状态。
|
||||
|
||||
## Scope
|
||||
|
||||
- 调整报销详情 PC/移动端与付款批次响应式详情的信息顺序和操作区,但不扩展到其他业务详情页重构。
|
||||
- 新增共享的只读付款阶段语义和付款批次三阶段 DTO,报销与付款分别保留自己的视图组装层。
|
||||
- 收敛通用时间线组件、详情工作区 `lg` 断点及 PC/移动动作派生,回归既有共享组件消费者。
|
||||
- 更新合成自动化、稳定工程规约和下一笔制单的安全操作说明;不执行部署、生产配置、网银导入或真实付款。
|
||||
|
||||
## Requirements
|
||||
|
||||
### R1 详情信息顺序
|
||||
|
||||
- 报销详情 PC 和移动端均调整为“概况 → 处理进度 → 报销明细 → 报销材料”;移动端底部“操作”段仍留在业务内容之后。
|
||||
- 删除 PC 的三个进度锚点动作,包括一个死链和两个指向现有处理进度面板的自指入口;返回、打印、催办、提交、撤回等真实动作保持可达。
|
||||
- 付款批次详情按“批次概况 → 处理进度 → 报销明细 → 银行回单”组织主内容。
|
||||
|
||||
### R2 付款处理语义单一事实源
|
||||
|
||||
- 建立共享付款阶段语义层,唯一维护阶段 key、标签及 `completed/current/pending/exception/terminated` 判定;“付款复核”“付款完成”及其状态条件不得在报销路由和付款批次路由各写一套。
|
||||
- 共享语义层按批次状态和时间戳判断阶段;两个调用方仅负责各自视角的 DTO 组装、责任人姓名解析、权限链接和报销历史兼容信息。
|
||||
- 报销视角继续保留提交、真实审批任务和两个付款阶段;付款批次视角展示“批次创建 → 付款复核 → 付款完成”三阶段。
|
||||
- `draft`、`reviewed`、`executed`、`failed`、`cancelled` 五种付款批次状态必须有明确投影。`failed` 的付款阶段为 `exception`;`cancelled` 根据是否已有复核时间终止在复核或付款阶段,后续阶段为 `terminated`,不得显示仍待处理。
|
||||
- 共享语义层必须接收与执行门禁同源的 `requiresBankReceipt`,不能仅凭回单数判断下一步。`reviewed` 且不需要回单时直接显示等待登记付款完成;需要回单且尚未上传时才按制单次数区分:未导出显示“等待财务线下付款并上传回单”,已导出显示“已生成银行制单,等待付款完成并上传回单”;需要回单且已有回单时显示等待登记付款完成。
|
||||
- 制单中间态只适用于需要银行回单的渠道;现金等不需要回单的批次不得出现上传银行回单或已生成银行制单的下一步文案。
|
||||
- 付款批次处理进度显示已有的真实创建人、复核人、执行人或取消人及时间;不得猜测未来责任人。
|
||||
|
||||
### R3 共享时间线表现
|
||||
|
||||
- 将现有 `ReimbursementProcessingProgress` 收敛为共享进度组件;保留当前数据驱动渲染,不重做成带大量配置项的新组件。
|
||||
- 共享组件使用通用阶段类型,并参数化 `aria-label`、测试标识和目标链接文案;PC 与移动端继续使用相同渲染逻辑。
|
||||
- `terminated` 使用中性终止视觉和“已终止”状态,不表现为错误、完成或待处理;`exception` 继续用于失败和发生取消动作的终止节点。
|
||||
|
||||
### R4 响应式操作区
|
||||
|
||||
- PC 报销与付款批次详情收敛到 `BusinessDetailWorkspace/Main/Aside + BusinessDetailActionPanel`;hero/概况卡不再保留第二套业务主操作。
|
||||
- 详情工作区双栏和操作面板 sticky 从 `xl` 调整到 `lg`,并回归现有 `AssetRegistryPage` 与 `WorkflowTaskDetailPage` 消费方,确保笔记本宽度可见且不遮挡内容。
|
||||
- 付款批次的 PC 粘性面板与移动端固定底栏必须消费同一份动作可见性/主次级模型,不能各自重复判断状态和权限。
|
||||
- 移动端只在固定底栏展示一个当前主操作;取消、重新下载等次要或破坏性动作进入“更多”并保留既有原因输入、风险提示和二次确认。
|
||||
- 上传银行回单成功后,当前主操作在原可视区域切换为“登记付款完成”,用户无需滚回页面顶部。不得通过同时渲染两个同名主按钮来实现就近入口。
|
||||
- 所有异步动作在执行中保持禁用和加载反馈;高风险付款、复核、取消及重新下载制单的既有确认合同不放宽。
|
||||
|
||||
### R5 兼容与边界
|
||||
|
||||
- 本任务只增加只读处理进度投影和调整页面布局/动作呈现,不改变付款批次写状态机、权限、maker-checker、回单门禁、快照、加密或审计合同。
|
||||
- 不新增数据库字段或迁移;服务端普通响应不得新增完整账号、密文、原始快照或批次相邻敏感数据。
|
||||
- 历史已付款但无付款批次的报销继续可读;无批次、无工作流、无回单或责任人记录缺失时,只降级对应阶段,不使整个详情失败。
|
||||
|
||||
### R6 下一笔制单安全说明
|
||||
|
||||
- 等下一张报销自然形成新快照批次,不取消重建杨俊当前已复核的旧批次。
|
||||
- 下一笔新批次的“验证制单”和“使用制单付款”是两步:若建设银行网银没有明确的“仅校验、不提交”环节,只做导出、Excel 打开和固定版本 `xlrd` 读回的离线验证,实际付款仍走人工;不得因文件生成成功直接导入提交。
|
||||
|
||||
## Test Plan
|
||||
|
||||
- 服务端纯语义单元测试用合成数据覆盖 `draft/reviewed/executed/failed/cancelled`,以及取消前后是否已有复核时间、需要/不需要回单、未制单/已制单/已有回单分支。
|
||||
- 扩展报销详情路由测试,证明其付款阶段与共享语义一致、无批次和历史已付款兼容不回退;扩展付款批次详情测试,证明三阶段 DTO、真实 actor name/time 和普通 DTO 隐私边界。
|
||||
- 前端类型检查与构建;共享时间线覆盖五种状态与 `terminated` 表现。
|
||||
- Playwright 使用合成响应覆盖付款批次五种状态、需要/不需要回单、PC/移动端动作唯一性、上传回单后主操作切换、报销 PC/移动端四段顺序、三个旧锚点消失,以及 `lg` sticky 相关消费者回归。
|
||||
- 报销动作迁移必须分别保留提交、打印、催办、撤回、删除的权限/状态可见性、确认或原因交互、成功 mutation 与刷新结果断言;不能只检查操作面板里出现了按钮。
|
||||
- 实施后按项目约束启动只读 reviewer,重点审查状态机投影、权限/隐私、PC/移动动作一致性,不允许 reviewer 修改代码。
|
||||
- 运行 Trellis、流程、文档、敏感内容和 `git diff --check` 门禁;用户可测试前仍须另行批准部署并通过公网检查。
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [x] 报销 PC 与移动端均按“概况 → 处理进度 → 明细 → 材料”展示,PC 三个旧进度锚点全部消失,移动端操作仍在底部。
|
||||
- [x] 付款批次详情用三阶段时间线替换“当前处理”事实卡,标题统一为“处理进度”,并显示真实已有责任人和时间。
|
||||
- [x] 两个服务端调用方共同使用唯一付款阶段语义层;阶段标签和五状态判定不存在第二份实现,结构测试能阻止重新分叉。
|
||||
- [x] `draft/reviewed/executed/failed/cancelled` 均由合成测试覆盖;失败显示 exception,取消在正确节点结束且后续显示 terminated,不再挂待处理。
|
||||
- [x] reviewed 需要回单时的未制单、已制单、已有回单三种文案与既定口径一致;不需要回单时直接等待登记完成且不出现银行回单/制单引导。
|
||||
- [x] 共享时间线同时服务报销 PC、报销移动端和付款批次,保留无障碍名称、稳定 testid、目标链接及中止态视觉。
|
||||
- [x] PC 报销与付款批次详情使用标准右侧操作面板,`lg` 笔记本宽度可粘性跟随;资产与审批任务详情无布局回退。
|
||||
- [x] 付款批次移动端使用 safe-area 固定底栏,PC/移动动作来自同一模型;每个视口只有一个当前主操作。
|
||||
- [x] 上传回单成功后无需滚动即可点击“登记付款完成”,且继续使用现有二次确认和回单硬门禁。
|
||||
- [x] 报销提交、打印、催办、撤回、删除迁移后各自的权限/状态可见性、确认或原因交互、成功刷新合同均有 E2E 回归,尤其锁定仅 reviewing 可撤回、仅 draft 可删除。
|
||||
- [x] 无数据库迁移、权限扩大或付款写状态机变化,普通响应不泄露银行敏感字段。
|
||||
- [x] 管理员手册明确下一笔制单仅在网银有“仅校验、不提交”环节时才进入网银,否则只做离线验证并人工付款。
|
||||
- [x] 自动化验收覆盖全部五状态;生产验收只覆盖当时已有真实状态(预计 draft/reviewed),缺少 executed/failed/cancelled 真实数据不阻塞任务完成,后续真实 executed 仅作补充验收。
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 取消或重建杨俊当前付款批次、执行真实付款、上传真实回单或写入任何生产银行数据。
|
||||
- 等待下一笔真实付款完成后再结束本任务,或把生产 `executed` 数据设为本任务验收门槛。
|
||||
- 企业网银导入、提交、放款、银行 API 直连或跨行制单能力。
|
||||
- 修改付款状态转换、maker-checker、回单要求、银行账户/快照模型、制单格式或导出权限。
|
||||
- 统一所有业务详情页、列表页、编辑页或重新设计视觉体系。
|
||||
- 新建数据库迁移、补写历史付款快照或为测试制造生产业务数据。
|
||||
|
||||
## Risks And Deferred Items
|
||||
|
||||
- `detail-workspace-grid` 与 `BusinessDetailActionPanel` 的断点是共享合同,调整时必须回归资产和审批任务详情;若 `lg` 宽度不足,应通过列宽/间距收敛解决,不退回页面私有 sticky。
|
||||
- 当前生产缺少后三种真实状态,自动化是本任务的完成证据;真实 `executed` 批次出现后可追加一次生产观察,但不重新打开本任务。
|
||||
- 建设银行网银是否存在安全的仅校验步骤仍未知;这只决定后续是否做网银格式确认,不改变本任务产品行为。
|
||||
|
||||
## Notes
|
||||
|
||||
- Keep `prd.md` focused on requirements, constraints, and acceptance criteria.
|
||||
- Lightweight tasks can remain PRD-only.
|
||||
- For complex tasks, add `design.md` for technical design and `implement.md` for execution planning before `task.py start`.
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "detail-page-structure-progress-actions",
|
||||
"name": "detail-page-structure-progress-actions",
|
||||
"title": "详情页结构统一与付款处理时间线",
|
||||
"description": "统一报销与付款批次详情页的信息顺序、处理进度表达和响应式操作区,并以共享付款阶段语义消除跨页面状态漂移。",
|
||||
"status": "in_progress",
|
||||
"dev_type": "fullstack",
|
||||
"scope": "报销详情 PC/移动端结构、付款批次三阶段进度 DTO、共享时间线组件、PC/移动端操作区与相关测试文档",
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "shunli",
|
||||
"assignee": "shunli",
|
||||
"createdAt": "2026-08-03",
|
||||
"completedAt": null,
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [],
|
||||
"notes": "已完成共享付款进度语义、报销与付款详情结构、PC/移动操作区收敛及合成五状态回归;只读审查 finding 已修复并复核通过。未部署,未执行生产写入、网银导入或真实付款。",
|
||||
"meta": {}
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户