diff --git a/docs/superpowers/specs/2026-08-01-quote-approver-setting-design.md b/docs/superpowers/specs/2026-08-01-quote-approver-setting-design.md new file mode 100644 index 000000000..7ff2d9ac7 --- /dev/null +++ b/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 拒绝;租户隔离。 +- 前端手工:设置保存 → 列表提交预填 → 改人提交 → 清空设置后恢复手选;无菜单权限用户不可进设置页。 diff --git a/docs/web-admin-ui-pattern-index.md b/docs/web-admin-ui-pattern-index.md index 218fbbdcc..29ed4bae4 100644 --- a/docs/web-admin-ui-pattern-index.md +++ b/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 编号) | ---