1111 lines
32 KiB
Markdown
1111 lines
32 KiB
Markdown
|
|
# 保险智能客服系统 — 完整开发计划
|
|||
|
|
|
|||
|
|
> **基于**:需求文档 V1.0 + API 文档 V1.1 + 前端开发计划 + BaoDan 源码分析
|
|||
|
|
> **当前状态**:后端空壳(49 行注释)+ 前端骨架(743 行)+ SQL 建表(112 行)
|
|||
|
|
> **预计工期**:10 个工作日(一人全栈)
|
|||
|
|
> **核心原则**:BaoDan 已有的绝不重复造轮子
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 零、已确认不需要自研的功能(用 BaoDan 原生)
|
|||
|
|
|
|||
|
|
| 功能 | BaoDan 提供的 | 对应需求编号 |
|
|||
|
|
|------|-----------|:---:|
|
|||
|
|
| LLM 模型配置 CRUD | `ModelProviderCredentialApi` 后台可视化配置 | 6.1 / A6.1.1-A6.1.2 |
|
|||
|
|
| Prompt 编辑/版本/测试 | App 配置页 + Annotation 系统 | 6.2 / A6.1.3-A6.1.4 |
|
|||
|
|
| 对话日志查看/筛选 | BaoDan 后台 /logs 页面 | 4.1.1-4.1.2 |
|
|||
|
|
| 负反馈管理 | `MessageFeedbackExportApi` + Annotation | 4.1.4 |
|
|||
|
|
| 点赞/点踩 | BaoDan WebApp 内置 | 1.4.1 |
|
|||
|
|
| 推荐追问 | `MessageSuggestedQuestionApi` | 1.2.4 / A2.2.2 |
|
|||
|
|
| 来源引用标注 | BaoDan RAG 自动返回 sources | 1.2.3 |
|
|||
|
|
| 会话标题自动命名 | BaoDan 自动命名 | 1.1.5 |
|
|||
|
|
| 知识库测试入口(hit testing) | `HitTestingApi` | 3.4.1 |
|
|||
|
|
| FAQ 手动条目 | BaoDan Annotation Reply = FAQ | 3.4.3 |
|
|||
|
|
| 文档上传/列表/删除/重试 | BaoDan `/datasets` 后台 | 3.1.1-3.1.2 / 3.1.5 / 3.2.x |
|
|||
|
|
| Markdown 渲染 | BaoDan WebApp 内置 | 1.2.1 |
|
|||
|
|
| 多轮对话上下文 | BaoDan conversation 机制 | 1.1.3 |
|
|||
|
|
| 流式输出 | BaoDan WebApp iframe | 1.1.2 |
|
|||
|
|
|
|||
|
|
**以上功能不需要写后端接口,不需要写前端页面。**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、后端自研接口清单(25 个,对齐 API 文档 V1.1)
|
|||
|
|
|
|||
|
|
### 1.1 认证鉴权(4 个)
|
|||
|
|
|
|||
|
|
| # | 方法 | URL | 说明 |
|
|||
|
|
|:---:|:---:|-----|------|
|
|||
|
|
| 1 | POST | /api/auth/wework-login | 企微 OAuth 登录 → JWT |
|
|||
|
|
| 2 | POST | /api/auth/password-login | 账密登录 → JWT |
|
|||
|
|
| 3 | POST | /api/auth/refresh-token | 刷新 Token |
|
|||
|
|
| 4 | POST | /api/auth/logout | 退出(Token 黑名单) |
|
|||
|
|
|
|||
|
|
### 1.2 智能问答(5 个)
|
|||
|
|
|
|||
|
|
| # | 方法 | URL | 说明 |
|
|||
|
|
|:---:|:---:|-----|------|
|
|||
|
|
| 5 | POST | /api/chat/message | 发送消息(SSE 流式,调 BaoDan Chat API) |
|
|||
|
|
| 6 | GET | /api/chat/sessions | 会话列表(封装 BaoDan API) |
|
|||
|
|
| 7 | POST | /api/chat/sessions | 创建会话 |
|
|||
|
|
| 8 | DELETE | /api/chat/sessions/{id} | 删除会话 |
|
|||
|
|
| 9 | GET | /api/chat/sessions/{id}/messages | 消息记录(含来源引用) |
|
|||
|
|
|
|||
|
|
### 1.3 反馈 + 检索(2 个)
|
|||
|
|
|
|||
|
|
| # | 方法 | URL | 说明 |
|
|||
|
|
|:---:|:---:|-----|------|
|
|||
|
|
| 10 | POST | /api/chat/messages/{id}/feedback | 提交反馈(封装 BaoDan API) |
|
|||
|
|
| 11 | POST | /api/retrieval/search | 向量检索(封装 BaoDan API) |
|
|||
|
|
|
|||
|
|
### 1.4 产品推荐(4 个)
|
|||
|
|
|
|||
|
|
| # | 方法 | URL | 说明 |
|
|||
|
|
|:---:|:---:|-----|------|
|
|||
|
|
| 12 | POST | /api/recommend/generate | 生成方案(调 BaoDan Workflow) |
|
|||
|
|
| 13 | GET | /api/recommend/generate/{task_id} | 查询任务状态 |
|
|||
|
|
| 14 | POST | /api/recommend/{id}/export | 导出 PDF/PPT/Word |
|
|||
|
|
| 15 | POST | /api/recommend/{id}/share | 生成分享链接 |
|
|||
|
|
|
|||
|
|
### 1.5 知识库增强(6 个)
|
|||
|
|
|
|||
|
|
| # | 方法 | URL | 说明 |
|
|||
|
|
|:---:|:---:|-----|------|
|
|||
|
|
| 16 | POST | /api/kb/documents/upload | 上传文档(附标签,调 BaoDan API) |
|
|||
|
|
| 17 | GET | /api/kb/documents | 文档列表(带自定义标签) |
|
|||
|
|
| 18 | GET | /api/kb/documents/{id}/status | 文档处理状态 |
|
|||
|
|
| 19 | PATCH | /api/kb/documents/{id} | 更新元数据(编号/标签) |
|
|||
|
|
| 20 | DELETE | /api/kb/documents/{id} | 删除文档 |
|
|||
|
|
| 21-24 | * | /api/kb/datasources/* | 保司数据源 CRUD + 同步 + 日志(4 个) |
|
|||
|
|
|
|||
|
|
### 1.6 用户权限(3 个)
|
|||
|
|
|
|||
|
|
| # | 方法 | URL | 说明 |
|
|||
|
|
|:---:|:---:|-----|------|
|
|||
|
|
| 25 | CRUD | /api/admin/users | 用户管理(含停用吊销 Token) |
|
|||
|
|
| 26 | POST | /api/admin/users/batch-import | 批量导入 |
|
|||
|
|
| 27 | CRUD | /api/admin/roles | 角色管理 |
|
|||
|
|
|
|||
|
|
### 1.7 系统日志 + 统计(4 个)
|
|||
|
|
|
|||
|
|
| # | 方法 | URL | 说明 |
|
|||
|
|
|:---:|:---:|-----|------|
|
|||
|
|
| 28 | GET | /api/admin/logs/system | 系统操作日志 |
|
|||
|
|
| 29 | GET | /api/stats/overview | 使用概览 |
|
|||
|
|
| 30 | GET | /api/stats/trend | 趋势数据 |
|
|||
|
|
| 31 | GET | /api/stats/kb-health | 知识库健康度 |
|
|||
|
|
|
|||
|
|
### 1.8 企微回调(4 个)
|
|||
|
|
|
|||
|
|
| # | 方法 | URL | 说明 |
|
|||
|
|
|:---:|:---:|-----|------|
|
|||
|
|
| 32 | GET | /api/wecom/callback | 企微 URL 验证 |
|
|||
|
|
| 33 | POST | /api/wecom/callback | 企微消息接收 |
|
|||
|
|
| 34 | GET | /api/wecom/oauth | OAuth 入口 |
|
|||
|
|
| 35 | GET | /api/wecom/oauth/callback | OAuth 回调 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、前端自研页面清单
|
|||
|
|
|
|||
|
|
### 2.1 用户端(5 个页面 + 5 个组件)
|
|||
|
|
|
|||
|
|
| 页面 | 路径 | 说明 | 对应需求 |
|
|||
|
|
|------|------|------|---------|
|
|||
|
|
| LoginPage.vue | /login | 企微 OAuth + 账密登录 | 无(全新) |
|
|||
|
|
| ChatPage.vue | /chat | iframe 嵌入 BaoDan WebApp | M1 |
|
|||
|
|
| ChatFilters.vue | — | 险种/保司筛选器组件 | 1.3.1-1.3.3 |
|
|||
|
|
| ChatCopyButton.vue | — | 复制回答按钮组件 | 1.2.5 |
|
|||
|
|
| RecommendPage.vue | /recommend | 推荐方案表单 + 结果 | M2.1-M2.2 |
|
|||
|
|
| RecommendForm.vue | — | 客户信息表单组件 | 2.1.1-2.1.6 |
|
|||
|
|
| RecommendResult.vue | — | 方案展示组件 | 2.2-2.3 |
|
|||
|
|
| RecommendHistory.vue | /recommend/history | 历史方案列表 | 2.5.1-2.5.4 |
|
|||
|
|
| RecommendDetail.vue | /recommend/detail/:id | 方案详情 + 导出 | 2.3-2.4 |
|
|||
|
|
|
|||
|
|
### 2.2 管理端(6 个页面)
|
|||
|
|
|
|||
|
|
| 页面 | 路径 | 说明 | 对应需求 |
|
|||
|
|
|------|------|------|---------|
|
|||
|
|
| DashboardPage.vue | /admin | 管理后台首页(跳转入口) | — |
|
|||
|
|
| UsersPage.vue | /admin/users | 用户 CRUD + 批量导入 | 5.1-5.2 |
|
|||
|
|
| PermissionsPage.vue | /admin/roles | 角色权限配置 | 5.2 |
|
|||
|
|
| StatsPage.vue | /admin/stats | 数据统计仪表盘 | M7 |
|
|||
|
|
| KBManagePage.vue | /admin/kb | 文档管理 + 标签 + 编号 | 3.1.3-3.1.4 |
|
|||
|
|
| DataSourcePage.vue | /admin/datasource | 保司数据源配置 | 3.3 |
|
|||
|
|
|
|||
|
|
> 注:知识库主界面、对话日志、Prompt 管理、模型配置 → 跳转 BaoDan 后台,不自研。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、数据库表(3 张自研表,已建好)
|
|||
|
|
|
|||
|
|
| 表名 | 用途 | 当前状态 |
|
|||
|
|
|------|------|:---:|
|
|||
|
|
| wecom_user_mapping | 企微用户 ↔ BaoDan 用户映射 | 已建 |
|
|||
|
|
| recommendation_records | 推荐方案记录 | 已建 |
|
|||
|
|
| system_operation_logs | 系统操作审计日志 | 已建 |
|
|||
|
|
|
|||
|
|
可能需要追加的表:
|
|||
|
|
|
|||
|
|
| 表名 | 用途 | 何时建 |
|
|||
|
|
|------|------|--------|
|
|||
|
|
| document_metadata | 文档编号/标签/险种/保司 | Phase 7 KB 增强时 |
|
|||
|
|
| datasource_configs | 保司 API 数据源配置 | Phase 7 KB 增强时 |
|
|||
|
|
| datasource_sync_logs | 同步日志 | Phase 7 KB 增强时 |
|
|||
|
|
| share_tokens | 方案分享链接 Token | Phase 3 产品推荐时 |
|
|||
|
|
| token_blacklist | JWT 黑名单(或用 Redis) | Phase 1 认证时 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、分阶段开发计划
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 0:项目脚手架(0.5 天)
|
|||
|
|
|
|||
|
|
**目标**:BaoDan + 自研代码能跑起来,路由能通。
|
|||
|
|
|
|||
|
|
#### 后端任务
|
|||
|
|
|
|||
|
|
**0.1 创建 insurance/ 模块骨架**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
api/insurance/
|
|||
|
|
├── __init__.py # 空
|
|||
|
|
├── config.py # 配置常量(JWT Secret、企微配置等)
|
|||
|
|
├── utils/
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── response.py # 统一响应封装:success_response() / error_response()
|
|||
|
|
│ ├── auth.py # JWT 签发/校验/装饰器
|
|||
|
|
│ └── db.py # 复用 BaoDan 的 db:from extensions.ext_database import db
|
|||
|
|
├── wecom/
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── routes.py # Blueprint: wecom_bp
|
|||
|
|
│ ├── wecom_bot.py # 消息回调处理
|
|||
|
|
│ ├── wecom_oauth.py # OAuth 登录
|
|||
|
|
│ └── wecom_api.py # 企微 API 封装(发消息/获取 Token)
|
|||
|
|
├── recommend/
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── routes.py # Blueprint: recommend_bp
|
|||
|
|
│ └── workflow_helper.py # BaoDan Workflow 调用封装
|
|||
|
|
├── permissions/
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── routes.py # Blueprint: permissions_bp
|
|||
|
|
│ └── middleware.py # 权限校验中间件
|
|||
|
|
├── stats/
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ └── routes.py # Blueprint: stats_bp
|
|||
|
|
└── db/
|
|||
|
|
├── __init__.py
|
|||
|
|
├── models.py # SQLAlchemy 模型(3 张自研表)
|
|||
|
|
└── init.sql # 建表脚本(已有)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
每个 `routes.py` 先放一个 health check 占位接口。
|
|||
|
|
|
|||
|
|
**0.2 注册路由到 BaoDan**
|
|||
|
|
|
|||
|
|
修改 `baodan-main/api/app_factory.py`(或 `main.py`),在 app 创建后加:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
try:
|
|||
|
|
from insurance.utils.response import InsuranceResponse
|
|||
|
|
from insurance.wecom.routes import wecom_bp
|
|||
|
|
from insurance.recommend.routes import recommend_bp
|
|||
|
|
from insurance.permissions.routes import permissions_bp
|
|||
|
|
from insurance.stats.routes import stats_bp
|
|||
|
|
app.register_blueprint(wecom_bp, url_prefix='/api/wecom')
|
|||
|
|
app.register_blueprint(recommend_bp, url_prefix='/api/recommend')
|
|||
|
|
app.register_blueprint(permissions_bp, url_prefix='/api/admin')
|
|||
|
|
app.register_blueprint(stats_bp, url_prefix='/api/stats')
|
|||
|
|
except ImportError:
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**0.3 修改 BaoDan 前端 iframe 配置**
|
|||
|
|
|
|||
|
|
`web/.env.local` 添加:
|
|||
|
|
```
|
|||
|
|
NEXT_PUBLIC_ALLOW_EMBED=true
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 前端任务
|
|||
|
|
|
|||
|
|
**0.4 确认前端项目能启动**
|
|||
|
|
|
|||
|
|
已有 `package.json`、`router`、`App.vue`。安装依赖后 `pnpm dev` 验证。
|
|||
|
|
|
|||
|
|
**0.5 统一响应拦截器**
|
|||
|
|
|
|||
|
|
确保 `src/utils/api.ts` 的 axios 拦截器处理 `code !== 0` 的情况。
|
|||
|
|
|
|||
|
|
#### 验证标准
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 后端
|
|||
|
|
curl http://localhost:5001/api/health # 返回 {"status":"ok"}
|
|||
|
|
curl http://localhost:5001/api/auth/password-login # 返回参数错误(不是 404)
|
|||
|
|
|
|||
|
|
# 前端
|
|||
|
|
pnpm dev → 浏览器打开 localhost:3000 → 显示登录页
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 1:认证系统(1 天)
|
|||
|
|
|
|||
|
|
**目标**:能登录、能鉴权、Token 能刷新。
|
|||
|
|
|
|||
|
|
#### 后端(0.5 天)
|
|||
|
|
|
|||
|
|
**1.1 config.py — 配置项**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
JWT_SECRET = os.getenv('JWT_SECRET', 'your-secret-key')
|
|||
|
|
JWT_EXPIRE_HOURS = 2
|
|||
|
|
REDIS_TOKEN_PREFIX = 'token:blacklist:'
|
|||
|
|
WECOM_CORP_ID = os.getenv('WECOM_CORP_ID', '')
|
|||
|
|
WECOM_AGENT_SECRET = os.getenv('WECOM_AGENT_SECRET', '')
|
|||
|
|
WECOM_TOKEN = os.getenv('WECOM_TOKEN', '')
|
|||
|
|
WECOM_AES_KEY = os.getenv('WECOM_AES_KEY', '')
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**1.2 utils/auth.py — JWT 工具**
|
|||
|
|
|
|||
|
|
- `generate_token(user_id, username, role, department)` → 签发 JWT
|
|||
|
|
- `decode_token(token)` → 解码 + 校验有效期
|
|||
|
|
- `login_required` 装饰器 → 从 Header 提取 JWT → 解码 → 注入 current_user
|
|||
|
|
- `admin_required` 装饰器 → 额外校验 role in [super_admin, admin]
|
|||
|
|
|
|||
|
|
**1.3 utils/response.py — 统一响应**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def success(data=None, message="success"):
|
|||
|
|
return {"code": 0, "message": message, "data": data}
|
|||
|
|
|
|||
|
|
def error(code, message):
|
|||
|
|
return {"code": code, "message": message, "data": None}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**1.4 POST /api/auth/password-login**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
输入:{ username, password }
|
|||
|
|
处理:
|
|||
|
|
1. 参数校验(3-64字符,8-128字符)
|
|||
|
|
2. 查 wecom_user_mapping 表找用户
|
|||
|
|
3. bcrypt 校验密码(需在用户表加 password_hash 字段)
|
|||
|
|
4. 签发 JWT
|
|||
|
|
5. 记录 system_operation_logs(action=login)
|
|||
|
|
输出:{ token, expires_in, user }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 注意:wecom_user_mapping 表需要加 `password_hash` 字段(ALTER TABLE)。
|
|||
|
|
|
|||
|
|
**1.5 POST /api/auth/refresh-token**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
处理:
|
|||
|
|
1. 校验旧 Token 有效性(未过期、未在黑名单)
|
|||
|
|
2. 签发新 Token
|
|||
|
|
3. 旧 Token 加入 Redis 黑名单(EX 7200)
|
|||
|
|
输出:{ token, expires_in }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**1.6 POST /api/auth/logout**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
处理:
|
|||
|
|
1. 当前 Token 加入 Redis 黑名单
|
|||
|
|
2. 记录操作日志
|
|||
|
|
输出:{ code: 0 }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**1.7 POST /api/auth/wework-login**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
输入:{ code, state }
|
|||
|
|
处理:
|
|||
|
|
1. 用 code 调企微 gettoken API → 拿 access_token
|
|||
|
|
2. 用 access_token + code 调企微 auth/get_user_info → 拿 userid/name/department
|
|||
|
|
3. 查/建 wecom_user_mapping 记录
|
|||
|
|
4. 签发 JWT
|
|||
|
|
输出:{ token, expires_in, user }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 前端(0.5 天)
|
|||
|
|
|
|||
|
|
**1.8 LoginPage.vue**
|
|||
|
|
|
|||
|
|
- 企微登录按钮 → `window.location.href = '/api/wecom/oauth'`
|
|||
|
|
- 账密登录表单 → POST /api/auth/password-login → 存 token → 跳 /chat
|
|||
|
|
- 表单校验:用户名必填,密码必填
|
|||
|
|
|
|||
|
|
**1.9 路由守卫**
|
|||
|
|
|
|||
|
|
- `router.beforeEach` 检查 `localStorage.token`
|
|||
|
|
- 无 token → 跳 /login
|
|||
|
|
|
|||
|
|
**1.10 Token 自动刷新**
|
|||
|
|
|
|||
|
|
- api.ts 拦截器:响应 401 → 尝试 refresh-token → 成功则重试原请求 → 失败跳登录页
|
|||
|
|
|
|||
|
|
#### 验证标准
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 后端
|
|||
|
|
curl -X POST http://localhost:5001/api/auth/password-login \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{"username":"admin","password":"test1234"}'
|
|||
|
|
# → 返回 JWT token
|
|||
|
|
|
|||
|
|
curl -H "Authorization: Bearer <token>" http://localhost:5001/api/auth/refresh-token
|
|||
|
|
# → 返回新 token
|
|||
|
|
|
|||
|
|
curl -H "Authorization: Bearer <old_token>" http://localhost:5001/api/auth/refresh-token
|
|||
|
|
# → 旧 token 已失效
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 2:对话页面(1 天)
|
|||
|
|
|
|||
|
|
**目标**:用户能在 iframe 中跟 BaoDan 对话,筛选器可用。
|
|||
|
|
|
|||
|
|
#### 后端(0.5 天)
|
|||
|
|
|
|||
|
|
**2.1 POST /api/chat/message(SSE 流式)**
|
|||
|
|
|
|||
|
|
这是核心接口,封装 BaoDan Chat API:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
输入:{ session_id, message, filters }
|
|||
|
|
处理:
|
|||
|
|
1. JWT 鉴权
|
|||
|
|
2. 参数校验
|
|||
|
|
3. 根据 filters.险种 选择对应的 BaoDan App(不同险种不同知识库)
|
|||
|
|
- 无险种 → 全库 App
|
|||
|
|
- 重疾险 → 重疾险专用 App
|
|||
|
|
- 以此类推
|
|||
|
|
4. 调 BaoDan Chat API(blocking 模式):
|
|||
|
|
POST http://localhost:5001/v1/chat-messages
|
|||
|
|
Headers: Authorization: Bearer app-xxxxxxxx
|
|||
|
|
Body: { query, user, conversation_id, response_mode: "blocking" }
|
|||
|
|
5. 解析 BaoDan 响应 → 提取 answer + retriever_resources
|
|||
|
|
6. 返回 SSE 流式数据
|
|||
|
|
输出(SSE):
|
|||
|
|
data: {"type":"source","data":{...}}
|
|||
|
|
data: {"type":"delta","data":"根据"}
|
|||
|
|
data: {"type":"done","data":{"message_id":"...","conversation_id":"..."}}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 关键点:BaoDan 本身已有 SSE,我们可以直接用 blocking 模式拿到完整回答后转 SSE,或用 streaming 模式透传。先做 blocking 模式(简单),后续优化为 streaming。
|
|||
|
|
|
|||
|
|
**2.2 GET /api/chat/sessions**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
处理:
|
|||
|
|
1. 调 BaoDan API: GET /v1/conversations?user={user_id}&page=1&limit=20
|
|||
|
|
2. 转换格式为 API 文档定义的结构
|
|||
|
|
输出:{ total, items: [{ id, title, created_at, updated_at, message_count }] }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**2.3 POST /api/chat/sessions**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
处理:调 BaoDan API 创建空会话(或前端直接新建)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**2.4 DELETE /api/chat/sessions/{id}**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
处理:调 BaoDan API 删除会话
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**2.5 GET /api/chat/sessions/{id}/messages**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
处理:调 BaoDan API 获取消息列表 → 转换格式
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 前端(0.5 天)
|
|||
|
|
|
|||
|
|
**2.6 ChatPage.vue**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
结构:
|
|||
|
|
┌─────────────────────────────┐
|
|||
|
|
│ ChatFilters(筛选器) │
|
|||
|
|
├─────────────────────────────┤
|
|||
|
|
│ │
|
|||
|
|
│ iframe(BaoDan WebApp) │
|
|||
|
|
│ src="/baodan/chat/{app_id}" │
|
|||
|
|
│ │
|
|||
|
|
├─────────────────────────────┤
|
|||
|
|
│ ChatCopyButton + Suggestions │
|
|||
|
|
└─────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- ChatEmbed 组件:iframe 加载 BaoDan WebApp
|
|||
|
|
- ChatFilters:险种下拉(7 种)+ 保司下拉(动态加载)
|
|||
|
|
- 选择险种后切换 iframe src 到对应 BaoDan App
|
|||
|
|
|
|||
|
|
**2.7 App.vue 侧边栏**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
左侧导航:
|
|||
|
|
智能问答 → /chat
|
|||
|
|
产品推荐 → /recommend
|
|||
|
|
历史方案 → /recommend/history
|
|||
|
|
────────(管理员以下才显示)
|
|||
|
|
管理后台 → /admin
|
|||
|
|
────────
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- 根据用户 role 控制显示哪些菜单
|
|||
|
|
- 顶部栏:页面标题 + 用户名 + 退出
|
|||
|
|
|
|||
|
|
#### 验证标准
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 浏览器
|
|||
|
|
1. 登录 → 自动跳 /chat
|
|||
|
|
2. iframe 加载出 BaoDan 对话界面
|
|||
|
|
3. 筛选器下拉选择"重疾险"
|
|||
|
|
4. 在 iframe 中提问 → BaoDan 回答
|
|||
|
|
5. 侧边栏点击"产品推荐" → 跳转正常
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 3:产品推荐(2 天)— 最大自研模块
|
|||
|
|
|
|||
|
|
**目标**:填写客户信息 → 生成方案 → 查看结果 → 导出。
|
|||
|
|
|
|||
|
|
#### 后端(1 天)
|
|||
|
|
|
|||
|
|
**3.1 数据模型扩展 — recommendation_records**
|
|||
|
|
|
|||
|
|
确认表结构满足需求,补充 `share_token` 和 `share_expire_at` 字段。
|
|||
|
|
|
|||
|
|
**3.2 POST /api/recommend/generate**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
输入:{ customer, insurance_types, coverage_amount, coverage_period, existing_policies }
|
|||
|
|
处理:
|
|||
|
|
1. JWT 鉴权
|
|||
|
|
2. 参数校验(年龄 1-150、性别 male/female、险种至少 1 项等,见需求文档 13.3 节)
|
|||
|
|
3. INSERT recommendation_records(status=pending)
|
|||
|
|
4. 异步调 BaoDan Workflow API:
|
|||
|
|
POST http://localhost:5001/v1/workflows/run
|
|||
|
|
Headers: Authorization: Bearer app-yyyyyyyyyyyy
|
|||
|
|
Body: { inputs: { age, gender, insurance_types, ... }, response_mode: "blocking", user }
|
|||
|
|
5. 解析 Workflow 输出 → JSON 格式化为 3 套方案(基础/均衡/全面)
|
|||
|
|
6. UPDATE recommendation_records(status=done, generated_plan=...)
|
|||
|
|
7. 记录操作日志
|
|||
|
|
输出:{ task_id, status }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 关键:Workflow 返回的是 Markdown 格式的方案文本,需要在 workflow_helper.py 中解析为结构化 JSON。
|
|||
|
|
|
|||
|
|
**3.3 workflow_helper.py — BaoDan Workflow 调用封装**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def call_recommendation_workflow(customer_info, insurance_types, coverage_amount, coverage_period):
|
|||
|
|
"""
|
|||
|
|
调 BaoDan Workflow API 生成推荐方案
|
|||
|
|
返回: { plans: [{ name, total_premium, items: [...], summary }] }
|
|||
|
|
"""
|
|||
|
|
# 1. 构造 inputs
|
|||
|
|
# 2. POST /v1/workflows/run
|
|||
|
|
# 3. 解析 Markdown 输出 → 结构化 JSON
|
|||
|
|
# 4. 失败处理(超时 120s、Workflow 错误)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**3.4 GET /api/recommend/generate/{task_id}**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
处理:查 recommendation_records 表,返回 status + proposal
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**3.5 POST /api/recommend/{id}/export**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
输入:{ format: "pdf" | "pptx" | "docx" }
|
|||
|
|
处理:
|
|||
|
|
1. 查推荐记录
|
|||
|
|
2. 根据 format 调对应生成器:
|
|||
|
|
- docx: python-docx(先做,最简单)
|
|||
|
|
- pdf: reportlab 或 weasyprint
|
|||
|
|
- pptx: python-pptx
|
|||
|
|
3. 生成文件 → 保存到 /tmp/exports/ 或 OSS
|
|||
|
|
4. 返回下载链接(带临时 token,30 分钟有效)
|
|||
|
|
输出:{ download_url, expire_at }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**3.6 POST /api/recommend/{id}/share**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
处理:
|
|||
|
|
1. 生成随机 token
|
|||
|
|
2. 存 share_tokens 表(含过期时间)
|
|||
|
|
输出:{ share_url, expire_at }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 前端(1 天)
|
|||
|
|
|
|||
|
|
**3.7 RecommendForm.vue — 表单组件**
|
|||
|
|
|
|||
|
|
```vue
|
|||
|
|
结构:
|
|||
|
|
基础信息:姓名 / 年龄 / 性别(radio)/ 健康状况(select)/ 职业
|
|||
|
|
收入预算:年收入(万)/ 月预算(元)
|
|||
|
|
关注险种:checkbox group(寿险/重疾险/医疗险/意外险/年金险/储蓄险)
|
|||
|
|
保障需求:保额(slider + input)/ 保障期限(select)
|
|||
|
|
已有保单:可选折叠区域,动态添加
|
|||
|
|
[生成方案] 按钮
|
|||
|
|
|
|||
|
|
验证规则(见需求文档 13.3 节 + 14 节):
|
|||
|
|
- 年龄:必填,整数 1-150
|
|||
|
|
- 性别:必选
|
|||
|
|
- 职业:必填,1-64 字符
|
|||
|
|
- 月预算:必填,>0
|
|||
|
|
- 险种:至少选 1 项
|
|||
|
|
- 保额:>=1 万
|
|||
|
|
- 保障期限:必选
|
|||
|
|
|
|||
|
|
草稿保存:
|
|||
|
|
- useDraft composable → 自动存 localStorage
|
|||
|
|
- 提交成功后清除草稿
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**3.8 RecommendPage.vue — 主页面**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
结构:
|
|||
|
|
RecommendForm(表单)
|
|||
|
|
↓ 提交后
|
|||
|
|
loading 状态(轮询中...)
|
|||
|
|
↓ 完成后
|
|||
|
|
RecommendResult(结果展示)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
轮询逻辑:
|
|||
|
|
```javascript
|
|||
|
|
// 提交表单 → 拿到 task_id
|
|||
|
|
// setInterval(2s) 轮询 GET /api/recommend/generate/{task_id}
|
|||
|
|
// status=processing → 继续
|
|||
|
|
// status=done → 展示方案
|
|||
|
|
// status=failed → 显示错误
|
|||
|
|
// 超过 60 次轮询 → 超时提示
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**3.9 RecommendResult.vue — 结果展示**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
结构:
|
|||
|
|
三套方案(Collapse 折叠面板):
|
|||
|
|
基础方案 | 均衡方案 | 全面方案
|
|||
|
|
每套方案内:
|
|||
|
|
产品表格(产品名/保额/年保费/推荐理由)
|
|||
|
|
总保费
|
|||
|
|
方案总结
|
|||
|
|
操作栏:[浏览器打印] [重新生成] [导出 PDF] [分享]
|
|||
|
|
免责声明
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**3.10 RecommendHistory.vue — 历史方案列表**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
功能:
|
|||
|
|
分页表格:方案名称 / 客户姓名 / 险种 / 状态 / 创建时间 / 操作
|
|||
|
|
筛选:客户姓名 / 险种 / 时间范围
|
|||
|
|
操作:查看详情 / 导出 / 删除
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**3.11 RecommendDetail.vue — 方案详情**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
功能:
|
|||
|
|
展示完整方案内容
|
|||
|
|
导出按钮(PDF / Word / PPT)
|
|||
|
|
分享按钮 → 生成链接 → 复制
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 验证标准
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 端到端
|
|||
|
|
1. /recommend → 填写客户信息 → 点击"生成方案"
|
|||
|
|
2. 页面显示 loading → 轮询中...
|
|||
|
|
3. ~15 秒后显示 3 套方案
|
|||
|
|
4. 点击"导出 PDF" → 浏览器下载 PDF
|
|||
|
|
5. /recommend/history → 看到刚才生成的方案
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 4:企微集成(1.5 天)
|
|||
|
|
|
|||
|
|
**目标**:企微私聊/群聊能问 BaoDan 问题。
|
|||
|
|
|
|||
|
|
#### 后端
|
|||
|
|
|
|||
|
|
**4.1 wecom_api.py — 企微 API 封装**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
class WeComAPI:
|
|||
|
|
def get_access_token(self):
|
|||
|
|
"""获取企微 access_token,缓存到 Redis(提前 5 分钟刷新)"""
|
|||
|
|
|
|||
|
|
def send_text_message(self, user_id, content):
|
|||
|
|
"""单聊发消息"""
|
|||
|
|
|
|||
|
|
def send_group_message(self, chat_id, content):
|
|||
|
|
"""群聊发消息"""
|
|||
|
|
|
|||
|
|
def send_long_message(self, user_id, content):
|
|||
|
|
"""长消息自动分段发送(>2048字节时分段,间隔500ms)"""
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**4.2 wecom_bot.py — 消息回调处理**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
GET /api/wecom/callback(URL 验证)
|
|||
|
|
1. SHA1(sort([Token, timestamp, nonce, echostr]))
|
|||
|
|
2. 与 msg_signature 比对
|
|||
|
|
3. 验证通过 → 返回解密后的 echostr
|
|||
|
|
|
|||
|
|
POST /api/wecom/callback(消息接收)
|
|||
|
|
1. 立即返回 "success"(5 秒内)
|
|||
|
|
2. 异步处理:
|
|||
|
|
a. 验证签名 + 解密 XML
|
|||
|
|
b. 判断 MsgType:
|
|||
|
|
- text → 继续处理
|
|||
|
|
- image/voice/video/file → 回复"暂不支持该消息类型"
|
|||
|
|
- event → 忽略
|
|||
|
|
c. 群聊消息 → 去掉"@机器人"前缀
|
|||
|
|
d. 查 wecom_user_mapping 获取用户
|
|||
|
|
e. 调 BaoDan Chat API(blocking)
|
|||
|
|
f. 通过企微 API 回复
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 关键:5 秒内必须返回 success。所以用 Flask 的异步机制(threading/queue),先返回再处理。
|
|||
|
|
|
|||
|
|
**4.3 wecom_oauth.py — OAuth 登录**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
GET /api/wecom/oauth
|
|||
|
|
构造企微授权 URL → 302 重定向
|
|||
|
|
|
|||
|
|
GET /api/wecom/oauth/callback
|
|||
|
|
1. 用 code 调企微 API → 获取用户信息
|
|||
|
|
2. 查/建 wecom_user_mapping
|
|||
|
|
3. 签发 JWT
|
|||
|
|
4. 302 重定向到前端(URL 带 token)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**4.4 XML 加解密**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 企微消息加解密(AES-CBC)
|
|||
|
|
# 参考企微官方 SDK 或自行实现
|
|||
|
|
# 核心:decrypt_msg(encrypted_msg) → 明文 XML
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 验证标准
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 模拟企微回调
|
|||
|
|
curl "http://localhost:5001/api/wecom/callback?msg_signature=xxx×tamp=xxx&nonce=xxx&echostr=encrypted_echostr"
|
|||
|
|
# → 返回解密后的 echostr
|
|||
|
|
|
|||
|
|
# 模拟消息推送(用企微调试工具)
|
|||
|
|
# → 机器人回复 AI 回答
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 5:用户权限管理(1 天)
|
|||
|
|
|
|||
|
|
**目标**:管理员能管用户、配角色、数据隔离。
|
|||
|
|
|
|||
|
|
#### 后端
|
|||
|
|
|
|||
|
|
**5.1 用户 CRUD — /api/admin/users**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
GET /api/admin/users → 分页列表(支持 role/department/keyword 筛选)
|
|||
|
|
POST /api/admin/users → 新增用户(插入 wecom_user_mapping)
|
|||
|
|
PUT /api/admin/users/{id} → 编辑(改角色/部门/状态)
|
|||
|
|
DELETE /api/admin/users/{id} → 停用(status=disabled + 吊销所有 Token)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**5.2 批量导入 — /api/admin/users/batch-import**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
POST(multipart/form-data) → 解析 Excel → 批量插入
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**5.3 角色管理 — /api/admin/roles**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
GET /api/admin/roles → 5 个内置角色 + 自定义角色
|
|||
|
|
POST /api/admin/roles → 新建角色(name + permissions 数组)
|
|||
|
|
PUT /api/admin/roles/{id} → 更新权限
|
|||
|
|
DELETE /api/admin/roles/{id} → 删除(内置角色不可删)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**5.4 权限校验中间件 — middleware.py**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 在需要权限的路由上加装饰器:
|
|||
|
|
@require_permission('kb_manage')
|
|||
|
|
def upload_document():
|
|||
|
|
...
|
|||
|
|
|
|||
|
|
# 权限列表:
|
|||
|
|
# chat, proposal, kb_manage, kb_view, log_view, user_manage,
|
|||
|
|
# config_manage, team_stats, system_log
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**5.5 数据权限(5.2.3)**
|
|||
|
|
|
|||
|
|
这是 BaoDan 不具备的核心能力:
|
|||
|
|
```
|
|||
|
|
- 销售(sales) → 只能看自己的数据(推荐记录、对话)
|
|||
|
|
- 主管(manager) → 看本组数据(同 department)
|
|||
|
|
- 管理员(admin) / 超级管理员(super_admin) → 看全部
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
实现方式:在查询接口中自动注入 `WHERE user_id = ?` 或 `WHERE department = ?` 条件。
|
|||
|
|
|
|||
|
|
#### 前端
|
|||
|
|
|
|||
|
|
**5.6 UsersPage.vue**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
功能:
|
|||
|
|
用户表格(分页):用户名/企微ID/角色/部门/状态/操作
|
|||
|
|
新增用户弹窗
|
|||
|
|
编辑用户弹窗
|
|||
|
|
停用确认弹窗
|
|||
|
|
批量导入按钮(上传 Excel)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**5.7 PermissionsPage.vue**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
功能:
|
|||
|
|
左侧:角色列表(可选中)
|
|||
|
|
右侧:权限配置面板(checkbox 分组)
|
|||
|
|
对话:智能问答 / 产品推荐
|
|||
|
|
管理:知识库管理 / 对话日志 / 用户管理 / 数据统计 / 系统日志
|
|||
|
|
[保存权限] 按钮
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 验证标准
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 管理员操作
|
|||
|
|
1. 登录 admin → /admin/users → 看到用户列表
|
|||
|
|
2. 新增一个 sales 角色用户
|
|||
|
|
3. 用新用户登录 → 只能看到 /chat、/recommend
|
|||
|
|
4. 访问 /admin/users → 返回 403
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 6:数据统计(1 天)
|
|||
|
|
|
|||
|
|
**目标**:管理员能看到系统使用数据。
|
|||
|
|
|
|||
|
|
#### 后端
|
|||
|
|
|
|||
|
|
**6.1 GET /api/stats/overview**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
处理:
|
|||
|
|
今日问答数 → 查 BaoDan 对话记录(或自建统计表)
|
|||
|
|
活跃用户数 → 查 wecom_user_mapping 中 last_active_at 在今天内的
|
|||
|
|
知识库命中率 → 查 BaoDan 日志中有 retriever_resources 的比例
|
|||
|
|
文档总数 → 查 BaoDan datasets/documents 数量
|
|||
|
|
输出:{ today_chats, active_users, kb_hit_rate, total_documents }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**6.2 GET /api/stats/trend**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
输入:?metric=chat_count&start_date=2026-05-01&end_date=2026-05-31&granularity=day
|
|||
|
|
处理:按天聚合数据
|
|||
|
|
输出:{ metric, granularity, data: [{ date, value }] }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**6.3 GET /api/stats/kb-health**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
输入:?days=30
|
|||
|
|
处理:
|
|||
|
|
热门问题 TOP20 → 按 query 文本分组计数
|
|||
|
|
未命中问题 → 检索结果 score < 0.5 的问题
|
|||
|
|
文档覆盖率 → 各险种文档数量统计
|
|||
|
|
输出:{ hot_questions, missed_questions, coverage }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 注:热门问题和未命中问题需要在问答接口中记录日志到自研表(或从 BaoDan 日志中聚合)。
|
|||
|
|
|
|||
|
|
#### 前端
|
|||
|
|
|
|||
|
|
**6.4 StatsPage.vue**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
结构:
|
|||
|
|
顶栏:4 个指标卡片(今日问答/活跃用户/命中率/文档数)
|
|||
|
|
中间:趋势折线图(ECharts,7天/30天切换)
|
|||
|
|
底部左:险种分布饼图
|
|||
|
|
底部右:热门问题 TOP20 表格
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 验证标准
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
浏览器打开 /admin/stats → 看到指标卡片 + 图表
|
|||
|
|
(数据量少时可能为空,但页面不报错)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 7:知识库增强(1 天)
|
|||
|
|
|
|||
|
|
**目标**:BaoDan 后台不支持的 KB 功能(编号/标签/数据源)。
|
|||
|
|
|
|||
|
|
#### 后端
|
|||
|
|
|
|||
|
|
**7.1 数据库追加表**
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- 文档元数据(编号、标签、险种、保司)
|
|||
|
|
CREATE TABLE document_metadata (
|
|||
|
|
id SERIAL PRIMARY KEY,
|
|||
|
|
baodan_document_id VARCHAR(64) NOT NULL,
|
|||
|
|
dataset_id VARCHAR(64) NOT NULL,
|
|||
|
|
doc_number VARCHAR(32), -- 编号,如 CJ-XX-001
|
|||
|
|
insurance_type VARCHAR(32), -- 险种
|
|||
|
|
company VARCHAR(64), -- 保司
|
|||
|
|
tags JSONB DEFAULT '[]', -- 自定义标签
|
|||
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 保司 API 数据源配置
|
|||
|
|
CREATE TABLE datasource_configs (
|
|||
|
|
id SERIAL PRIMARY KEY,
|
|||
|
|
name VARCHAR(128) NOT NULL,
|
|||
|
|
api_url VARCHAR(512) NOT NULL,
|
|||
|
|
api_key_encrypted TEXT, -- AES 加密存储
|
|||
|
|
sync_frequency VARCHAR(32), -- CRON 表达式
|
|||
|
|
险种 VARCHAR(32),
|
|||
|
|
last_sync_at TIMESTAMP,
|
|||
|
|
last_sync_status VARCHAR(16),
|
|||
|
|
last_sync_count INTEGER,
|
|||
|
|
status VARCHAR(16) DEFAULT 'active',
|
|||
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 同步日志
|
|||
|
|
CREATE TABLE datasource_sync_logs (
|
|||
|
|
id SERIAL PRIMARY KEY,
|
|||
|
|
datasource_id INTEGER REFERENCES datasource_configs(id),
|
|||
|
|
status VARCHAR(16), -- success/failed
|
|||
|
|
items_added INTEGER DEFAULT 0,
|
|||
|
|
items_updated INTEGER DEFAULT 0,
|
|||
|
|
items_deleted INTEGER DEFAULT 0,
|
|||
|
|
error_message TEXT,
|
|||
|
|
started_at TIMESTAMP DEFAULT NOW(),
|
|||
|
|
completed_at TIMESTAMP
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**7.2 文档管理增强接口**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
POST /api/kb/documents/upload → 上传文档(同时写 document_metadata)
|
|||
|
|
GET /api/kb/documents → 文档列表(JOIN document_metadata 拿编号/标签)
|
|||
|
|
PATCH /api/kb/documents/{id} → 更新编号/标签
|
|||
|
|
GET /api/kb/documents/{id}/status → 处理状态
|
|||
|
|
DELETE /api/kb/documents/{id} → 删除文档
|
|||
|
|
POST /api/kb/documents/{id}/retry → 重试
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**7.3 保司数据源接口**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
GET /api/kb/datasources → 数据源列表
|
|||
|
|
POST /api/kb/datasources → 新建数据源
|
|||
|
|
POST /api/kb/datasources/{id}/sync → 手动同步(异步)
|
|||
|
|
GET /api/kb/datasources/{id}/logs → 同步日志
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**7.4 编号自动生成规则**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def generate_doc_number(insurance_type, company):
|
|||
|
|
"""
|
|||
|
|
规则:险种代码-保司代码-序号
|
|||
|
|
例:CJ-XX-001(重疾险-XX人寿-第1个文档)
|
|||
|
|
险种代码:CJ=重疾, RS=寿险, YL=医疗, YW=意外, CX=车险, NJ=年金, CX=储蓄
|
|||
|
|
"""
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 前端
|
|||
|
|
|
|||
|
|
**7.5 KBManagePage.vue**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
功能:
|
|||
|
|
文档列表表格(分页):编号/文件名/险种/保司/标签/状态/操作
|
|||
|
|
上传文档弹窗(多文件 + 选择险种 + 填写保司)
|
|||
|
|
编辑元数据弹窗(修改编号、标签)
|
|||
|
|
删除确认
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**7.6 DataSourcePage.vue**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
功能:
|
|||
|
|
数据源列表表格:名称/URL/同步频率/上次同步/状态/操作
|
|||
|
|
新建数据源弹窗
|
|||
|
|
[立即同步] 按钮 → 显示同步进度
|
|||
|
|
同步日志查看
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 验证标准
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
1. /admin/kb → 上传一个 MD 文件 → 选择险种 → 看到文档在列表中
|
|||
|
|
2. 点编辑 → 修改编号为 CJ-XX-001 → 保存成功
|
|||
|
|
3. /admin/datasource → 新建一个数据源 → 点击"立即同步"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 8:导出 + 日志 + 收尾(0.5 天)
|
|||
|
|
|
|||
|
|
#### 导出功能
|
|||
|
|
|
|||
|
|
**8.1 PDF 导出**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 使用 reportlab 或 weasyprint
|
|||
|
|
# 按模板渲染推荐方案 → 生成 PDF
|
|||
|
|
# 需要客户提供 PDF 模板(或先用简单模板)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**8.2 Word 导出**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 使用 python-docx
|
|||
|
|
# 最简单的导出方式,优先实现
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**8.3 PPT 导出**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 使用 python-pptx
|
|||
|
|
# 按模板生成 PPT(需要客户提供模板)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 系统日志
|
|||
|
|
|
|||
|
|
**8.4 system_operation_logs 记录**
|
|||
|
|
|
|||
|
|
在以下操作时自动写入:
|
|||
|
|
- 登录/登出
|
|||
|
|
- 文档上传/删除
|
|||
|
|
- 角色权限变更
|
|||
|
|
- 推荐方案生成
|
|||
|
|
|
|||
|
|
#### 通知告警(可选)
|
|||
|
|
|
|||
|
|
**8.5 企微 Webhook 通知**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def send_alert(message):
|
|||
|
|
"""通过企微机器人 Webhook 发送告警"""
|
|||
|
|
webhook_url = config.WECOM_WEBHOOK_URL
|
|||
|
|
requests.post(webhook_url, json={"msgtype": "text", "text": {"content": message}})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
告警场景:
|
|||
|
|
- 数据源同步失败
|
|||
|
|
- Token 月消耗超预算
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、依赖安装清单
|
|||
|
|
|
|||
|
|
### 后端(Python)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
PyJWT==2.* # JWT 签发
|
|||
|
|
bcrypt==4.* # 密码哈希
|
|||
|
|
python-docx==1.* # Word 导出
|
|||
|
|
reportlab==4.* # PDF 导出(可选)
|
|||
|
|
python-pptx==1.* # PPT 导出(可选)
|
|||
|
|
openpyxl==3.* # Excel 批量导入
|
|||
|
|
lxml==5.* # XML 解析(企微消息)
|
|||
|
|
cryptography==43.* # AES 加解密(企微消息 + API Key)
|
|||
|
|
celery==5.* # 异步任务(企微消息处理、文档同步)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 大部分依赖 BaoDan 已有(Flask、SQLAlchemy、Redis),不需要重复安装。
|
|||
|
|
|
|||
|
|
### 前端(Node)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
vue@3
|
|||
|
|
vue-router@4
|
|||
|
|
element-plus
|
|||
|
|
axios
|
|||
|
|
marked # Markdown 渲染
|
|||
|
|
echarts # 统计图表
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、风险与应对
|
|||
|
|
|
|||
|
|
| 风险 | 影响 | 应对 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| BaoDan Workflow 输出格式不稳定 | 推荐方案解析失败 | 在 workflow_helper.py 中加容错解析 + fallback |
|
|||
|
|
| 企微消息加解密实现复杂 | 回调不通 | 参考企微官方 Python SDK(wxwork-sdk) |
|
|||
|
|
| 9GB 知识库上传慢 | 首次导入耗时长 | 分批上传 + 异步处理 + 进度反馈 |
|
|||
|
|
| BaoDan 版本升级破坏接口 | 自研代码不可用 | 只改 main.py + app_factory.py,insurance/ 独立 |
|
|||
|
|
| 一人开发工期紧 | 10 天可能不够 | Phase 7-8 可推后,Phase 0-5 是 MVP |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、MVP 交付标准
|
|||
|
|
|
|||
|
|
Phase 0-5 完成后即可进入测试:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
✅ 能登录(企微 + 账密)
|
|||
|
|
✅ 能在 iframe 中跟 BaoDan 对话
|
|||
|
|
✅ 能筛选险种
|
|||
|
|
✅ 能填写客户信息生成推荐方案
|
|||
|
|
✅ 能查看历史方案
|
|||
|
|
✅ 企微私聊能问答
|
|||
|
|
✅ 管理员能管用户和角色
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Phase 6-8 为增强功能,可并行测试:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
⏳ 数据统计仪表盘
|
|||
|
|
⏳ 知识库编号/标签管理
|
|||
|
|
⏳ 保司数据源同步
|
|||
|
|
⏳ PDF/Word 导出
|
|||
|
|
⏳ 系统操作日志
|
|||
|
|
```
|