Просмотр исходного кода

docs: mark quote approver setting design implemented

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 3 месяцев назад
Родитель
Сommit
ce75576fb0

+ 149 - 0
docs/superpowers/specs/2026-08-01-quote-approver-setting-design.md

@@ -0,0 +1,149 @@
+# 报价单审批人设置(租户级默认审批人)
+
+**日期:** 2026-08-01  
+**状态:** 已实现  
+**选定方案:** A — 租户级「报价单审批人设置」页 + 提交审批弹窗预填  
+**相关 Demo:** `docs/fresh-mint-quote-approver-setting-demo.html`  
+**现状入口:** `web-admin` 报价单管理 `#/crm/quote`(提交审批弹窗每次手选审批人)
+
+## 1. 目标
+
+1. 管理员在独立设置页配置**租户级默认审批人**(支持多人、有序)。
+2. 业务员点击「提交审批」时,弹窗**自动预填**默认审批人,减少重复选择。
+3. 预填后仍可修改;未配置时行为与现网一致(审批人必填、须手选)。
+
+## 2. 非目标(首版不做)
+
+- 默认备注模板
+- 「记住上次选的人」客户端缓存
+- 按部门 / 金额分岔审批人
+- 接入通用工作流引擎(OpenSpec `workflow-conventions` 目标能力,另项推进)
+- 改变现有 `submitQuote` 审批链路语义(顺序审批、状态流转等保持不变)
+
+## 3. 已确认决策
+
+| 项 | 决策 |
+|----|------|
+| 配置粒度 | 租户级一份配置 |
+| 提交时可改预填审批人 | 可以 |
+| 谁维护设置 | 仅拥有「报价单审批人设置」菜单权限的角色 |
+| 未配置时 | 与现在一样:审批人必填,弹窗为空,须手选 |
+| 默认备注 | 首版不做 |
+
+## 4. 数据模型
+
+### 4.1 表 `crm_quote_approver_setting`
+
+新建表,遵守 database-conventions 公共字段顺序:`id` → 业务字段 → 公共字段。
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `id` | VARCHAR(64) | UUID 主键 |
+| `approver_ids` | VARCHAR(1000) | 有序审批人用户 ID,逗号分隔(与现提交 `approverIds` 语义一致) |
+| `status` | CHAR(1) | `0` 启用 / `1` 停用;停用等同未配置 |
+| `tenant_no` | … | 租户 |
+| `order_num` / `remark` / `create_*` / `update_*` / `del_flag` | … | 公共字段 |
+
+约定:
+
+- 同一 `tenant_no` 下有效(`del_flag=0`)记录**至多一条**:`GET` 取该条;`PUT` 无则 insert、有则 update(upsert),禁止同租户插入第二条有效记录。
+- SQL 变更同步维护 `docs/sql/`(及必要的 migrate 脚本)。
+- 不做默认备注字段;备注仍只在提交弹窗手填。
+
+### 4.2 模型与 CRUD
+
+- SQLAlchemy:`backend/app/models/crm_models.py` 新增 `CrmQuoteApproverSetting`
+- CRUD:`backend/app/crud/crm/quote_approver_setting.py`(或同级模块)
+  - `get_setting(db, tenant_no)` → dict | None
+  - `save_setting(db, tenant_no, approver_ids, status, user_info)` → upsert
+
+保存时校验:审批人 ID 须为当前租户下存在且可用的用户;无效 ID 拒绝保存并提示。
+
+## 5. API
+
+挂在现有 CRM 路由体系(与 `crm_quote_routes` 同前缀风格),建议:
+
+| 方法 | 路径(示意) | 说明 |
+|------|----------------|------|
+| GET | `/api/web/admin/crm/quote-approver-setting` | 返回当前租户配置;无记录返回空对象/`null`(前端当未配置) |
+| PUT | `/api/web/admin/crm/quote-approver-setting` | Body:`{ approverIds: string[], status: '0'\|'1' }`;有则更新、无则创建 |
+
+约束:
+
+- 读写均按当前用户 `tenant_no` 过滤/写入,**不信任**客户端覆盖租户。
+- GET:登录且具备报价单相关业务权限即可读(用于提交预填);不要求具备设置页菜单。
+- PUT:须具备「报价单审批人设置」菜单权限(与项目现有角色-菜单校验方式对齐)。
+- **不改**现有 `submitQuote` 入参:仍由前端提交最终 `approverIds`。
+
+## 6. 前端
+
+### 6.1 设置页
+
+- 路由建议:`#/crm/quote-approver-setting`
+- 源码建议:`web-admin/src/views/crm/quote/approver-setting/index.vue`(表单配置页,非列表 CRUD)
+- 字段:默认审批人(多选、有序)、启用状态
+- UI:Fresh Mint;`label-position="top"`;面板主标题走 `panelTitleBarTextRules`(「报价单审批人设置」)
+- 菜单:CRM 报价相关下新增菜单项;图标仅一级菜单;权限挂在角色-菜单上
+- API 模块:`web-admin/src/api/crm/quote/` 增补 get/save setting
+
+### 6.2 提交审批弹窗预填
+
+改造所有会打开「提交审批」并选择审批人的入口,至少包括:
+
+- `web-admin/src/views/crm/quote/index.vue`
+- `web-admin/src/views/crm/quote/components/QuoteFormPanel.vue`
+- 若 `ApproverSelector.vue` 仍被使用,一并预填
+
+行为:
+
+1. 打开弹窗 → 拉用户列表 + 拉设置。
+2. 若存在**启用**配置且过滤无效用户后仍有 ID → 预填 `approverIds`;可选轻提示「已按审批人设置预填,可修改」。
+3. 否则不预填、不提示,校验与现网一致(审批人必填)。
+4. 拉设置失败:不阻断打开弹窗,视为未配置。
+5. 备注字段:不预填。
+
+### 6.3 界面模式
+
+- 设置页:接近「单对象配置表单」;对照 `docs/web-admin-ui-pattern-index.md` 选型时优先表单配置类模式(实现计划中写明 P 编号)。
+- 提交弹窗:沿用现有 `dialog-form-layout` + `form-grid-2`,不新开交互范式。
+
+## 7. 数据流
+
+```
+管理员 → 设置页 PUT → crm_quote_approver_setting
+业务员 → 打开提交弹窗 → GET setting → 预填 approverIds(可改)
+业务员 → 确定 → 现有 submitQuote({ id, approverIds, remark })
+后端 → create_approval_records(现有逻辑)
+```
+
+## 8. 边界情况
+
+| 场景 | 行为 |
+|------|------|
+| 设置中含已停用/已删用户 | 保存时校验失败;预填时过滤无效 ID,过滤后为空则当未配置 |
+| `status=停用` | 不预填 |
+| 清空审批人并保存 | 允许;之后不预填 |
+| 多人顺序 | 与现网一致:按选择顺序依次审批 |
+| 租户隔离 | 全部按 `tenant_no` |
+
+## 9. 验收标准
+
+1. 管理员保存启用的默认审批人后,业务员打开提交弹窗可见预填且顺序正确。
+2. 业务员修改预填审批人后可成功提交,审批记录与所选一致。
+3. 未配置或停用时,提交行为与改造前一致。
+4. 无设置菜单权限的用户无法打开/保存设置页;有报价权限的用户仍可正常提交审批。
+5. 跨租户不可读到他租配置。
+
+## 10. 实现触点(清单)
+
+| 层 | 触点 |
+|----|------|
+| SQL | `docs/sql/` + migrate;新表 `crm_quote_approver_setting` |
+| Backend | model、CRUD、CRM route 注册、权限 |
+| Frontend | 设置页、API、菜单/路由、提交弹窗预填 |
+| Docs | 本设计;可选更新 UI pattern 索引条目 |
+
+## 11. 测试建议
+
+- 后端:get 空/有配置;put upsert;停用不返回为「可预填」;非法用户 ID 拒绝;租户隔离。
+- 前端手工:设置保存 → 列表提交预填 → 改人提交 → 清空设置后恢复手选;无菜单权限用户不可进设置页。

+ 1 - 0
docs/web-admin-ui-pattern-index.md

@@ -453,6 +453,7 @@ const viewSections = computed(() => [{
 | db/plans, db/inventory, db/weighing(关联查看) | P09 · `DbRelatedViewDialog` / `SystemViewDialog` |
 | protocol(录入) | P01 + P12 |
 | demo/product | P01 + 专用 product-view-dialog |
+| **crm/quote/approver-setting**(报价单审批人设置) | 单对象配置表单(对照 `docs/fresh-mint-quote-approver-setting-demo.html`;无独立 P 编号) |
 
 ---