# 技术方案:消息推送策略优化与超时提醒 > **需求来源**: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() ``` --- ## 三、实现情况 | 任务 | 状态 | 文件位置 | |------|------|----------| | 数据库迁移 | ✅ 已完成 | `backend/migrations/versions/001_add_reminder_fields.sql` | | 数据模型更新 | ✅ 已完成 | `backend/app/models/conversation.py` | | 消息发送逻辑修改 | ✅ 已完成 | `backend/app/api/messages.py` | | 新建提醒服务 | ✅ 已完成 | `backend/app/services/reminder_service.py` | | 新建定时任务 | ✅ 已完成 | `backend/app/tasks/reminder_task.py` | | 定时任务注册 | ✅ 已完成 | `backend/app/main.py` | --- ## 四、上线前置条件 1. 在生产数据库执行迁移脚本 `001_add_reminder_fields.sql` 2. 重启后端服务以加载定时任务 --- ## 五、风险与注意事项 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/03-技术架构/02-技术方案/技术方案-消息推送策略优化与超时提醒.md` | 本文档 | --- *最后更新:2026-07-05 18:20*