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

678 lines
19 KiB
Markdown
Raw Normal View History

# 保险智能客服系统 — 后续开发计划
> **文档版本**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. 部署文档