feat: 审批流程模块 (T审批A审批)
- 新增 backend/app/api/approval.py 审批API - 前端H5支持发起审批、审批操作 - 添加审批卡片弹窗组件 - 路由注册审批模块
This commit is contained in:
@@ -0,0 +1,461 @@
|
||||
# 数据库 ER 图 + 环境变量清点
|
||||
|
||||
**日期**: 2026-06-15
|
||||
**审计人**: Claude(满载跑批)
|
||||
**关联**: [[技术架构]] / [[风险跟踪表]] / [[前端审计报告]]
|
||||
|
||||
---
|
||||
|
||||
## 📌 1. ER 图(ASCII + Mermaid)
|
||||
|
||||
### 1.1 实体清单(16 张表)
|
||||
|
||||
| # | 表名 | 中文 | 模型文件 | 用途 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | `conversations` | 会话 | `conversation.py` | 核心:员工-坐席咨询会话 |
|
||||
| 2 | `messages` | 消息 | `message.py` | 会话内的所有消息 |
|
||||
| 3 | `agents` | 坐席 | `agent.py` | IT 服务人员 |
|
||||
| 4 | `employees` | 员工 | `employee.py` | 通过 OAuth2 认证的员工 |
|
||||
| 5 | `agent_notes` | 坐席备注 | `agent_note.py` | 坐席对会话的备注 |
|
||||
| 6 | `system_configs` | 系统配置 | `system_config.py` | 动态配置(关键词/阈值) |
|
||||
| 7 | `config_change_logs` | 配置变更日志 | `config_change_log.py` | 配置项的审计 |
|
||||
| 8 | `quick_reply_templates` | 快速回复模板 | `quick_reply_template.py` | 坐席常用回复 |
|
||||
| 9 | `funny_phrases` | 趣味话术 | `funny_phrase.py` | 等候中的趣味话 |
|
||||
| 10 | `approval_links` | 审批流程链接 | `approval_link.py` | 各类审批入口 |
|
||||
| 11 | `software_downloads` | 软件下载 | `software_download.py` | 常用软件清单 |
|
||||
| 12 | `troubleshooting_templates` | 排障模板 | `troubleshooting_template.py` | 标准化排障路径 |
|
||||
| 13 | `todo_items` | 待办事项 | `todo_item.py` | 工单/审批/设备 |
|
||||
| 14 | `roles` | 角色 | `role.py` | RBAC 角色定义 |
|
||||
| 15 | `user_roles` | 用户-角色关联 | `user_role.py` | 多对多关联 |
|
||||
| 16 | `role_mapping_rules` | 角色映射规则 | `role_mapping_rule.py` | 自动分配规则 |
|
||||
|
||||
### 1.2 ER 图(Mermaid)
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
EMPLOYEES ||--o{ CONVERSATIONS : "创建(通过 corp_id+employee_id)"
|
||||
EMPLOYEES ||--o{ USER_ROLES : "拥有角色"
|
||||
CONVERSATIONS ||--o{ MESSAGES : "包含"
|
||||
CONVERSATIONS ||--o{ AGENT_NOTES : "有备注"
|
||||
CONVERSATIONS }o--|| AGENTS : "被分配给"
|
||||
AGENTS ||--o{ AGENT_NOTES : "写"
|
||||
AGENTS ||--o{ QUICK_REPLY_TEMPLATES : "提交"
|
||||
AGENTS ||--o{ CONFIG_CHANGE_LOGS : "改配置"
|
||||
ROLES ||--o{ USER_ROLES : "分配给"
|
||||
ROLES ||--o{ ROLE_MAPPING_RULES : "按规则映射"
|
||||
CONVERSATIONS ||--o| TODO_ITEMS : "关联待办"
|
||||
SYSTEM_CONFIGS ||--o{ CONFIG_CHANGE_LOGS : "被改"
|
||||
|
||||
EMPLOYEES {
|
||||
string id PK "UUID"
|
||||
string corp_id "企业ID"
|
||||
string employee_id "企微UserID"
|
||||
string name "姓名"
|
||||
string department "部门(IDs)"
|
||||
string position "岗位"
|
||||
string mobile
|
||||
string email
|
||||
string avatar
|
||||
int status "1激活 2禁用 4未激活"
|
||||
string it_level "技能等级"
|
||||
string it_level_source
|
||||
json notes "坐席备注"
|
||||
datetime last_login_at
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
AGENTS {
|
||||
string id PK
|
||||
string user_id UK "企微UserID"
|
||||
string name
|
||||
string status "online/offline/busy"
|
||||
int current_load
|
||||
int max_load
|
||||
string role "admin/agent"
|
||||
json skill_tags
|
||||
string otp_secret "TOTP密钥"
|
||||
boolean otp_enabled
|
||||
string password_hash "bcrypt"
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
CONVERSATIONS {
|
||||
string id PK
|
||||
string corp_id
|
||||
string employee_id
|
||||
string employee_name
|
||||
string department
|
||||
string position
|
||||
string level
|
||||
string status "ai/queued/serving/resolved"
|
||||
boolean is_vip
|
||||
boolean is_pinned
|
||||
boolean is_todo
|
||||
int urgency_score "1-5"
|
||||
json tags
|
||||
string assigned_agent_id FK
|
||||
json collaborating_agent_ids
|
||||
json participants
|
||||
int ai_substantive_reply_count
|
||||
int impact_scope
|
||||
boolean is_blocking
|
||||
string emotion_state
|
||||
string dify_conversation_id
|
||||
datetime last_message_at
|
||||
string last_message_summary
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
MESSAGES {
|
||||
string id PK
|
||||
string conversation_id FK
|
||||
string sender_type "employee/agent/ai/system"
|
||||
string sender_id
|
||||
string sender_name
|
||||
text content
|
||||
string msg_type "text/image/file/voice/system"
|
||||
string reply_to_id "引用"
|
||||
string media_id
|
||||
string media_url
|
||||
string file_name
|
||||
int file_size
|
||||
json extra_data
|
||||
boolean ai_suggestion
|
||||
string status "sending/sent/delivered/read"
|
||||
datetime recallable_until
|
||||
boolean is_read
|
||||
string suggestion_action "accepted/edited/ignored"
|
||||
datetime created_at
|
||||
}
|
||||
|
||||
AGENT_NOTES {
|
||||
string id PK
|
||||
string conversation_id FK
|
||||
string agent_id
|
||||
text content
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
SYSTEM_CONFIGS {
|
||||
string id PK
|
||||
string config_key UK
|
||||
text config_value
|
||||
string description
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
CONFIG_CHANGE_LOGS {
|
||||
string id PK
|
||||
string config_key
|
||||
text old_value
|
||||
text new_value
|
||||
string changed_by
|
||||
datetime changed_at
|
||||
}
|
||||
|
||||
QUICK_REPLY_TEMPLATES {
|
||||
string id PK
|
||||
string category
|
||||
string title
|
||||
text content
|
||||
json variables
|
||||
int sort_order
|
||||
string status "draft/pending/approved/rejected"
|
||||
int version
|
||||
string submitted_by
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
FUNNY_PHRASES {
|
||||
string id PK
|
||||
string scene "shake/keyword/waiting/connected/timeout/vip"
|
||||
text content
|
||||
string tone
|
||||
int sort_order
|
||||
boolean is_active
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
APPROVAL_LINKS {
|
||||
string id PK
|
||||
string category "IT/HR/行政/财务"
|
||||
string title
|
||||
text url
|
||||
int sort_order
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
SOFTWARE_DOWNLOADS {
|
||||
string id PK
|
||||
string category "办公/开发/安全/工具"
|
||||
string name
|
||||
string version
|
||||
string platform
|
||||
text download_url
|
||||
int sort_order
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
TROUBLESHOOTING_TEMPLATES {
|
||||
string id PK
|
||||
string name
|
||||
string category "vpn/email/system/account"
|
||||
json path_steps
|
||||
json flowchart
|
||||
boolean is_active
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
TODO_ITEMS {
|
||||
string id PK
|
||||
string type "ticket/approval/device"
|
||||
string title
|
||||
string priority "urgent/high/normal"
|
||||
json description
|
||||
string status "pending/processing/resolved"
|
||||
string assigned_agent_id
|
||||
string corp_id
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
ROLES {
|
||||
string id PK
|
||||
string name UK "user/agent/admin"
|
||||
string display_name
|
||||
text description
|
||||
json permissions
|
||||
boolean is_default
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
USER_ROLES {
|
||||
string id PK
|
||||
string employee_id
|
||||
string role_id FK
|
||||
string source "auto/tag/ehr/manual"
|
||||
string assigned_by
|
||||
datetime assigned_at
|
||||
datetime expires_at
|
||||
}
|
||||
|
||||
ROLE_MAPPING_RULES {
|
||||
string id PK
|
||||
string role_id FK
|
||||
string source_type "wecom_tag/ehr_position"
|
||||
string source_value
|
||||
int priority
|
||||
boolean is_active
|
||||
datetime created_at
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 ER 关系总结
|
||||
|
||||
```
|
||||
┌────────────┐
|
||||
│ EMPLOYEES │
|
||||
│ (员工) │
|
||||
└─────┬──────┘
|
||||
│ corp_id + employee_id
|
||||
┌─────────────┼─────────────┐
|
||||
│ │ │
|
||||
v v v
|
||||
┌────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│CONVER- │ │ USER_ROLES │ │TODO_ITEMS │
|
||||
│SATIONS │ │ ↕ │ │(企业内待办) │
|
||||
└──┬─────┘ │ ROLES │ └──────────────┘
|
||||
│ │↕ │
|
||||
│ │ROLE_MAPPING │
|
||||
│ │_RULES │
|
||||
│ └──────────────┘
|
||||
│ 1:N
|
||||
v
|
||||
┌────────┐ 1:N ┌────────┐
|
||||
│MESSAGES│◄─────│AGENT_ │
|
||||
└────────┘ │NOTES │
|
||||
└────┬───┘
|
||||
│ 写
|
||||
v
|
||||
┌────────┐
|
||||
┌──────────┐ │AGENTS │
|
||||
│CONFIGS │ └───┬────┘
|
||||
│ ↕ │ │ 改
|
||||
│CHANGE │◄───────┘
|
||||
│LOGS │
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
**关系数**: 13 个外键关联 + 3 个 JSON 数组(协作/参与者/技能)
|
||||
**外键关系**:
|
||||
1. `conversations.employee_id` → 企微 ID(无 DB FK,跨企业灵活)
|
||||
2. `conversations.assigned_agent_id` → `agents.id`(可空)
|
||||
3. `messages.conversation_id` → `conversations.id` (CASCADE)
|
||||
4. `agent_notes.conversation_id` → `conversations.id` (CASCADE)
|
||||
5. `agent_notes.agent_id` → `agents.id`(无 CASCADE)
|
||||
6. `user_roles.role_id` → `roles.id` (CASCADE)
|
||||
7. `role_mapping_rules.role_id` → `roles.id` (CASCADE)
|
||||
8. `config_change_logs.changed_by` → `agents.id`(无 FK)
|
||||
9. `quick_reply_templates.submitted_by` → `agents.id`(可空)
|
||||
|
||||
---
|
||||
|
||||
## 📌 2. 字段-模块映射
|
||||
|
||||
| 业务模块 | 主要表 | 关键字段 |
|
||||
|---|---|---|
|
||||
| 鉴权登录 | `agents`, `employees`, `roles`, `user_roles` | `user_id`, `password_hash`, `otp_secret`, `role` |
|
||||
| 会话管理 | `conversations` | `status`, `urgency_score`, `assigned_agent_id`, `is_vip` |
|
||||
| 消息 | `messages` | `sender_type`, `content`, `msg_type`, `reply_to_id` |
|
||||
| AI 助手 | `conversations`, `system_configs` | `dify_conversation_id`, `ai_substantive_reply_count` |
|
||||
| 排障 | `troubleshooting_templates` | `path_steps`, `flowchart` |
|
||||
| 快速回复 | `quick_reply_templates` | `category`, `content`, `variables` |
|
||||
| 待办 | `todo_items` | `type`, `status`, `priority` |
|
||||
| 工具面板 | `approval_links`, `software_downloads`, `funny_phrases` | `category`, `scene` |
|
||||
| 动态配置 | `system_configs`, `config_change_logs` | `config_key`, `config_value` |
|
||||
| 审计 | `config_change_logs` | `changed_by`, `changed_at`, `old_value`, `new_value` |
|
||||
|
||||
---
|
||||
|
||||
## 📌 3. 数据规模评估(生产估算)
|
||||
|
||||
| 表 | 日增(估) | 总量/年 | 备注 |
|
||||
|---|---|---|---|
|
||||
| `conversations` | 100-500 | 50K-100K | 视企业规模 |
|
||||
| `messages` | 1K-10K | 1M-3M | 高频 |
|
||||
| `employees` | 10-30 | 5K-20K | 增长慢 |
|
||||
| `agents` | 0-1 | 20-50 | 增长极慢 |
|
||||
| `agent_notes` | 50-200 | 30K-70K | 每会话 1-2 条 |
|
||||
| `quick_reply_templates` | 1-3 | 50-200 | 缓慢增长 |
|
||||
| `system_configs` | 0-1 | 50-100 | 极慢 |
|
||||
| `config_change_logs` | 5-20 | 5K-10K | 审计 |
|
||||
| `todo_items` | 50-200 | 30K-70K | 流转快 |
|
||||
| `troubleshooting_templates` | 0-1 | 30-50 | 缓慢 |
|
||||
| `funny_phrases` | 0 | 30-50 | 几乎不变 |
|
||||
| `approval_links` | 0-1 | 20-50 | 缓慢 |
|
||||
| `software_downloads` | 0-1 | 30-80 | 缓慢 |
|
||||
| `roles` | 0 | 3-10 | 几乎不变 |
|
||||
| `user_roles` | 5-15 | 5K-20K | 跟员工同步 |
|
||||
| `role_mapping_rules` | 0 | 5-15 | 几乎不变 |
|
||||
|
||||
**总数据量估算**: 第 1 年 ~5-10 MB(纯数据), 含索引 ~20-50 MB
|
||||
**建议**: PostgreSQL 起步 10 GB 足够,3-5 年无需扩容
|
||||
|
||||
---
|
||||
|
||||
## 📌 4. 环境变量清点(15 个 + 4 个文档化待补)
|
||||
|
||||
### 4.1 后端核心(`backend/app/config.py`)
|
||||
|
||||
| # | 变量 | 类型 | 默认 | 必填 | 敏感 | 用途 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 | `WECOM_CORP_ID` | str | ww1234... | ✅ | ❌ | 企微企业 ID |
|
||||
| 2 | `WECOM_AGENT_ID` | str | 1000002 | ✅ | ❌ | 企微应用 ID |
|
||||
| 3 | `WECOM_SECRET` | str | your-agent-secret | ✅ | 🔴 高 | 企微应用 Secret |
|
||||
| 4 | `WECOM_TOKEN` | str | your-callback-token | ✅ | 🟠 中 | 回调 Token |
|
||||
| 5 | `WECOM_ENCODING_AES_KEY` | str | your-aes-key-43-... | ✅ | 🟠 中 | 回调 AES Key |
|
||||
| 6 | `DATABASE_URL` | str | postgresql://wecom:... | ✅ | 🔴 高(密码部分) | DB 连接 |
|
||||
| 7 | `REDIS_URL` | str | redis://localhost:6379/0 | ✅ | 🟠 中(密码) | Redis 连接 |
|
||||
| 8 | `BACKEND_HOST` | str | 0.0.0.0 | ❌ | ❌ | 监听地址 |
|
||||
| 9 | `BACKEND_PORT` | int | 8000 | ❌ | ❌ | 监听端口 |
|
||||
| 10 | `CORS_ORIGINS` | str(逗号分隔) | localhost:5173,5174 | 🟡 生产必填 | ❌ | CORS 白名单 |
|
||||
| 11 | `DIFY_API_URL` | str | "" | 🟡 启用 AI 必填 | ❌ | Dify Chat 端点 |
|
||||
| 12 | `DIFY_API_KEY` | str | "" | 🟡 启用 AI 必填 | 🔴 高 | Dify API Key |
|
||||
| 13 | `DIFY_TIMEOUT` | int | 30 | ❌ | ❌ | Dify 超时 |
|
||||
| 14 | `DIFY_WINGMAN_API_URL` | str | "" | ❌ | ❌ | Wingman 端点 |
|
||||
| 15 | `DIFY_WINGMAN_API_KEY` | str | "" | ❌ | 🔴 高 | Wingman Key |
|
||||
| 16 | `DIFY_WINGMAN_TIMEOUT` | int | 30 | ❌ | ❌ | Wingman 超时 |
|
||||
| 17 | `MOCK_LOGIN_ENABLED` | bool | false | ❌ | ❌ | Mock 登录开关 |
|
||||
|
||||
**合计 17 个**(`Settings` 字段),**5 个敏感**(3 个 P0-高,2 个 P0-中)
|
||||
|
||||
### 4.2 部署相关(`deploy-server/.env` / `deploy-nas/.env.nas`)
|
||||
|
||||
| # | 变量 | 用途 |
|
||||
|---|---|---|
|
||||
| 18 | `POSTGRES_USER` | DB 用户名 |
|
||||
| 19 | `POSTGRES_PASSWORD` | DB 密码(🔴) |
|
||||
| 20 | `POSTGRES_DB` | DB 名 |
|
||||
| 21 | `REDIS_PASSWORD` | Redis 密码(🔴) |
|
||||
|
||||
### 4.3 前端(Vue 4 个端)
|
||||
|
||||
| 前端 | 变量 | 用途 |
|
||||
|---|---|---|
|
||||
| admin | `VITE_API_BASE_URL` | 后端地址 |
|
||||
| agent | `VITE_API_BASE_URL`, `VITE_WS_URL` | 后端 + WebSocket |
|
||||
| h5 | `VITE_API_BASE_URL`, `VITE_WS_URL` | 同上 |
|
||||
| portal | `VITE_API_BASE_URL`, `VITE_PORTAL_REDIRECT` | 入口跳转 |
|
||||
|
||||
### 4.4 漏配/待补
|
||||
|
||||
| # | 变量 | 状态 | 影响 |
|
||||
|---|---|---|---|
|
||||
| A | `LOG_LEVEL` | ❌ 缺失 | 日志粒度无法控制 |
|
||||
| B | `JWT_SECRET` / `SESSION_SECRET` | ❌ 缺失 | token 加密用,但还没用 JWT |
|
||||
| C | `WS_TOKEN_SECRET` | ❌ 缺失 | WS token 签名用 |
|
||||
| D | `DIFY_PROXY_URL` | ❌ 文档化但未用 | 公司有内部 Dify,本项目直连 |
|
||||
|
||||
---
|
||||
|
||||
## 📌 5. 敏感凭据安全审计
|
||||
|
||||
### 5.1 现状
|
||||
|
||||
| # | 凭据 | 存储位置 | 风险 |
|
||||
|---|---|---|---|
|
||||
| 1 | WECOM_SECRET | `.env.production`(git?) | 🟠 中(看是否加 .gitignore) |
|
||||
| 2 | POSTGRES_PASSWORD | `.env.production` | 🟠 中 |
|
||||
| 3 | REDIS_PASSWORD | `.env.production` | 🟠 中 |
|
||||
| 4 | DIFY_API_KEY | `.env.production` | 🟠 中 |
|
||||
| 5 | 内部 Gitea tokens | wincred(✅) | 🟢 已修 |
|
||||
|
||||
### 5.2 待办(风险跟踪表 M-11)
|
||||
|
||||
- [ ] `.env.production` 是否在 .gitignore?(需确认)
|
||||
- [ ] `.env.nas` 是否入仓?(文档明确说不入)
|
||||
- [ ] 公司有内部 Vault?目前直连 Dify
|
||||
- [ ] WECOM_TOKEN / AES_KEY 走 vault(下一轮)
|
||||
|
||||
### 5.3 短期方案(本周)
|
||||
|
||||
```bash
|
||||
# 1. 验证 .gitignore 覆盖
|
||||
git check-ignore -v .env.production .env.nas backend/.env
|
||||
|
||||
# 2. 验证仓里无 secret
|
||||
git log --all -p --source -- .env.production 2>/dev/null | head -20
|
||||
|
||||
# 3. 跑 gitleaks 扫描
|
||||
bash scripts/security-audit.sh --secrets
|
||||
```
|
||||
|
||||
### 5.4 长期方案(下季度)
|
||||
|
||||
1. **NAS Vault**:用 Synology 的「密码保险箱」存关键 secret
|
||||
2. **Server Keyring**:用 systemd-creds / HashiCorp Vault
|
||||
3. **环境变量注入**:容器启动时从 vault 拉,不入镜像
|
||||
|
||||
---
|
||||
|
||||
## 📌 6. 关联文档
|
||||
|
||||
- [[技术架构]] §3 数据层
|
||||
- [[风险跟踪表]] M-11(凭据管理)/ D-3(DB 密码)
|
||||
- [[外部系统集成]] §1-4(火绒/联软/aTrust/eHR 凭据)
|
||||
- [[SOP-001-Gitea部署]] - token 走 wincred
|
||||
- [[Gitea部署指南]] - Gitea app.ini 凭据
|
||||
|
||||
---
|
||||
|
||||
*本清点是 2026-06-15 Claude 满载跑批产出,待评审*
|
||||
Reference in New Issue
Block a user