## Context 山峡化工 web-admin 运输管理(PL)已有 ETC/加油充值申请与发放(`pl_vehicle_recharge_apply` / `pl_vehicle_recharge_record`),采用双菜单、无审批、1:0~1 关联、发放看板 UX。客户新增 **车辆维保** 需求,业务形态相似但申请字段更丰富,且需在选车时提醒未过预计取车日的待处理维保。 工程约束:租户隔离、数据权限、软删除、Fresh Mint UI、静态路由(`VITE_ACCESS_MODE=frontend`)。 ## Goals / Non-Goals **Goals:** - 交付维保申请页 + 处理登记页,业务规则与客户确认一致 - 复用 ETC 模块架构,降低回归与工期 - 选车维保提醒 API + 前端弹窗 **Non-Goals:** - 审批流、车辆状态自动联动、报表、小程序 ## Decisions ### D1 双菜单平行模块(非抽象框架) **决策**:新建 `pl_vehicle_maintenance_*` 表与独立 Service/API/页面,复制 ETC 模式。 **理由**:仅第二个类似场景,抽象成本高;独立模块便于维保特有规则(提醒、日期校验)演进。 **备选**:通用 ApplyDisburse 基类 — 拒绝(过度设计)。 ### D2 处理完成 = 申请 status processed **决策**:不设 `is_processed` 字段;创建/更新处理记录且关联申请时,申请置 `processed`。 **理由**:客户选 A,与 ETC「发放即完成」一致。 **备选**:独立布尔 — 拒绝。 ### D3 金额可选 **决策**:`amount` NULL 允许;非 NULL 时 > 0。 **理由**:客户选 B,可先登记处理人与时间。 ### D4 维保类型 varchar + UI allow-create **决策**:库存自由文本;字典仅作下拉预设(保养/维修/年检)。 **理由**:客户要求可手填;避免每次自定义类型写 dict 表。 ### D5 选车提醒 **决策**:查询 `pending` 且 `(expected_pickup_date IS NULL OR today <= expected_pickup_date)` 的申请;`today > expected_pickup_date` 不提醒;取车时间为空仍提醒。 **理由**:客户明确规则;不依赖 `vehicle_status`。 ### D6 单号前缀 **决策**:申请 `SXWB`,处理 `SXWC`。 **理由**:与 SXSQ/SXCL 命名风格一致,WB=维保,WC=维保处理。 ### D7 处理看板 API **决策**:`GET .../process-board`,申请 LEFT JOIN 处理(同 ETC `disburse-board`)。 **理由**:UX 已验证;行内处理/编辑。 ## Risks / Trade-offs | 风险 | 缓解 | |------|------| | 与 ETC 代码重复 | 接受;后续若第三模块再抽公共层 | | 多条 pending 提醒信息过多 | 弹窗列表展示全部待提醒项 | | 预计取车日为空长期 pending 持续提醒 | 符合客户确认;业务侧应填取车日或作废 | | 静态路由遗漏导致菜单不可见 | 同步 `pl.ts` + DB 菜单 | ## Migration Plan 1. 执行 `docs/sql/migrations/2026-06-29-pl-vehicle-maintenance.sql` 2. 部署后端 + 前端 3. 为相关角色授权菜单(脚本含 super_admin + 拥有 PL_VEHICLE 的角色) 4. 回滚:隐藏菜单;表保留(软删即可) ## Open Questions - (无 — 客户已确认 V1 范围)