feat: alert wecom when no designer is available
This commit is contained in:
@@ -3,6 +3,7 @@ import logging
|
||||
import httpx
|
||||
import asyncio
|
||||
from typing import Optional
|
||||
from services.service_designer_alert import designer_alert_service
|
||||
|
||||
logger = logging.getLogger("cs_agent")
|
||||
|
||||
@@ -53,6 +54,10 @@ class DispatchService:
|
||||
return designer
|
||||
|
||||
logger.warning(f"[Dispatch]{u_tag} 派单被拒: {data.get('reason')} body={body}")
|
||||
await designer_alert_service.notify_if_needed(
|
||||
trigger=f"dispatch_rejected:{data.get('reason') or 'unknown'}",
|
||||
customer_id=user_id,
|
||||
)
|
||||
return None
|
||||
|
||||
if response.status_code == 401:
|
||||
|
||||
76
services/service_designer_alert.py
Normal file
76
services/service_designer_alert.py
Normal file
@@ -0,0 +1,76 @@
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Dict
|
||||
|
||||
from db.chat_log_db import get_waiting_customer_pool
|
||||
from db.pending_transfer_db import count_open_pending_transfers
|
||||
from services.service_wecom_bot import wecom_bot_service
|
||||
|
||||
logger = logging.getLogger("cs_agent")
|
||||
|
||||
DESIGNER_ALERT_START_HOUR = int(os.getenv("DESIGNER_ALERT_START_HOUR", "8"))
|
||||
DESIGNER_ALERT_END_HOUR = int(os.getenv("DESIGNER_ALERT_END_HOUR", "24"))
|
||||
DESIGNER_ALERT_COOLDOWN_SECONDS = int(os.getenv("DESIGNER_ALERT_COOLDOWN_SECONDS", "300"))
|
||||
DESIGNER_ALERT_POOL_WINDOW_MINUTES = int(os.getenv("DESIGNER_ALERT_POOL_WINDOW_MINUTES", "30"))
|
||||
|
||||
|
||||
class DesignerAlertService:
|
||||
def __init__(self):
|
||||
self._last_alert_at = 0.0
|
||||
|
||||
@staticmethod
|
||||
def _in_active_window(now: datetime) -> bool:
|
||||
hour = now.hour
|
||||
return DESIGNER_ALERT_START_HOUR <= hour < DESIGNER_ALERT_END_HOUR
|
||||
|
||||
@staticmethod
|
||||
def _render_shop_lines(pool: Dict) -> str:
|
||||
shops = pool.get("shops") or []
|
||||
if not shops:
|
||||
return "- 暂无店铺明细"
|
||||
lines = []
|
||||
for item in shops[:10]:
|
||||
acc_id = str(item.get("acc_id") or "")
|
||||
waiting = int(item.get("waiting_customers") or 0)
|
||||
lines.append(f"- {acc_id}:{waiting}人")
|
||||
return "\n".join(lines)
|
||||
|
||||
async def notify_if_needed(self, *, trigger: str = "", customer_id: str = "", acc_id: str = "") -> bool:
|
||||
now = datetime.now()
|
||||
if not self._in_active_window(now):
|
||||
return False
|
||||
|
||||
now_ts = time.time()
|
||||
if now_ts - self._last_alert_at < max(DESIGNER_ALERT_COOLDOWN_SECONDS, 30):
|
||||
return False
|
||||
|
||||
pending_count = count_open_pending_transfers()
|
||||
pool = get_waiting_customer_pool(DESIGNER_ALERT_POOL_WINDOW_MINUTES)
|
||||
waiting_total = int(pool.get("total_waiting_customers") or 0)
|
||||
if pending_count <= 0 and waiting_total <= 0:
|
||||
return False
|
||||
|
||||
content = (
|
||||
"【设计师在线提醒】\n"
|
||||
f"当前时间:{now.strftime('%Y-%m-%d %H:%M:%S')}\n"
|
||||
"8点到24点内检测到暂无设计师接单,有客户待转接。\n"
|
||||
f"触发来源:{trigger or '-'}\n"
|
||||
f"当前会话:{customer_id or '-'} / {acc_id or '-'}\n"
|
||||
f"待转接池:{pending_count}人\n"
|
||||
f"当前客户池:{waiting_total}人(近{pool.get('window_minutes') or DESIGNER_ALERT_POOL_WINDOW_MINUTES}分钟最后一条仍是客户消息)\n"
|
||||
"店铺分布:\n"
|
||||
f"{self._render_shop_lines(pool)}\n"
|
||||
"群里如果有设计师在线,麻烦看一下。"
|
||||
)
|
||||
ok = await wecom_bot_service.send_text(content)
|
||||
if ok:
|
||||
self._last_alert_at = now_ts
|
||||
logger.info(
|
||||
f"[DesignerAlert] 已发送企微提醒 trigger={trigger} pending={pending_count} waiting={waiting_total}"
|
||||
)
|
||||
return ok
|
||||
|
||||
|
||||
designer_alert_service = DesignerAlertService()
|
||||
Reference in New Issue
Block a user