feat: 企业微信 Phase 1 — token 续期 + 回调验证 + 调度器注册

wecom.py:
- Token 自动续期 (7200s 过期 + 60s 提前量 + 42001 重试)
- POST 请求自动重试 (最多 3 次,含速率限制退避)
- 新增 send_markdown_message() / send_template_card() 富消息方法

wecom.py API:
- GET /api/wecom/callback: 企微回调 URL 验证 (SHA1 签名 + AES 解密)
- POST /api/wecom/callback: 事件接收占位

scheduler.py:
- 仅推送给已绑定 wecom_userid 的经理
- 消息内容优化 (已填报/未填报人数统计)

main.py:
- APScheduler 注册每日 17:30 自动检查填报

已验证: WECOM_TOKEN 获取成功

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-26 09:37:13 +08:00
parent 72fb7524f3
commit 36ba9338f1
5 changed files with 232 additions and 35 deletions
+20 -9
View File
@@ -15,8 +15,10 @@ async def check_daily_reporting(db: AsyncSession) -> dict:
if weekday >= 5: # Skip weekends
return {"status": "weekend", "date": str(today)}
# Get all managers
result = await db.execute(select(User).where(User.role == "manager"))
# Get all managers with wecom_userid
result = await db.execute(
select(User).where(User.role == "manager", User.wecom_userid.isnot(None))
)
managers = result.scalars().all()
# Get managers who have reported today
@@ -31,16 +33,25 @@ async def check_daily_reporting(db: AsyncSession) -> dict:
reported_map[str(uid)] = True
not_reported = []
reported_names = []
for m in managers:
if str(m.id) not in reported_map:
if str(m.id) in reported_map:
reported_names.append(m.name)
else:
not_reported.append(m)
if not_reported and managers:
content = f"📋 今日填报提醒({today}\n\n以下同事尚未提交今日拜访记录:\n"
for m in not_reported:
content += f"{m.name}\n"
content += "\n请尽快完成今日拜访填报 🙏"
# Send markdown message to not-reported managers
if not_reported:
names = "".join(m.name for m in not_reported)
content = (
f"## 📋 今日填报提醒\n\n"
f"> 日期:{today}\n"
f"> 已填报:{len(reported_names)}\n"
f"> 未填报:**{len(not_reported)} 人**\n\n"
f"以下同事尚未提交今日拜访记录:\n"
+ "".join(f"- **{m.name}**\n" for m in not_reported)
+ f"\n请尽快完成今日拜访填报 🙏"
)
user_ids = [m.wecom_userid for m in not_reported if m.wecom_userid]
if user_ids:
await wecom_client.send_text_message(user_ids, content)