baodan/docs/后续开发计划.md

678 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 保险智能客服系统 — 后续开发计划
> **文档版本**V1.0
> **更新日期**2026-06-25
> **当前状态**:后端框架完成,核心功能完成 64%,产品推荐功能待实现
> **预计工期**2-3 个工作日
---
## 一、当前项目状态
### 1.1 已完成功能64%
| 模块 | 功能 | 状态 | 备注 |
|------|------|:----:|------|
| **认证系统** | 企微 OAuth 登录 | ✅ | 需配置真实企微 |
| | 账密登录 | ✅ | admin/admin123456 |
| | Token 刷新 | ✅ | |
| | 退出登录 | ✅ | |
| **对话功能** | iframe 嵌入 BaoDan | ✅ | |
| | 险种筛选 | ✅ | 7 种险种 |
| | 会话管理 | ✅ | |
| **用户管理** | 用户 CRUD | ✅ | |
| | 角色权限 | ✅ | 5 种内置角色 |
| | 权限校验中间件 | ✅ | |
| **知识库** | 文档上传/列表/删除 | ✅ | 调用 BaoDan API |
| | 文档状态查询 | ✅ | |
| | 数据源 CRUD | ✅ | |
| **统计报表** | 使用概览 | ✅ | 占位数据 |
| | 趋势数据 | ✅ | 占位数据 |
| | 知识库健康度 | ✅ | 占位数据 |
| | Token 消耗 | ✅ | 占位数据 |
| **系统管理** | 方案模板管理 | ✅ | |
| | 通知告警配置 | ✅ | |
| | 分组管理 | ✅ | |
| | Prompt 管理 | ✅ | |
| | 登录日志 | ✅ | |
| | 对话记录 | ✅ | |
| **导出功能** | PDF 导出 | ✅ | |
| | Word 导出 | ✅ | |
### 1.2 未完成功能36%
| 模块 | 功能 | 优先级 | 工作量 |
|------|------|:------:|:------:|
| **产品推荐** | BaoDan Workflow 配置 | 🔴 高 | 0.5 天 |
| | Workflow 调用封装 | 🔴 高 | 0.5 天 |
| | 产品推荐 API 联调 | 🔴 高 | 0.5 天 |
| **用户管理** | 批量导入用户 | 🟡 中 | 0.5 天 |
| | 数据权限过滤 | 🟡 中 | 0.5 天 |
| **知识库** | 文档编号自动生成 | 🟢 低 | 0.2 天 |
| **企微集成** | XML 加解密 | 🟡 中 | 0.5 天 |
| **测试** | 功能测试 | 🔴 高 | 1 天 |
---
## 二、后续开发计划
### Phase 2.5BaoDan Workflow 配置0.5 天)
**目标**:在 Dify 后台配置产品推荐 Workflow
#### 任务清单
| # | 任务 | 说明 | 验证标准 |
|---|------|------|----------|
| W.1 | 创建 Workflow 应用 | 在 Dify 后台创建新的 Workflow 应用 | 应用创建成功 |
| W.2 | 配置节点1参数校验 | Code Node校验输入参数 | 传入合法参数通过 |
| W.3 | 配置节点2检索策略生成 | Code Node根据险种生成检索策略 | 输出检索策略 JSON |
| W.4 | 配置节点3知识库检索 | Knowledge Retrieval Node | 返回相关文档 |
| W.5 | 配置节点4LLM 方案生成 | LLM Node生成推荐方案 | 输出 Markdown 方案 |
| W.6 | 配置节点5异常处理 | Code Node处理异常情况 | 异常时返回友好提示 |
| W.7 | 配置节点6格式化输出 | Code Node格式化为 JSON | 输出结构化方案 |
| W.8 | 配置条件分支 | 根据险种类型分支处理 | 分支逻辑正确 |
| W.9 | 测试验证 | 端到端测试 | 输入客户信息 → 输出 3 套方案 |
#### Workflow 节点设计
```
开始
[节点1] 参数校验 (Code Node)
[节点2] 检索策略生成 (Code Node)
[节点3] 知识库检索 (Knowledge Retrieval Node)
[节点4] LLM 方案生成 (LLM Node)
[节点5] 异常处理 (Code Node)
[节点6] 格式化输出 (Code Node)
结束
```
#### 输入参数
```json
{
"customer_name": "张三",
"customer_age": 30,
"customer_gender": "male",
"health_status": "健康",
"occupation": "工程师",
"annual_income": 300000,
"monthly_budget": 5000,
"insurance_types": ["重疾险", "医疗险"],
"coverage_amount": 500000,
"coverage_period": "至80岁",
"existing_policies": []
}
```
#### 输出格式
```json
{
"status": "done",
"proposal": {
"customer_name": "张三",
"plans": [
{
"name": "基础方案",
"total_premium": 12000,
"items": [
{
"product_name": "XX重疾险",
"coverage_amount": 300000,
"annual_premium": 8000,
"recommend_reason": "性价比高,保障全面"
}
],
"summary": "适合预算有限的客户"
},
{
"name": "均衡方案",
"total_premium": 18000,
"items": [...],
"summary": "保障与价格平衡"
},
{
"name": "全面方案",
"total_premium": 25000,
"items": [...],
"summary": "保障最全面"
}
],
"disclaimer": "以上方案仅供参考,具体以保险合同为准"
}
}
```
---
### Phase 3.1:产品推荐后端 API0.5 天)
**目标**:实现产品推荐相关的后端 API
#### 任务清单
| # | 任务 | API | 说明 |
|---|------|-----|------|
| 3.1.1 | 数据库扩展 | - | 添加 share_token 等字段 |
| 3.1.2 | Workflow 调用封装 | - | 封装 Dify Workflow API |
| 3.1.3 | 生成方案 API | POST /recommend/generate | 调用 Workflow |
| 3.1.4 | 查询状态 API | GET /recommend/generate/{task_id} | 轮询任务状态 |
| 3.1.5 | 导出方案 API | POST /recommend/{id}/export | PDF/Word 导出 |
| 3.1.6 | 分享链接 API | POST /recommend/{id}/share | 生成分享链接 |
#### 3.1.1 数据库扩展
```sql
-- 添加分享相关字段
ALTER TABLE recommendation_records
ADD COLUMN IF NOT EXISTS share_token VARCHAR(64),
ADD COLUMN IF NOT EXISTS share_expire_at TIMESTAMP;
```
#### 3.1.2 Workflow 调用封装
**文件**`api/insurance/recommend/workflow_helper.py`
```python
"""BaoDan Workflow 调用封装。"""
import requests
from flask import current_app
class WorkflowHelper:
"""Workflow API 调用封装。"""
def run_workflow(self, inputs: dict, user_id: str) -> dict:
"""
执行 Workflow 获取推荐方案。
Args:
inputs: 客户信息和保险需求
user_id: 用户 ID
Returns:
Workflow 执行结果
"""
base_url = current_app.config.get("BAODAN_API_URL", "http://localhost:5001")
api_key = current_app.config.get("BAODAN_WORKFLOW_API_KEY", "")
resp = requests.post(
f"{base_url}/v1/workflows/run",
json={
"inputs": inputs,
"response_mode": "blocking",
"user": f"recommend_{user_id}",
},
headers={"Authorization": f"Bearer {api_key}"},
timeout=120,
)
return resp.json()
```
#### 3.1.3 生成方案 API
**文件**`api/insurance/recommend/routes.py`
```python
@recommend_bp.route("/generate", methods=["POST"])
@jwt_required
def generate():
"""生成推荐方案。"""
data = request.get_json()
if not data:
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
user_id = request.user_id
# 参数校验(见需求文档 §13.3
errors = self._validate_params(data)
if errors:
return jsonify({"code": 1001, "message": "; ".join(errors), "data": None}), 400
# 创建推荐记录
from insurance.recommend.service import RecommendService
service = RecommendService()
result = service.create_proposal(user_id, data)
if result["code"] != 0:
return jsonify(result), 400
task_id = result["data"]["task_id"]
# 异步调用 Workflow
import threading
threading.Thread(
target=self._run_workflow_async,
args=(task_id, data, user_id),
daemon=True,
).start()
return jsonify({"code": 0, "data": {"task_id": task_id, "status": "processing"}})
```
#### 3.1.4 查询状态 API
```python
@recommend_bp.route("/generate/<task_id>", methods=["GET"])
@jwt_required
def get_status(task_id):
"""查询推荐任务状态。"""
from insurance.recommend.service import RecommendService
service = RecommendService()
result = service.get_proposal_status(task_id)
return jsonify(result)
```
#### 3.1.5 导出方案 API
```python
@recommend_bp.route("/<proposal_id>/export", methods=["POST"])
@jwt_required
def export_proposal(proposal_id):
"""导出推荐方案。"""
data = request.get_json()
format_type = data.get("format", "pdf") # pdf / docx
from insurance.recommend.service import RecommendService
service = RecommendService()
result = service.export_proposal(proposal_id, format_type)
if result["code"] != 0:
return jsonify(result), 400
return jsonify(result)
```
#### 3.1.6 分享链接 API
```python
@recommend_bp.route("/<proposal_id>/share", methods=["POST"])
@jwt_required
def share_proposal(proposal_id):
"""生成分享链接。"""
from insurance.recommend.service import RecommendService
service = RecommendService()
result = service.create_share_link(proposal_id)
return jsonify(result)
```
---
### Phase 3.2产品推荐前端联调0.5 天)
**目标**:联调前端与后端 API
#### 已有前端文件
| 文件 | 说明 | 状态 |
|------|------|:----:|
| RecommendPage.vue | 推荐主页面 | ✅ 已存在 |
| RecommendForm.vue | 客户信息表单 | ✅ 已存在 |
| RecommendResult.vue | 方案展示组件 | ✅ 已存在 |
| RecommendHistory.vue | 历史方案列表 | ✅ 已存在 |
| RecommendDetail.vue | 方案详情页 | ✅ 已存在 |
#### 需要修改的文件
| 文件 | 修改内容 | 工作量 |
|------|----------|:------:|
| RecommendPage.vue | 联调 generate API | 0.2 天 |
| RecommendResult.vue | 适配后端返回格式 | 0.2 天 |
| RecommendHistory.vue | 联调 list API | 0.1 天 |
| RecommendDetail.vue | 联调 export/share API | 0.1 天 |
#### RecommendPage.vue 联调逻辑
```typescript
async function onSubmit(formData: RecommendRequest) {
loading.value = true
generating.value = true
result.value = null
try {
// 1. 提交生成请求
const submitRes = await api.post('/recommend/generate', formData)
const taskId = submitRes.data.task_id
// 2. 轮询状态
let retries = 0
const maxRetries = 60
while (retries < maxRetries) {
await new Promise(r => setTimeout(r, 2000))
const pollRes = await api.get(`/recommend/generate/${taskId}`)
const task = pollRes.data
if (task.status === 'done') {
result.value = task
ElMessage.success('方案生成成功')
return
}
if (task.status === 'failed') {
ElMessage.error(task.error_message || '方案生成失败')
return
}
retries++
}
ElMessage.warning('生成超时,请稍后在历史方案中查看')
} catch {
// 错误已由 api 拦截器处理
} finally {
loading.value = false
generating.value = false
}
}
```
---
### Phase 5.1批量导入用户0.5 天)
**目标**:支持 Excel 批量导入用户
#### 任务清单
| # | 任务 | 说明 |
|---|------|------|
| 5.1.1 | 后端 API | POST /admin/users/batch-import |
| 5.1.2 | Excel 解析 | 使用 openpyxl 解析 Excel |
| 5.1.3 | 批量插入 | 批量插入用户记录 |
| 5.1.4 | 前端上传 | UsersPage 添加导入按钮 |
#### 后端实现
```python
@bp.route("/users/batch-import", methods=["POST"])
@super_admin_required
def batch_import_users():
"""批量导入用户。"""
file = request.files.get("file")
if not file:
return jsonify({"code": 1001, "message": "请选择文件", "data": None}), 400
# 解析 Excel
import openpyxl
wb = openpyxl.load_workbook(file)
ws = wb.active
users = []
for row in ws.iter_rows(min_row=2, values_only=True):
username, department, role = row[0], row[1], row[2]
if username:
users.append({
"username": username,
"department": department or "",
"role": role or "sales",
})
# 批量插入
from insurance.admin.service import AdminService
service = AdminService()
result = service.batch_create_users(users)
return jsonify(result)
```
#### 前端实现
```vue
<!-- UsersPage.vue -->
<el-upload
:action="'/insurance/admin/users/batch-import'"
:headers="uploadHeaders"
:on-success="onImportSuccess"
:on-error="onImportError"
accept=".xlsx,.xls"
:show-file-list="false"
>
<el-button>批量导入</el-button>
</el-upload>
```
---
### Phase 5.2数据权限过滤0.5 天)
**目标**:实现销售只看自己的数据,主管看本组数据
#### 任务清单
| # | 任务 | 说明 |
|---|------|------|
| 5.2.1 | 数据权限中间件 | get_data_scope() 已实现 |
| 5.2.2 | 推荐记录过滤 | 根据权限过滤推荐记录 |
| 5.2.3 | 对话记录过滤 | 根据权限过滤对话记录 |
#### 实现逻辑
```python
# 在查询接口中注入数据权限
def get_proposals(user_id, params):
"""获取推荐记录列表(带数据权限)。"""
from insurance.middleware.auth_middleware import get_data_scope
scope = get_data_scope()
query = db.session.query(RecommendationRecord)
if scope["scope"] == "self":
# 销售:只看自己的
query = query.filter(RecommendationRecord.user_id == user_id)
elif scope["scope"] == "team":
# 主管:看本部门的
query = query.filter(
RecommendationRecord.user_id.in_(
db.session.query(WeComUserMapping.id).filter(
WeComUserMapping.department == scope["department"]
)
)
)
# admin/super_admin看全部
return query.all()
```
---
### Phase 7.1文档编号自动生成0.2 天)
**目标**:文档上传时自动生成编号
#### 编号规则
```
格式:{险种代码}-{保司代码}-{序号}
示例CJ-XX-001重疾险-XX人寿-第1个文档
险种代码:
- CJ = 重疾险
- RS = 寿险
- YL = 医疗险
- YW = 意外险
- CX = 车险
- NJ = 年金险
- CX = 储蓄险
```
#### 实现
```python
def generate_doc_number(insurance_type: str, company: str) -> str:
"""生成文档编号。"""
type_codes = {
"重疾险": "CJ", "寿险": "RS", "医疗险": "YL",
"意外险": "YW", "车险": "CX", "年金险": "NJ", "储蓄险": "CX",
}
type_code = type_codes.get(insurance_type, "XX")
company_code = company[:2] if company else "XX"
# 查询当前序号
count = db.session.query(DocumentMetadata).filter(
DocumentMetadata.insurance_type == insurance_type,
DocumentMetadata.company == company,
).count()
return f"{type_code}-{company_code}-{count + 1:03d}"
```
---
### Phase 8.1功能测试1 天)
**目标**:验证所有功能正常工作
#### 测试清单
| # | 测试项 | 测试用例 | 验证标准 |
|---|--------|----------|----------|
| X.1 | 登录 | 账密登录 | 返回 token可访问受保护页面 |
| X.2 | 登录 | 企微 OAuth | 重定向到企微授权页 |
| X.3 | 对话 | 发送消息 | 返回 AI 回答 |
| X.4 | 对话 | 险种筛选 | 切换险种后对话正常 |
| X.5 | 推荐 | 生成方案 | 返回 3 套方案 |
| X.6 | 推荐 | 导出 PDF | 下载 PDF 文件 |
| X.7 | 用户 | 新增用户 | 用户列表增加 |
| X.8 | 用户 | 角色权限 | 非管理员无法访问 /admin |
| X.9 | 知识库 | 上传文档 | 文档出现在列表 |
| X.10 | 统计 | 查看仪表盘 | 显示数据 |
---
## 三、开发时间表
### 第 1 天产品推荐核心1.5 天工作量)
| 时间 | 任务 | 产出 |
|------|------|------|
| 上午 | Phase 2.5: Workflow 配置 | Workflow 应用创建完成 |
| 下午 | Phase 3.1: 后端 API | generate/status/export/share API |
| 晚上 | Phase 3.2: 前端联调 | 推荐页面可正常使用 |
### 第 2 天增强功能1.5 天工作量)
| 时间 | 任务 | 产出 |
|------|------|------|
| 上午 | Phase 5.1: 批量导入 | Excel 导入功能 |
| 下午 | Phase 5.2: 数据权限 | 销售/主管数据隔离 |
| 晚上 | Phase 7.1: 文档编号 | 自动编号功能 |
### 第 3 天:测试 + 部署1 天工作量)
| 时间 | 任务 | 产出 |
|------|------|------|
| 上午 | Phase 8.1: 功能测试 | 测试报告 |
| 下午 | 部署 + 文档 | 生产环境部署 |
---
## 四、文件变更清单
### 后端文件
| 文件 | 操作 | 说明 |
|------|:----:|------|
| api/insurance/recommend/workflow_helper.py | 修改 | 封装 Workflow 调用 |
| api/insurance/recommend/routes.py | 修改 | 完善 generate/status/export/share |
| api/insurance/recommend/service.py | 修改 | 实现业务逻辑 |
| api/insurance/admin/routes.py | 修改 | 添加 batch-import |
| api/insurance/admin/service.py | 修改 | 实现批量导入 |
| api/insurance/kb/service.py | 修改 | 添加编号生成 |
### 前端文件
| 文件 | 操作 | 说明 |
|------|:----:|------|
| frontend/src/pages/RecommendPage.vue | 修改 | 联调 generate API |
| frontend/src/pages/RecommendResult.vue | 修改 | 适配返回格式 |
| frontend/src/pages/RecommendHistory.vue | 修改 | 联调 list API |
| frontend/src/pages/admin/UsersPage.vue | 修改 | 添加导入按钮 |
---
## 五、配置变更
### docker-compose.dify.yml
```yaml
# 更新 Workflow API Key从 Dify 后台获取)
BAODAN_WORKFLOW_API_KEY: "app-real-workflow-api-key"
```
### 数据库变更
```sql
-- 添加分享字段
ALTER TABLE recommendation_records
ADD COLUMN IF NOT EXISTS share_token VARCHAR(64),
ADD COLUMN IF NOT EXISTS share_expire_at TIMESTAMP;
```
---
## 六、验收标准
### 功能验收
| # | 功能 | 验收标准 |
|---|------|----------|
| 1 | 登录 | 账密/企微登录正常 |
| 2 | 对话 | iframe 嵌入 BaoDan可对话 |
| 3 | 推荐 | 填写表单 → 生成 3 套方案 |
| 4 | 导出 | 方案可导出 PDF/Word |
| 5 | 用户管理 | CRUD + 角色权限正常 |
| 6 | 知识库 | 文档上传/列表正常 |
| 7 | 统计 | 仪表盘显示数据 |
### 性能验收
| # | 指标 | 标准 |
|---|------|------|
| 1 | 登录响应 | < 2 |
| 2 | 对话响应 | < 5 |
| 3 | 推荐生成 | < 30 |
| 4 | 页面加载 | < 3 |
---
## 七、风险与应对
| 风险 | 影响 | 应对措施 |
|------|------|----------|
| Workflow 配置复杂 | 推荐功能无法使用 | 参考 Dify 官方文档逐步配置 |
| Workflow 输出格式不稳定 | 方案解析失败 | workflow_helper.py 中加容错解析 |
| 企微 XML 加解密 | 消息回调不通 | 参考企微官方 Python SDK |
| 测试时间不足 | 部署后出现问题 | 优先测试核心功能 |
---
## 八、总结
### 工作量估算
| 任务 | 工作量 | 优先级 |
|------|:------:|:------:|
| Workflow 配置 | 0.5 | 🔴 |
| 产品推荐 API | 0.5 | 🔴 |
| 前端联调 | 0.5 | 🔴 |
| 批量导入 | 0.5 | 🟡 |
| 数据权限 | 0.5 | 🟡 |
| 文档编号 | 0.2 | 🟢 |
| 功能测试 | 1 | 🔴 |
| **总计** | **3.2 天** | |
### 交付物
1. 完整的产品推荐功能Workflow + API + 前端
2. 批量导入用户功能
3. 数据权限过滤
4. 文档编号自动生成
5. 功能测试报告
6. 部署文档