bea288e414
== 已部署上线 (9项) == - 代办事项真实数据源集成 (企微审批API 8bug修复链) - H5/坐席端 Logo样式统一+绿色背景 - 视频引导页修复 (localStorage key v2) - 坐席端 v9 Vue版本修复 (ElMessage._context) - 截图按钮 v10 修复 (getDisplayMedia user gesture) - 扫码样式恢复+H5扫码登录跳转修复 - H5截图快捷键提示 == 代码完成待部署 (3项) == - 知识迭代3Bug修复 (#8 POST端点/#7 MERGE幂等/#6 过期检查) - 会议室预定-小鱼易联终端 (40文件, 40/40测试通过) - IT资产升级审批推送 (asset_service.py) == 需求文档 (2项) == - 坐席端AI辅助消息框-PRD (4项新功能确认) - 坐席端布局优化建议 v2.0 (7天计划) == 新增文档 == - 日报-2026-07-11.md - 知识迭代Bug修复报告-20260711.md - 会议室预定-部署指南.md - CHANGELOG.md 更新 == 测试 == - test_todo_integration.py: 40/40 - test_meetingroom.py: 40/40 - test_bugfix_ki_suggestions.py: 21/21
214 lines
7.6 KiB
Plaintext
214 lines
7.6 KiB
Plaintext
# 业务路由推荐 — 类图
|
||
|
||
> 数据模型 + 服务类 + API 类的完整定义
|
||
|
||
```mermaid
|
||
classDiagram
|
||
direction LR
|
||
|
||
%% ===== 数据模型 =====
|
||
class BusinessContact {
|
||
+id: int
|
||
+name: str
|
||
+gender: str
|
||
+department: str
|
||
+position: str
|
||
+responsibility: str
|
||
+extension: str
|
||
+service_area: str
|
||
+wecom_userid: str
|
||
+avatar_url: str
|
||
+business_category: str
|
||
+is_active: bool
|
||
+created_at: datetime
|
||
+updated_at: datetime
|
||
}
|
||
|
||
class RoutingEvent {
|
||
+id: int
|
||
+conversation_id: str
|
||
+employee_id: str
|
||
+message_content: str
|
||
+business_category: str
|
||
+routing_confidence: float
|
||
+contact_id: int
|
||
+contact_name: str
|
||
+is_clicked: bool
|
||
+created_at: datetime
|
||
}
|
||
|
||
%% ===== 服务类 =====
|
||
class RoutingService {
|
||
-ROUTING_PREFILTER_KEYWORDS: list~str~
|
||
-ROUTING_KEYWORD_TO_CATEGORY: dict~str, str~
|
||
-ROUTING_CONFIDENCE_THRESHOLD: float
|
||
+keyword_prefilter(text: str) bool
|
||
+async detect_routing_intent(text: str, employee_id: str) dict
|
||
-async _call_dify_unified_intent(text: str, employee_id: str) dict
|
||
-_fallback_routing_detect(text: str) tuple
|
||
+async get_contact_by_category(category: str, db: AsyncSession) BusinessContact
|
||
+async get_contacts(category: str, keyword: str, db: AsyncSession) list~BusinessContact~
|
||
+async send_contact_card(db, conversation, employee_id, contact, reason) Message
|
||
-async _create_routing_text_message(db, conversation, reason, category) Message
|
||
-async _create_system_hint_message(db, conversation) Message
|
||
+async record_routing_event(db, conversation_id, employee_id, content, category, confidence, contact) RoutingEvent
|
||
-async _push_via_ws(employee_id, conversation, messages) None
|
||
}
|
||
|
||
%% ===== API 类 =====
|
||
class RoutingAPI {
|
||
+GET /api/h5/routing/contact
|
||
+GET /api/routing/contacts
|
||
+POST /api/conversations/{id}/send-contact-card
|
||
}
|
||
|
||
class ApprovalAPI {
|
||
+POST /api/approval/detect-intent
|
||
-async _call_dify_approval_intent(text, employee_id) dict
|
||
}
|
||
|
||
%% ===== Schema 类 =====
|
||
class ApprovalDetectIntentResponse {
|
||
+is_approval_request: bool
|
||
+confidence: float
|
||
+approval_type: str|None
|
||
+source: str
|
||
+intent_type: str
|
||
+business_category: str|None
|
||
+routing_confidence: float
|
||
}
|
||
|
||
class ContactCardResponse {
|
||
+id: int
|
||
+name: str
|
||
+gender: str
|
||
+department: str
|
||
+position: str
|
||
+responsibility: str
|
||
+extension: str
|
||
+service_area: str
|
||
+wecom_userid: str
|
||
+avatar_url: str
|
||
+business_category: str
|
||
}
|
||
|
||
class SendContactCardRequest {
|
||
+contact_id: int
|
||
+reason: str
|
||
}
|
||
|
||
%% ===== 现有类(引用) =====
|
||
class Message {
|
||
+id: str
|
||
+conversation_id: str
|
||
+sender_type: str
|
||
+msg_type: str
|
||
+content: str
|
||
+extra_data: dict
|
||
}
|
||
|
||
class H5AiTask {
|
||
+async process_h5_ai_reply(conversation_id, employee_id, content, dify_conversation_id)
|
||
-async _handle_routing(db, conversation, employee_id, content) bool
|
||
-async _handle_byod_query(db, conversation, employee_id, content)
|
||
-async _persist_and_push(db, conversation, employee_id, content, ...)
|
||
}
|
||
|
||
class WSManager {
|
||
+async broadcast(data: dict)
|
||
+async broadcast_to_employees(employee_ids: list~str~, data: dict)
|
||
}
|
||
|
||
class DifyAPI {
|
||
POST /v1/chat-messages
|
||
+inputs: dict
|
||
+query: str
|
||
+response_mode: "blocking"
|
||
+user: str
|
||
}
|
||
|
||
%% ===== 关系 =====
|
||
BusinessContact "1" --> RoutingEvent : contact_id FK
|
||
|
||
RoutingService --> BusinessContact : 查询/创建
|
||
RoutingService --> RoutingEvent : 记录
|
||
RoutingService --> Message : 创建contact_card消息
|
||
RoutingService --> WSManager : WS推送
|
||
RoutingService --> DifyAPI : 调用统一意图识别
|
||
RoutingService ..> ApprovalDetectIntentResponse : 解析响应
|
||
|
||
RoutingAPI --> RoutingService : 调用
|
||
RoutingAPI ..> ContactCardResponse : 返回
|
||
RoutingAPI ..> SendContactCardRequest : 接收
|
||
|
||
ApprovalAPI ..> ApprovalDetectIntentResponse : 返回(扩展)
|
||
ApprovalAPI --> DifyAPI : 调用(同一Dify应用)
|
||
|
||
H5AiTask --> RoutingService : 调用_handle_routing
|
||
H5AiTask --> Message : 创建AI消息
|
||
H5AiTask --> WSManager : WS推送
|
||
|
||
%% ===== 样式 =====
|
||
style BusinessContact fill:#e8f5e9,stroke:#07C160
|
||
style RoutingEvent fill:#e8f5e9,stroke:#07C160
|
||
style RoutingService fill:#fff3e0,stroke:#ff9800
|
||
style RoutingAPI fill:#e3f2fd,stroke:#1976d2
|
||
style ApprovalAPI fill:#e3f2fd,stroke:#1976d2
|
||
style ApprovalDetectIntentResponse fill:#f3e5f5,stroke:#9c27b0
|
||
style ContactCardResponse fill:#f3e5f5,stroke:#9c27b0
|
||
style SendContactCardRequest fill:#f3e5f5,stroke:#9c27b0
|
||
style Message fill:#f5f5f5,stroke:#9e9e9e
|
||
style H5AiTask fill:#fce4ec,stroke:#e91e63
|
||
style WSManager fill:#f5f5f5,stroke:#9e9e9e
|
||
style DifyAPI fill:#e0f7fa,stroke:#00acc1
|
||
```
|
||
|
||
## 字段详情
|
||
|
||
### BusinessContact(业务联系人)
|
||
|
||
| 属性 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | int | PK, 自增 |
|
||
| name | str(50) | 联系人姓名 |
|
||
| gender | str(10) | male / female |
|
||
| department | str(100) | 部门名称(如「行政部」) |
|
||
| position | str(100) | 岗位(如「设备管理岗」) |
|
||
| responsibility | str(500) | 负责业务描述 |
|
||
| extension | str(20) | 分机号 |
|
||
| service_area | str(200) | 服务区域/办公地点 |
|
||
| wecom_userid | str(100) | 企微用户ID(openEnterpriseChat 用) |
|
||
| avatar_url | str(500) | 头像URL(空则用姓名首字渲染) |
|
||
| business_category | str(50) | 行政/人力资源/财务/法务/行政-物业 |
|
||
| is_active | bool | 是否启用(默认 true) |
|
||
| created_at | datetime | 创建时间 |
|
||
| updated_at | datetime | 更新时间 |
|
||
|
||
### RoutingEvent(路由命中统计 — P1)
|
||
|
||
| 属性 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | int | PK, 自增 |
|
||
| conversation_id | str(36) | FK → conversations.id |
|
||
| employee_id | str(64) | 员工企微 UserID |
|
||
| message_content | str(500) | 触发路由的员工消息(截断) |
|
||
| business_category | str(50) | 识别的业务类别 |
|
||
| routing_confidence | float | 路由置信度 |
|
||
| contact_id | int | FK → business_contacts.id |
|
||
| contact_name | str(50) | 联系人姓名(冗余存储) |
|
||
| is_clicked | bool | 员工是否点击「联系TA」 |
|
||
| created_at | datetime | 创建时间 |
|
||
|
||
### RoutingService 方法说明
|
||
|
||
| 方法 | 签名 | 说明 |
|
||
|------|------|------|
|
||
| keyword_prefilter | (text: str) → bool | 非IT关键词预过滤,命中返回True |
|
||
| detect_routing_intent | async (text: str, employee_id: str) → dict | 调用Dify统一意图识别,返回路由判断结果 |
|
||
| _call_dify_unified_intent | async (text: str, employee_id: str) → dict | 调用Dify原生API(私有方法) |
|
||
| _fallback_routing_detect | (text: str) → tuple | Dify不可用时关键词降级兜底(私有) |
|
||
| get_contact_by_category | async (category: str, db) → BusinessContact | 按业务类别查询第一个有效联系人 |
|
||
| get_contacts | async (category: str, keyword: str, db) → list[BusinessContact] | 查询联系人列表(坐席端用) |
|
||
| send_contact_card | async (db, conversation, employee_id, contact, reason) → Message | 发送名片三段式消息(路由文本+名片+系统提示) |
|
||
| record_routing_event | async (db, ...) → RoutingEvent | 记录路由命中事件(P1统计) |
|