feat: 企微菜单管理 — create_menu / get_menu / delete_menu
wecom.py 新增: - create_menu(buttons) — 创建/替换应用自定义菜单 - get_menu() — 获取当前菜单配置 - delete_menu() — 删除菜单 API 新增: - POST /api/wecom/setup-menu — 一键部署标准菜单(开始填报 + 绑定账号) - GET /api/wecom/menu — 查看当前菜单 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -137,6 +137,32 @@ async def test_message(
|
||||
return {"success": success, "sent_to": wecom_userid}
|
||||
|
||||
|
||||
@router.post("/setup-menu")
|
||||
async def setup_menu(current_user: dict = Depends(require_director)):
|
||||
"""Create the standard app menu (开始填报 + 绑定账号)."""
|
||||
buttons = [
|
||||
{
|
||||
"type": "view",
|
||||
"name": "📝 开始填报",
|
||||
"url": "https://qj.dhdx.fun/m",
|
||||
},
|
||||
{
|
||||
"type": "view",
|
||||
"name": "🔗 绑定账号",
|
||||
"url": "https://qj.dhdx.fun/bind-wechat",
|
||||
},
|
||||
]
|
||||
success = await wecom_client.create_menu(buttons)
|
||||
return {"success": success, "message": "菜单已部署" if success else "菜单创建失败"}
|
||||
|
||||
|
||||
@router.get("/menu")
|
||||
async def get_menu(current_user: dict = Depends(require_director)):
|
||||
"""Get current app menu configuration."""
|
||||
menu = await wecom_client.get_menu()
|
||||
return menu or {"message": "No menu configured"}
|
||||
|
||||
|
||||
@router.post("/trigger-daily-check")
|
||||
async def trigger_daily_check(
|
||||
current_user: dict = Depends(require_director),
|
||||
|
||||
@@ -156,4 +156,51 @@ class WecomClient:
|
||||
return False
|
||||
|
||||
|
||||
# ── Menu management ──
|
||||
|
||||
async def create_menu(self, buttons: list[dict]) -> bool:
|
||||
"""Create/replace the app's custom menu (visible in chat window)."""
|
||||
if not settings.WECOM_AGENT_ID:
|
||||
return False
|
||||
try:
|
||||
body = {"button": buttons}
|
||||
await self._post_with_retry(
|
||||
f"https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid={settings.WECOM_AGENT_ID}",
|
||||
body,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
async def get_menu(self) -> dict | None:
|
||||
"""Get current app menu configuration."""
|
||||
if not settings.WECOM_AGENT_ID:
|
||||
return None
|
||||
try:
|
||||
token = await self._get_token()
|
||||
url = f"https://qyapi.weixin.qq.com/cgi-bin/menu/get?access_token={token}&agentid={settings.WECOM_AGENT_ID}"
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(url, timeout=10)
|
||||
data = resp.json()
|
||||
if data.get("errcode") == 0:
|
||||
return data
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
async def delete_menu(self) -> bool:
|
||||
"""Delete the app's custom menu."""
|
||||
if not settings.WECOM_AGENT_ID:
|
||||
return False
|
||||
try:
|
||||
token = await self._get_token()
|
||||
url = f"https://qyapi.weixin.qq.com/cgi-bin/menu/delete?access_token={token}&agentid={settings.WECOM_AGENT_ID}"
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(url, timeout=10)
|
||||
data = resp.json()
|
||||
return data.get("errcode") == 0
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
wecom_client = WecomClient()
|
||||
|
||||
Reference in New Issue
Block a user