6.7 KiB
6.7 KiB
报价单审批人设置(租户级默认审批人)
日期: 2026-08-01
状态: 已实现
选定方案: A — 租户级「报价单审批人设置」页 + 提交审批弹窗预填
相关 Demo: docs/fresh-mint-quote-approver-setting-demo.html
现状入口: web-admin 报价单管理 #/crm/quote(提交审批弹窗每次手选审批人)
1. 目标
- 管理员在独立设置页配置租户级默认审批人(支持多人、有序)。
- 业务员点击「提交审批」时,弹窗自动预填默认审批人,减少重复选择。
- 预填后仍可修改;未配置时行为与现网一致(审批人必填、须手选)。
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 | Nonesave_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.vueweb-admin/src/views/crm/quote/components/QuoteFormPanel.vue- 若
ApproverSelector.vue仍被使用,一并预填
行为:
- 打开弹窗 → 拉用户列表 + 拉设置。
- 若存在启用配置且过滤无效用户后仍有 ID → 预填
approverIds;可选轻提示「已按审批人设置预填,可修改」。 - 否则不预填、不提示,校验与现网一致(审批人必填)。
- 拉设置失败:不阻断打开弹窗,视为未配置。
- 备注字段:不预填。
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. 验收标准
- 管理员保存启用的默认审批人后,业务员打开提交弹窗可见预填且顺序正确。
- 业务员修改预填审批人后可成功提交,审批记录与所选一致。
- 未配置或停用时,提交行为与改造前一致。
- 无设置菜单权限的用户无法打开/保存设置页;有报价权限的用户仍可正常提交审批。
- 跨租户不可读到他租配置。
10. 实现触点(清单)
| 层 | 触点 |
|---|---|
| SQL | docs/sql/ + migrate;新表 crm_quote_approver_setting |
| Backend | model、CRUD、CRM route 注册、权限 |
| Frontend | 设置页、API、菜单/路由、提交弹窗预填 |
| Docs | 本设计;可选更新 UI pattern 索引条目 |
11. 测试建议
- 后端:get 空/有配置;put upsert;停用不返回为「可预填」;非法用户 ID 拒绝;租户隔离。
- 前端手工:设置保存 → 列表提交预填 → 改人提交 → 清空设置后恢复手选;无菜单权限用户不可进设置页。