228 lines
7.1 KiB
Markdown
228 lines
7.1 KiB
Markdown
|
|
# 技术方案:消息推送策略优化与超时提醒
|
|||
|
|
|
|||
|
|
> **需求来源**:2026-07-05 产品讨论
|
|||
|
|
> **版本**:v1.0
|
|||
|
|
> **状态**:待开发
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、需求概述
|
|||
|
|
|
|||
|
|
### 1.1 业务背景
|
|||
|
|
|
|||
|
|
当前坐席回复用户消息时,会同时走两个通道:
|
|||
|
|
1. **WebSocket** → 推送到 H5 页面
|
|||
|
|
2. **企微应用消息** → 推送到"IT支持服务"应用的消息列表
|
|||
|
|
|
|||
|
|
这导致两种场景混在一起:
|
|||
|
|
- 场景A:员工找坐席(一对一私密对话)→ 期望只走 H5
|
|||
|
|
- 场景B:IT支持组群发通知 → 期望走企微消息
|
|||
|
|
|
|||
|
|
### 1.2 产品需求
|
|||
|
|
|
|||
|
|
| 需求 | 描述 |
|
|||
|
|
|------|------|
|
|||
|
|
| R1 | 正常对话:坐席回复仅推送到 H5 页面(WebSocket) |
|
|||
|
|
| R2 | 坐席回复后员工 3 分钟(可配置)未回复,发送企微提醒消息 |
|
|||
|
|
| R3 | 提醒消息只发 1 次 |
|
|||
|
|
| R4 | 10 分钟后自动标记会话为"待关闭"状态 |
|
|||
|
|
| R5 | 提醒文案固定(见 1.3) |
|
|||
|
|
|
|||
|
|
### 1.3 提醒文案
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
IT服务提醒:您有新的消息未查看,咨询将在10分钟后标记为待关闭,请尽快点击处理 👉 https://itsupport.servyou.com.cn/itdesk/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、技术方案
|
|||
|
|
|
|||
|
|
### 2.1 架构设计
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────┐ ┌──────────────┐ ┌─────────────────┐
|
|||
|
|
│ 坐席发送 │────▶│ WebSocket │────▶│ H5页面 │
|
|||
|
|
│ 消息 │ │ (仅推送H5) │ │ (实时可见) │
|
|||
|
|
└─────────────┘ └──────────────┘ └─────────────────┘
|
|||
|
|
│
|
|||
|
|
▼ (触发条件)
|
|||
|
|
┌─────────────────────────────────────────┐
|
|||
|
|
│ 后台定时任务 (每30秒) │
|
|||
|
|
│ • 检查超时未回复会话 │
|
|||
|
|
│ • 发送企微提醒消息 │
|
|||
|
|
│ • 标记会话状态 │
|
|||
|
|
└─────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 数据库改动
|
|||
|
|
|
|||
|
|
#### 2.2.1 conversations 表新增字段
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
ALTER TABLE conversations
|
|||
|
|
ADD COLUMN IF NOT EXISTS last_agent_reply_at TIMESTAMP DEFAULT NULL,
|
|||
|
|
ADD COLUMN IF NOT EXISTS reminder_sent BOOLEAN DEFAULT FALSE,
|
|||
|
|
ADD COLUMN IF NOT EXISTS reminder_sent_at TIMESTAMP DEFAULT NULL,
|
|||
|
|
ADD COLUMN IF NOT EXISTS pending_close_at TIMESTAMP DEFAULT NULL;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| `last_agent_reply_at` | TIMESTAMP | 坐席最后回复时间 |
|
|||
|
|
| `reminder_sent` | BOOLEAN | 是否已发送提醒 |
|
|||
|
|
| `reminder_sent_at` | TIMESTAMP | 提醒发送时间 |
|
|||
|
|
| `pending_close_at` | TIMESTAMP | 待关闭时间(最后回复+10分钟) |
|
|||
|
|
|
|||
|
|
#### 2.2.2 配置表(可选)
|
|||
|
|
|
|||
|
|
在系统配置表中添加:
|
|||
|
|
|
|||
|
|
| key | default | 说明 |
|
|||
|
|
|-----|---------|------|
|
|||
|
|
| `reminder.timeout_minutes` | 3 | 未回复超时时间(分钟) |
|
|||
|
|
| `reminder.close_minutes` | 10 | 自动待关闭时间(分钟) |
|
|||
|
|
| `reminder.enabled` | true | 是否启用提醒功能 |
|
|||
|
|
|
|||
|
|
### 2.3 后端改动
|
|||
|
|
|
|||
|
|
#### 2.3.1 消息发送逻辑修改
|
|||
|
|
|
|||
|
|
**文件**:`backend/app/api/messages.py`
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 坐席发送消息时
|
|||
|
|
async def send_message(...):
|
|||
|
|
# 1. 仅通过 WebSocket 推送到 H5(不再调用企微 API)
|
|||
|
|
await manager.send_to_employee(conversation.employee_id, ws_event)
|
|||
|
|
|
|||
|
|
# 2. 更新会话的最后坐席回复时间
|
|||
|
|
conversation.last_agent_reply_at = datetime.now()
|
|||
|
|
conversation.reminder_sent = False # 重置提醒标记
|
|||
|
|
conversation.pending_close_at = datetime.now() + timedelta(minutes=10)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2.3.2 新增定时任务
|
|||
|
|
|
|||
|
|
**文件**:`backend/app/tasks/reminder_task.py`(新建)
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 每 30 秒执行一次
|
|||
|
|
@scheduler.scheduled_job('interval', seconds=30)
|
|||
|
|
async def check_unreplied_sessions():
|
|||
|
|
"""检查超时未回复的会话,发送提醒"""
|
|||
|
|
|
|||
|
|
# 1. 查找需要处理的会话
|
|||
|
|
sessions = await db.execute(select(Conversation).where(
|
|||
|
|
Conversation.status == 'active',
|
|||
|
|
Conversation.last_agent_reply_at.isnot(None),
|
|||
|
|
Conversation.reminder_sent == False,
|
|||
|
|
Conversation.last_agent_reply_at < (datetime.now() - timedelta(minutes=3))
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
for session in sessions:
|
|||
|
|
# 2. 发送企微提醒消息
|
|||
|
|
await send_reminder_message(session)
|
|||
|
|
|
|||
|
|
# 3. 标记已发送
|
|||
|
|
session.reminder_sent = True
|
|||
|
|
session.reminder_sent_at = datetime.now()
|
|||
|
|
|
|||
|
|
# 4. 处理待关闭会话
|
|||
|
|
pending = await db.execute(select(Conversation).where(
|
|||
|
|
Conversation.status == 'active',
|
|||
|
|
Conversation.pending_close_at < datetime.now()
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
for session in pending:
|
|||
|
|
session.status = 'pending_close' # 待关闭状态
|
|||
|
|
|
|||
|
|
await db.commit()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2.3.3 提醒消息发送函数
|
|||
|
|
|
|||
|
|
**文件**:`backend/app/services/reminder_service.py`(新建)
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
async def send_reminder_message(conversation: Conversation):
|
|||
|
|
"""发送超时提醒企微消息"""
|
|||
|
|
|
|||
|
|
message = "IT服务提醒:您有新的消息未查看,咨询将在10分钟后标记为待关闭,请尽快点击处理 👉 https://itsupport.servyou.com.cn/itdesk/"
|
|||
|
|
|
|||
|
|
redis_client = settings.create_redis_client()
|
|||
|
|
wecom_service = WecomService(redis_client)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
await wecom_service.send_text_message(
|
|||
|
|
conversation.employee_id,
|
|||
|
|
message
|
|||
|
|
)
|
|||
|
|
finally:
|
|||
|
|
await wecom_service.close()
|
|||
|
|
await redis_client.close()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.4 前端改动
|
|||
|
|
|
|||
|
|
#### 2.4.1 坐席端(无需改动)
|
|||
|
|
|
|||
|
|
当前坐席发送消息功能保持不变,后端会自动处理推送逻辑。
|
|||
|
|
|
|||
|
|
#### 2.4.2 H5 端(无需改动)
|
|||
|
|
|
|||
|
|
WebSocket 接收消息逻辑保持不变。
|
|||
|
|
|
|||
|
|
### 2.5 部署配置
|
|||
|
|
|
|||
|
|
#### 2.5.1 后端定时任务启动
|
|||
|
|
|
|||
|
|
在 `backend/app/main.py` 中注册定时任务:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|||
|
|
|
|||
|
|
scheduler = AsyncIOScheduler()
|
|||
|
|
scheduler.add_job(check_unreplied_sessions, 'interval', seconds=30)
|
|||
|
|
scheduler.start()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、任务分解
|
|||
|
|
|
|||
|
|
| # | 任务 | 文件 | 预估工时 |
|
|||
|
|
|---|------|------|---------|
|
|||
|
|
| 1 | 数据库迁移 | conversations 表新增字段 | 0.5h |
|
|||
|
|
| 2 | 消息发送逻辑修改 | `backend/app/api/messages.py` | 0.5h |
|
|||
|
|
| 3 | 新建提醒服务 | `backend/app/services/reminder_service.py` | 1h |
|
|||
|
|
| 4 | 新建定时任务 | `backend/app/tasks/reminder_task.py` | 1h |
|
|||
|
|
| 5 | 定时任务注册 | `backend/app/main.py` | 0.5h |
|
|||
|
|
| 6 | 部署测试 | - | 1h |
|
|||
|
|
|
|||
|
|
**总计**:约 4.5 小时
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、风险与注意事项
|
|||
|
|
|
|||
|
|
1. **定时任务并发**:多实例部署时需确保任务不重复执行(建议加分布式锁)
|
|||
|
|
2. **历史数据**:已存在的会话不受影响,新逻辑仅对新增会话生效
|
|||
|
|
3. **配置灵活性**:当前为固定值,后续可扩展为可配置
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、相关文件清单
|
|||
|
|
|
|||
|
|
| 文件 | 操作 |
|
|||
|
|
|------|------|
|
|||
|
|
| `backend/app/api/messages.py` | 修改 |
|
|||
|
|
| `backend/app/services/reminder_service.py` | 新建 |
|
|||
|
|
| `backend/app/tasks/reminder_task.py` | 新建 |
|
|||
|
|
| `backend/app/main.py` | 修改 |
|
|||
|
|
| `docs/02-产品需求/04-技术方案-消息推送策略优化与超时提醒.md` | 新建 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
*最后更新:2026-07-05 15:40*
|