From 513d3b0fb39d7085ad8496d6c6a7f425cb17a4c5 Mon Sep 17 00:00:00 2001 From: zlwu Date: Thu, 3 Sep 2026 16:16:13 +0800 Subject: [PATCH] docs: add plan-archive price permission design Document button-level archive/price controls on the existing transport plan archive page instead of a separate view module. Co-authored-by: Cursor --- ...pl-plan-archive-price-permission-design.md | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 docs/superpowers/specs/2026-09-03-pl-plan-archive-price-permission-design.md diff --git a/docs/superpowers/specs/2026-09-03-pl-plan-archive-price-permission-design.md b/docs/superpowers/specs/2026-09-03-pl-plan-archive-price-permission-design.md new file mode 100644 index 000000000..a1e163537 --- /dev/null +++ b/docs/superpowers/specs/2026-09-03-pl-plan-archive-price-permission-design.md @@ -0,0 +1,175 @@ +# 运输计划归档:只读可见 + 隐藏单价金额 设计 + +日期:2026-09-03 +范围:`web-admin` 【运输计划归档】页及相关查看弹窗/导出;`backend` 计划归档写接口与读/导出脱敏;`sys_menu` 按钮权限 +状态:已评审(待用户确认本文档后实现) + +## 1. 背景与目标 + +客户希望部分角色可以进入【运输计划归档】界面查看进度与数量信息,但: + +1. **不能**执行【归档】/【调整】操作; +2. **不能**看到单价、金额相关数据(含运费单价/运费金额)。 + +### 已否决方案 + +- **新增独立菜单「运输计划归档查看」**:两套页面/路由/角色配置,后续维护成本高。 + +### 采用方案 + +- **在当前界面做权限处理**:复用 `pl:plan-archive:list`,用按钮权限拆分「归档操作」与「价格可见」。 + +## 2. 已确认决策 + +| 项 | 决策 | +|---|---| +| 实现路径 | 当前页权限控制,不新建模块 | +| 归档操作权限 | 复用已有 `pl:plan-archive:archive`(菜单已有,前端尚未接线) | +| 价格可见权限 | **新建** `pl:plan-archive:price` | +| 价格范围 | 产品单价/金额 **与** 运费单价/运费金额 **一并** 受 `price` 控制 | +| 导出 | 无 `price` 时去掉价相关列(不仅清空单元格) | +| ERP 勾选 | **本期不改**(只读角色若已有 list 仍可操作 ERP;若需再拆权限后续单开) | +| `edit` 按钮权限 | **本期不强制接线**(无 `archive` 即无法进入归档填写) | +| `super_admin` | 视为拥有全部相关权限 | +| 安全边界 | 前端隐藏 + 后端脱敏/写接口 403,避免仅藏 UI | + +## 3. 权限模型 + +| perms | menu_type | 作用 | 现状 | +|---|---|---|---| +| `pl:plan-archive:list` | C(页面) | 进入归档页、看列表 | 已有 | +| `pl:plan-archive:query` | F | 查询(可与 list 一并授权) | 已有 | +| `pl:plan-archive:edit` | F | 编辑(本期不强制 UI 接线) | 已有 | +| `pl:plan-archive:archive` | F | 归档/调整入口与提交 | 菜单已有,需接线 | +| `pl:plan-archive:price` | F | 查看单价/金额(含运费价) | **新建** | + +### 角色配置示例 + +| 角色意图 | 勾选 | +|---|---| +| 只读业务(看进度、不见价、不能归档) | `list`(+`query`) | +| 归档员 | `list` + `archive` + `price` | +| 财务看价不归档 | `list` + `price` | + +历史已授权「运输计划归档」整页的角色:上线后需在角色管理中 **显式补勾** `archive` / `price`(否则会变成「能进页但不能归档且不见价」)。实现阶段应在变更说明/SQL 备注中写清迁移建议(例如:对原拥有 `PL_PLAN_ARCHIVE` 页面权限的角色默认补上 `archive`+`price`,避免现网行为回退)。 + +## 4. 前端行为 + +入口页:`web-admin/src/views/pl/plan-archive/index.vue` +权限读取:与现网一致,使用登录态 `menuCodes`(参考 `pl:plan:force-follow-status`)。 + +### 4.1 无 `pl:plan-archive:archive` + +- 列表工具栏「归档 / 调整」按钮隐藏; +- 查看弹窗 hero「归档 / 调整」按钮隐藏; +- 不打开 `PlPlanArchiveDialog`(无入口即可;若有深链/误调也应被权限挡住)。 + +### 4.2 无 `pl:plan-archive:price` + +| 位置 | 处理 | +|---|---| +| 列表「单价(元)」「金额(元)」列 | 不渲染;列设置中移除对应项 | +| 列表底部统计行 | 金额相关合计不展示 | +| 查看弹窗段次产品 / IO 字段 | 关闭价金额展示;**数量仍可见** | +| 查看弹窗「品牌归档明细」 | 隐藏单价、金额列 | +| 查看弹窗运费区 | 隐藏「运输单价」「运费金额」;保留是否有运费、公里数、计算方式等非价字段 | +| 归档专用导出 | 去掉单价、金额、运费单价、运费金额列 | +| 合同详情 | 保持现有 `hide-product-price` | + +### 4.3 仍可见(只读角色) + +计划编号/日期、单据类型、段次客户与地址、产品与型号、计划/实际数量、入出库数量、归档状态、跟进状态、车牌司机、ERP、备注等非价格字段。 + +### 4.4 实现备注(组件传参) + +- `PlPlanViewDialog` / `PlPlanViewTabs`:`show-archive-io-fields` 需拆成「数量」与「价格」可控,或增加 `showArchivePriceFields`(无 `price` 时仅数量、无价)。 +- 列表列定义与 `usePersistedListColumns`:无权限时从可见列集合中剔除 `productUnitPrice` / `productAmount`,避免本地缓存仍勾出空列。 + +## 5. 后端行为 + +权限校验模式对齐 `FORCE_FOLLOW_STATUS_PERM`:`super_admin` 放行;否则 `get_user_menu_codes` 判断。 + +### 5.1 写接口(无 `archive` → 403) + +- `POST /api/.../transport/plan/{id}/archive` +- `POST /api/.../transport/plan/{id}/archive-draft` + +文案建议:`无运输计划归档操作权限`。 + +### 5.2 读接口脱敏(无 `price` → 价字段置 `null`) + +归档页使用的计划列表、详情(含 stops / products / brandQtys / transport 运费字段)在序列化前脱敏。 + +**脱敏字段(建议清单)** + +- 产品/段次:`inboundPrice`、`outboundPrice`、`inboundAmount`、`outboundAmount` +- 品牌行:`unitPrice`(及若存在的金额派生字段) +- 计划/运输:`freightPrice`、`freightAmount` +- 列表汇总若暴露:`totalAmount` + +**不脱敏**:各类数量(`qty` / `inboundQty` / `outboundQty` 等)、状态、客户、车牌等。 + +### 5.3 导出(`exportFormat=archive`) + +无 `price` 时,从 `PLAN_ARCHIVE_EXPORT_COLUMNS` 中 **移除** 列: + +- `unitPrice`(单价) +- `amount`(金额) +- `freightPrice`(运费单价) +- `freightAmount`(运费金额) + +运费单位(`freightType`)可保留。 + +## 6. 数据与菜单变更 + +1. 在 `docs/sql/` 增加 `sys_menu` 插入脚本: + - `id`:如 `PL_PLAN_ARCHIVE_PRICE` + - `parent_id`:`PL_PLAN_ARCHIVE` + - `menu_type`:`F` + - `perms`:`pl:plan-archive:price` + - `menu_name`:建议「查看单价金额」 +2. 同步更新全量快照或增量迁移说明(与现网菜单规范一致:`docs/sql` + 角色授权)。 +3. **迁移建议(推荐默认)**:对已拥有 `PL_PLAN_ARCHIVE`(或 `pl:plan-archive:list`)的角色,批量补授权 `PL_PLAN_ARCHIVE_A`(archive)与新建的 price 按钮,保持上线前行为不变;新「只读」角色再单独去掉这两项。 + +## 7. 验收场景 + +| # | 角色权限 | 期望 | +|---|---|---| +| A | 仅 `list` | 能进页;无归档按钮;列表/查看/导出均无单价金额;直接调 archive 接口 403 | +| B | `list` + `archive`,无 `price` | 能归档;归档填写中不应依赖「先看价」——若弹窗内价为录入项,无 `price` 时仍应允许录入但 **打开前详情不回显他人已填价**(见下方边界);列表/查看/导出无价 | +| C | `list` + `price`,无 `archive` | 能看价;无归档按钮;写接口 403 | +| D | `list` + `archive` + `price` | 与现网完整能力一致 | +| E | `super_admin` | 与 D 相同 | + +### 边界说明(场景 B) + +「无 price 但有 archive」在业务上少见。约定: + +- **读路径**一律脱敏(列表/详情打开时不见价); +- **归档弹窗提交**仍可填写单价并写入(写权限由 `archive` 覆盖); +- 若产品确认「能归档就必须能看价」,可在角色配置上强制 `archive` 依赖勾选 `price`(UI 提示即可,后端可不强绑)。 + +**推荐产品约定**:归档员角色同时勾选 `archive` + `price`;不单独发放「无价可归档」。 + +## 8. 非目标(本期不做) + +- 新建「运输计划归档查看」菜单/路由/页面副本; +- 拆分 ERP 勾选权限; +- 运输计划主列表、运费结算、库存台账等其他模块的价格权限(仅本归档页链路); +- 字段级加密或审计日志增强。 + +## 9. 主要改动面(实现索引) + +| 层 | 路径(示意) | +|---|---| +| 菜单 SQL | `docs/sql/` 增量 + `sys_menu` | +| 列表页 | `web-admin/src/views/pl/plan-archive/index.vue` | +| 查看弹窗/Tabs | `pl-plan-view-dialog`、`pl-plan-view-tabs`、`pl-plan-stop-product-table`、`pl-plan-archive-brand-view-block` | +| 归档写 API | `backend/app/api/pl/plan.py`(`archive` / `archive-draft`) | +| 读脱敏 / 导出 | `plan.py` 列表/详情组装 + `PLAN_ARCHIVE_EXPORT_COLUMNS` / `build_plan_archive_export_rows` | + +## 10. 风险与注意 + +- **角色回退**:若不做「补授权」迁移,现网归档员会突然不能归档且不见价。 +- **列宽缓存**:本地 `pl-plan-archive-list-columns-v*` 可能仍记住价列;无权限时须强制剔除。 +- **脱敏遗漏**:详情嵌套 stops/products/brandQtys/transport 多处含价,需统一在序列化出口处理,避免漏网。