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}
|
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")
|
@router.post("/trigger-daily-check")
|
||||||
async def trigger_daily_check(
|
async def trigger_daily_check(
|
||||||
current_user: dict = Depends(require_director),
|
current_user: dict = Depends(require_director),
|
||||||
|
|||||||
@@ -156,4 +156,51 @@ class WecomClient:
|
|||||||
return False
|
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()
|
wecom_client = WecomClient()
|
||||||
|
|||||||
Reference in New Issue
Block a user