优化:日报改为单条文本卡片推送
This commit is contained in:
@@ -28,7 +28,6 @@ CLEANING_TYPE_NAMES = {
|
||||
}
|
||||
|
||||
WEEKDAY_NAMES = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
|
||||
REPORT_COVER_IMAGE_URL = "https://wework.qpic.cn/wwpic/252813_jOfDHtcISzuodLa_1629280209/0"
|
||||
|
||||
|
||||
def _format_duration(minutes: float) -> str:
|
||||
@@ -317,19 +316,27 @@ def _build_preview_text(report: Dict) -> str:
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _build_report_news(report: Dict) -> Dict:
|
||||
def _build_report_textcard(report: Dict) -> Dict:
|
||||
summary = report["summary"]
|
||||
click_url = settings.wechat.service_base_url or "https://work.weixin.qq.com"
|
||||
description = (
|
||||
f"{report['overview']}\n"
|
||||
f"首响 {summary['avg_resp']}|完结 {summary['avg_close']}|误报率 {summary['false_alarm_rate']}\n"
|
||||
f"高发区域:{report['tops']['areas']}"
|
||||
)
|
||||
description_lines = [
|
||||
f"<div class=\"gray\">{report['subtitle']}</div>",
|
||||
f"<div class=\"normal\">昨日新增 <font color=\"warning\">{summary['yesterday_total']}</font> 条({report['change_str']})</div>",
|
||||
f"<div class=\"normal\">昨日完成 {summary['completed_count']} 条|当前待处理 <font color=\"warning\">{summary['backlog_count']}</font> 条</div>",
|
||||
f"<div class=\"normal\">安保 {summary['security_count']} 条|保洁 {summary['clean_count']} 条</div>",
|
||||
f"<div class=\"normal\">平均首响 <font color=\"info\">{summary['avg_resp']}</font>|平均完结 <font color=\"info\">{summary['avg_close']}</font></div>",
|
||||
f"<div class=\"normal\">误报率 {summary['false_alarm_rate']}|遗留待处理 {summary['carry_over_count']} 条</div>",
|
||||
"<div class=\"gray\">重点风险</div>",
|
||||
f"<div class=\"normal\">安保高发:{report['tops']['alarm_types']}</div>",
|
||||
f"<div class=\"normal\">高发区域:{report['tops']['areas']}</div>",
|
||||
f"<div class=\"normal\">高发摄像头:{report['tops']['cameras']}</div>",
|
||||
]
|
||||
if report["top_overdue"]:
|
||||
description_lines.append(f"<div class=\"normal\">优先跟进:{report['top_overdue'][0]}</div>")
|
||||
return {
|
||||
"title": report["title"],
|
||||
"description": description,
|
||||
"description": "".join(description_lines),
|
||||
"url": click_url,
|
||||
"picurl": REPORT_COVER_IMAGE_URL,
|
||||
}
|
||||
|
||||
|
||||
@@ -340,11 +347,11 @@ async def generate_daily_report() -> Optional[str]:
|
||||
return _build_preview_text(report)
|
||||
|
||||
|
||||
async def generate_daily_report_news() -> Optional[Dict]:
|
||||
async def generate_daily_report_textcard() -> Optional[Dict]:
|
||||
report = await _build_daily_report_data()
|
||||
if not report:
|
||||
return None
|
||||
return _build_report_news(report)
|
||||
return _build_report_textcard(report)
|
||||
|
||||
|
||||
async def _send_daily_report():
|
||||
@@ -356,31 +363,25 @@ async def _send_daily_report():
|
||||
return
|
||||
|
||||
try:
|
||||
news = await generate_daily_report_news()
|
||||
card = await generate_daily_report_textcard()
|
||||
preview = await generate_daily_report()
|
||||
if not news or not preview:
|
||||
if not card or not preview:
|
||||
logger.info("日报生成内容为空,跳过发送")
|
||||
return
|
||||
|
||||
wechat_svc = get_wechat_service()
|
||||
ok = await wechat_svc.send_group_news(
|
||||
ok = await wechat_svc.send_group_textcard(
|
||||
chat_id=chat_id,
|
||||
title=news["title"],
|
||||
description=news["description"],
|
||||
url=news["url"],
|
||||
picurl=news["picurl"],
|
||||
title=card["title"],
|
||||
description=card["description"],
|
||||
url=card["url"],
|
||||
)
|
||||
if ok:
|
||||
await asyncio.sleep(1)
|
||||
detail_ok = await wechat_svc.send_group_markdown(chat_id, preview)
|
||||
if detail_ok:
|
||||
logger.info("日报图文+摘要已发送到企微群聊")
|
||||
else:
|
||||
logger.warning("日报图文已发送,但摘要markdown发送失败")
|
||||
logger.info("日报文本卡片已发送到企微群聊")
|
||||
else:
|
||||
fallback_ok = await wechat_svc.send_group_markdown(chat_id, preview)
|
||||
if fallback_ok:
|
||||
logger.info("日报图文发送失败,已降级为markdown发送")
|
||||
logger.info("日报文本卡片发送失败,已降级为markdown发送")
|
||||
else:
|
||||
logger.error("日报发送失败")
|
||||
except Exception:
|
||||
|
||||
@@ -588,6 +588,35 @@ class WeChatService:
|
||||
logger.error(f"发送群聊markdown异常: {e}")
|
||||
return False
|
||||
|
||||
async def send_group_textcard(self, chat_id: str, title: str, description: str, url: str = "") -> bool:
|
||||
"""发送 textcard 消息到群聊,适合单条摘要展示。"""
|
||||
if not self._enabled:
|
||||
return False
|
||||
try:
|
||||
access_token = await self._get_access_token()
|
||||
msg = {
|
||||
"chatid": chat_id,
|
||||
"msgtype": "textcard",
|
||||
"textcard": {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"url": url or "https://work.weixin.qq.com",
|
||||
"btntxt": "查看详情",
|
||||
},
|
||||
}
|
||||
api_url = f"https://qyapi.weixin.qq.com/cgi-bin/appchat/send?access_token={access_token}"
|
||||
async with httpx.AsyncClient(timeout=10) as client:
|
||||
resp = await client.post(api_url, json=msg)
|
||||
data = resp.json()
|
||||
if data.get("errcode") != 0:
|
||||
logger.error(f"群聊文本卡片发送失败: {data}")
|
||||
return False
|
||||
logger.info(f"群聊文本卡片已发送: chatid={chat_id}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"发送群聊文本卡片异常: {e}")
|
||||
return False
|
||||
|
||||
async def send_group_image(self, chat_id: str, media_id: str) -> bool:
|
||||
"""发送图片消息到群聊"""
|
||||
if not self._enabled:
|
||||
|
||||
Reference in New Issue
Block a user