Files
shanxia2.0/docs/superpowers/specs/2026-08-01-quote-approver-setting-design.md
T
2026-08-01 17:29:37 +08:00

6.7 KiB
Raw Blame History

报价单审批人设置(租户级默认审批人)

日期: 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 同前缀风格),建议:

方法 路径(示意) 说明
POST /api/web/.../crm/quote-approver-setting/get 返回当前租户配置;无记录返回 { approverIds: [], status: '0' }(空列表不预填;默认启用避免设置页首次落到停用)
POST /api/web/.../crm/quote-approver-setting/save 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 拒绝;租户隔离。
  • 前端手工:设置保存 → 列表提交预填 → 改人提交 → 清空设置后恢复手选;无菜单权限用户不可进设置页。