ソースを参照

docs: add miniprogram ETC vehicle recharge apply design.

Captures approved scope for driver/escort mine-vehicles filtering, menu perms, and reuse of existing apply APIs.

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 1 ヶ月 前
親
コミット
3d7d999f48

+ 277 - 0
docs/superpowers/specs/2026-09-27-mini-pl-vehicle-recharge-apply-design.md

@@ -0,0 +1,277 @@
+# 小程序 · ETC加油充值申请 — 设计文档
+
+> **日期**: 2026-09-27  
+> **状态**: 已批准(待实现)  
+> **前置**:  
+> - Web 申请/审批/发放:`docs/superpowers/specs/2026-06-29-pl-vehicle-recharge-design.md`  
+> - 审批工作流:`docs/superpowers/specs/2026-09-26-pl-vehicle-recharge-workflow-design.md`  
+> - 小程序菜单/角色模式:`docs/superpowers/specs/2026-09-13-mini-pl-driver-plan-design.md`  
+> - UI 参考:`miniprogram/pages/pl/fuel-register/`  
+> **界面规范**: `docs/miniprogram-ui-spec-sanqiang.md`
+
+---
+
+## 1. 目标与范围
+
+### 1.1 目标
+
+在小程序「运输管理」下新增 **【ETC加油充值申请】**,供 **司机 / 押运员** 角色:
+
+1. 查看 **本人车辆**(`pl_vehicle_personnel` 含当前用户关联人员)上的全部充值申请(含他人代申请);
+2. 新建申请(草稿 / 保存并提交)、草稿与驳回可编辑再提交、本人单可作废;
+3. 详情展示申请信息 + 审批进度/历史 + 发放信息(对齐 Web 申请详情);
+4. 交互与视觉对齐现有 **【加油登记】**。
+
+### 1.2 已确认决策
+
+| # | 项 | 决策 |
+|---|-----|------|
+| D1 | 列表范围 | 车牌 ∈ 当前用户关联人员所在车辆(`pl_vehicle_personnel`);**含他人代申请** |
+| D2 | 充值类型 | 可选 **ETC / 加油**(与 Web 一致) |
+| D3 | 操作闭环 | 新建 → 草稿 → 提交;草稿/驳回可编辑再提交;**本人**单可作废;他人代申请 **仅查看** |
+| D4 | 详情 | 申请信息 + 审批进度/历史 + 发放信息 |
+| D5 | 实现方案 | **复用** Web `/transport/vehicle-recharge-apply/*`,增加 `mineVehicles` 作用域;不新建一套业务 API |
+| D6 | 申请人 | 小程序强制为当前登录用户(不可改选) |
+| D7 | 车牌 | 仅本人挂靠车辆;多车下拉;仅一辆时自动选中 |
+| D8 | 角色 | `sys_role.role_name IN ('司机', '押运员')`(按名匹配;测试库可幂等补建) |
+
+### 1.3 非目标
+
+- 小程序端审批、发放登记
+- 改动 Web「ETC加油充值申请 / 审批 / 发放管理」三页业务逻辑(除后端对 `mineVehicles` 的兼容)
+- 改动充值审批流程配置
+- 纯前端过滤全量列表(禁止)
+
+---
+
+## 2. 架构
+
+```
+小程序 list / form
+  → GET/POST/PUT … /transport/vehicle-recharge-apply/*?mineVehicles=true
+  → GET /transport/vehicle?mineVehicles=true(车牌下拉)
+  → 服务端:
+       user.id
+         → pl_personnel.sys_user_id
+         → pl_vehicle_personnel.personnel_id
+         → pl_vehicle.license_plate 集合
+       列表:license_plate IN 集合
+       写:车牌 ∈ 集合;申请人 = 当前用户;编辑/提交/作废仅本人申请
+Web 申请 / 审批 / 发放 不传 mineVehicles,行为不变
+```
+
+**推荐方案说明(相对独立小程序 API)**:复用同一状态机与审批/发放数据,避免双端漂移;仅增加车辆人员作用域校验。
+
+---
+
+## 3. 菜单与权限
+
+### 3.1 菜单树
+
+```
+移动端根 (id=1)
+└─ 运输管理 (MINI_PL_ROOT)                         ← 复用
+   ├─ 加油登记 (MINI_PL_FUEL_REG)                  ← 不动
+   ├─ ETC加油充值申请 (MINI_PL_VEHICLE_RECHARGE_APPLY) ← 新建
+   ├─ …(现场运输计划单 / 运输计划 / 司机运输计划单等现有项)
+```
+
+| 字段 | 值 |
+|------|-----|
+| id | `MINI_PL_VEHICLE_RECHARGE_APPLY` |
+| menu_name | `ETC加油充值申请` |
+| parent_id | `MINI_PL_ROOT` |
+| menu_type | `C` |
+| path | `vehicle-recharge-apply` |
+| perms | `mini:pl:vehicleRechargeApply:list` |
+| order_num | 建议紧接加油登记之后(如 `2`;冲突以迁移 SQL 为准) |
+
+### 3.2 角色授权
+
+- 按 `sys_role.role_name IN ('司机', '押运员') AND del_flag = 0` 匹配(不写死 role id)
+- **测试库**:角色不存在则幂等创建,再绑菜单
+- **生产库**:角色已存在则只做菜单 + `sys_role_menu`
+- 绑定菜单:`1`、`MINI_PL_ROOT`、`MINI_PL_VEHICLE_RECHARGE_APPLY`
+
+### 3.3 交付 SQL
+
+`docs/sql/migrations/2026-09-27-mini-pl-vehicle-recharge-apply-menus.sql`  
+(菜单 + 角色补齐 + 授权;幂等 `NOT EXISTS`)
+
+### 3.4 前端工作台配置
+
+| 文件 | 改动 |
+|------|------|
+| `miniprogram/config/workbench-menus.js` | 运输管理下增加菜单项 |
+| `miniprogram/config/api.js` | `PAGE_PATHS` + `WORKBENCH_ROUTE_MAP` |
+| `miniprogram/pages.json` | 分包注册 list / form |
+
+- code: `pl-vehicle-recharge-apply`
+- perms: `mini:pl:vehicleRechargeApply:list`
+- 工作台按 `menuCodes` 过滤(`workbenchMenuFilter.js`),无 perms 则不可见
+
+---
+
+## 4. 页面与交互
+
+### 4.1 页面路径
+
+| 页面 | 路径 |
+|------|------|
+| 列表 | `miniprogram/pages/pl/vehicle-recharge-apply/list.vue` |
+| 表单/详情 | `miniprogram/pages/pl/vehicle-recharge-apply/form.vue` |
+
+样式:复用 `@/styles/bx-theme.scss` 与加油登记同类 class(`bx-page`、`topbar`、`expense-card`、`fab-add`、`bx-sheet`、`form-card`、`bottom-action-bar` 等)。
+
+### 4.2 列表
+
+- 顶栏标题:`ETC加油充值申请`;右下角 FAB 新建
+- 搜索:申请单号 / 车牌(`q`)
+- 状态 Tab:全部 / 草稿 / 审批中 / 已驳回 / 已发放 / 已作废  
+  (状态值:`draft` / `in_approval` / `rejected` / `disbursed` / `cancelled`;不单独展示历史 `pending`)
+- 卡片:车牌主标题 + 状态 Tag;KV:申请单号、充值类型、申请日期、申请人、期初公里数、备注(有则显示)
+- 操作:
+  - 本人且 `draft|rejected`:编辑 / 提交 / 作废
+  - 其余:查看
+- 下拉刷新 + 上拉分页;请求统一带 `mineVehicles=true`
+
+### 4.3 表单 / 详情(同一 form 页)
+
+**可编辑(本人且 `draft|rejected`,或新建)**
+
+| 字段 | 规则 |
+|------|------|
+| 申请单号 | 只读(新建无) |
+| 申请人 | 锁定当前用户展示名 |
+| 车牌号 | 必填;底部 sheet 选本人车辆;1 辆自动选中 |
+| 充值类型 | 必填;分段 ETC / 加油 |
+| 申请日期 | 必填;默认今天 |
+| 期初公里数 | 选填 |
+| 备注 | 选填 |
+| 附件 | 选填;`uni.chooseImage` + 上传;folder=`pl/vehicle-recharge/apply` |
+
+**只读块(详情有数据时展示)**
+
+- 审批进度 / 历史(对齐 Web `approvalFlow` / `approvalHistory`)
+- 发放信息:充值订单号、充值日期、金额、卡号、加油站/渠道、发放人、备注、发放附件;无发放时显示「暂无」
+
+**底栏**
+
+- 可编辑:`保存`、`保存并提交`
+- 本人草稿/驳回:可作废(确认框)
+- 他人代申请或不可编辑状态:无写操作按钮
+
+### 4.4 车牌选择
+
+- UI:与加油登记相同的 `bx-sheet` 模糊检索
+- 数据:`GET /transport/vehicle?mineVehicles=true`(pageSize 足够覆盖本人车辆;可选本地 keyword 过滤)
+- 0 辆:提示「暂无可用车辆」/「未关联驾押人员,请联系管理员」(按是否解析到人员区分)
+
+---
+
+## 5. 后端 API / 数据范围
+
+### 5.1 参数
+
+在现有申请相关接口增加查询/写作用域参数:
+
+- `mineVehicles`(bool,alias 同名;默认 `false`)
+- Web 管理端 **不传**,行为与现网一致
+
+### 5.2 行为矩阵
+
+| 方法 | 路径 | `mineVehicles=true` |
+|------|------|---------------------|
+| GET | `/transport/vehicle-recharge-apply/` | `license_plate ∈ 本人车辆车牌集` |
+| GET | `/transport/vehicle-recharge-apply/{id}` | 不在集合 → **403** |
+| POST | `/transport/vehicle-recharge-apply/` | 申请人强制当前用户;车牌须在集合 |
+| PUT | `/{id}` | 须 **本人申请** + 可编辑状态;车牌须在集合 |
+| POST | `/{id}/submit` | 须 **本人申请** + 可编辑状态 |
+| POST | `/{id}/cancel` | 须 **本人申请** + 草稿/驳回 |
+| GET | `/transport/vehicle` | 仅返回本人挂靠车辆 |
+
+### 5.3 本人车辆车牌集
+
+```
+current_user.id
+  → pl_personnel WHERE sys_user_id = user.id AND del_flag = 0
+  → pl_vehicle_personnel WHERE personnel_id = … AND del_flag = 0
+  → pl_vehicle.license_plate(同租户、del_flag = 0)
+```
+
+- 复用 `resolve_personnel_for_user`(`pl_driver_plan_service` 已有)
+- 无关联人员 → 空集合(列表空;写操作拒绝并提示)
+
+### 5.4 建议实现落点
+
+| 位置 | 内容 |
+|------|------|
+| `pl_vehicle_recharge_service`(或共享 helper) | `_license_plates_for_user_personnel`、`_assert_mine_vehicle_plate`、`_assert_own_apply_for_write`;`list_applies` / `get` / `create` / `update` / `submit` / `cancel` 接入 `mine_vehicles` |
+| `api/pl/vehicle_recharge.py` | 解析 `mineVehicles` 并传入 service |
+| `api/pl/base_data.py` `list_vehicles` | 支持 `mineVehicles` 过滤 |
+| 测试 | 车辆人员过滤、他人代申请可见只读、越权 403、Web 默认路径回归 |
+
+### 5.5 状态机(不改)
+
+`draft` → `in_approval` → `disbursed`;`rejected` 可改再提;`cancelled` 终态。  
+可编辑集合仍为 `draft` / `rejected`。
+
+---
+
+## 6. 小程序 API 封装
+
+文件:`miniprogram/api/pl.js`(或同目录扩展)
+
+```js
+// 示意:所有申请接口默认带 mineVehicles: true
+vehicleRechargeApplyApi = {
+  list, get, create, update, submit, cancel
+}
+// 车辆:fetchVehicleOptions(q, { mineVehicles: true })
+```
+
+上传路径须在 `API_ENCRYPT_EXCLUDE_PATHS` 已覆盖的既有上传通道内(与加油登记一致)。
+
+---
+
+## 7. 错误处理
+
+| 场景 | HTTP / 行为 | 小程序提示方向 |
+|------|-------------|----------------|
+| 未绑定人员 | 空列表;新建拦截 | 未关联驾押人员,请联系管理员 |
+| 无挂靠车辆 | 下拉空 | 暂无可用车辆 |
+| 车牌不在集合 | 400/403 | 只能选择本人车辆 |
+| 编辑/提交/作废他人单 | 403 | 只能操作本人申请 |
+| 非可编辑状态改写 | 400 | 沿用后端文案 |
+| 流程未配置节点 | 400 | 充值审批流程未配置节点 |
+
+---
+
+## 8. 验收清单
+
+1. 司机/押运员工作台可见「ETC加油充值申请」;无该 perms 的角色不可见  
+2. 列表仅本人车辆申请(含他人代申请)  
+3. 新建:车牌=本人车辆;多车可选;申请人锁定本人;类型可选 ETC/加油  
+4. 保存草稿 → 提交 → `in_approval`;Web 审批端可见该单  
+5. 驳回后可改再提;本人草稿/驳回可作废  
+6. 他人代申请:可看详情(审批+发放),无编辑/提交/作废  
+7. 详情字段对齐 Web(申请 + 审批流 + 发放)  
+8. UI 对齐加油登记(topbar / card / FAB / sheet / 底栏)  
+9. Web 申请列表不传 `mineVehicles`,数据范围与现网一致  
+
+---
+
+## 9. 实现文件清单(预期)
+
+| 端 | 文件 |
+|----|------|
+| SQL | `docs/sql/migrations/2026-09-27-mini-pl-vehicle-recharge-apply-menus.sql` |
+| Backend | `backend/app/api/pl/vehicle_recharge.py`、`base_data.py`;`backend/app/services/pl_vehicle_recharge_service.py`(+ 可选 helper);测试 |
+| Mini | `pages/pl/vehicle-recharge-apply/list.vue`、`form.vue`;`api/pl.js`;`config/workbench-menus.js`;`config/api.js`;`pages.json` |
+
+---
+
+## 10. 与「加油登记」差异说明
+
+现有加油登记小程序使用 `mineOnly`:**按登记人 = 当前用户** 过滤,**不是**按车辆人员。  
+本功能按产品要求采用 **车辆人员归属**(D1),仅 UI/页面骨架参考加油登记;后端过滤语义不同,勿混用 `mineOnly` 参数名以免误解。