feat: 企微 API 代理 + 菜单部署修复

config.py:
- 新增 WECOM_API_BASE 环境变量 (默认 https://qyapi.weixin.qq.com)

wecom.py:
- 所有 API 调用改用 settings.WECOM_API_BASE (支持代理)
- 修复 _post_with_retry URL 拼接 bug (? vs &)
- 菜单名去掉 emoji (企微限制 16 字符)

api/wecom.py:
- setup-menu 端点菜单名修正

.env.example:
- 新增 WECOM_API_BASE 说明

当前 .env 配置: WECOM_API_BASE=https://api.v6ole.top
已验证: 通过代理获取 token , 菜单创建 

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-26 11:58:12 +08:00
parent da1f24c710
commit 1d2dacc3ab
4 changed files with 15 additions and 19 deletions
+10 -9
View File
@@ -19,7 +19,7 @@ class WecomClient:
if self._access_token and time.time() < self._token_expires_at - 60:
return self._access_token
url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={self.corp_id}&corpsecret={self.secret}"
url = f"{settings.WECOM_API_BASE}/cgi-bin/gettoken?corpid={self.corp_id}&corpsecret={self.secret}"
async with httpx.AsyncClient() as client:
resp = await client.get(url, timeout=10)
data = resp.json()
@@ -35,7 +35,8 @@ class WecomClient:
for attempt in range(max_retries):
try:
token = await self._get_token()
full_url = f"{url}?access_token={token}"
sep = "&" if "?" in url else "?"
full_url = f"{url}{sep}access_token={token}"
async with httpx.AsyncClient() as client:
resp = await client.post(full_url, json=body, timeout=10)
data = resp.json()
@@ -70,7 +71,7 @@ class WecomClient:
"""Exchange OAuth2 code for userid (used in silent login)."""
try:
token = await self._get_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token={token}&code={code}"
url = f"{settings.WECOM_API_BASE}/cgi-bin/auth/getuserinfo?access_token={token}&code={code}"
async with httpx.AsyncClient() as client:
resp = await client.get(url, timeout=10)
data = resp.json()
@@ -92,7 +93,7 @@ class WecomClient:
"text": {"content": content},
}
await self._post_with_retry(
"https://qyapi.weixin.qq.com/cgi-bin/message/send", body
f"{settings.WECOM_API_BASE}/cgi-bin/message/send", body
)
return True
except Exception:
@@ -110,7 +111,7 @@ class WecomClient:
"markdown": {"content": content},
}
await self._post_with_retry(
"https://qyapi.weixin.qq.com/cgi-bin/message/send", body
f"{settings.WECOM_API_BASE}/cgi-bin/message/send", body
)
return True
except Exception:
@@ -149,7 +150,7 @@ class WecomClient:
},
}
await self._post_with_retry(
"https://qyapi.weixin.qq.com/cgi-bin/message/send", body
f"{settings.WECOM_API_BASE}/cgi-bin/message/send", body
)
return True
except Exception:
@@ -165,7 +166,7 @@ class WecomClient:
try:
body = {"button": buttons}
await self._post_with_retry(
f"https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid={settings.WECOM_AGENT_ID}",
f"{settings.WECOM_API_BASE}/cgi-bin/menu/create?agentid={settings.WECOM_AGENT_ID}",
body,
)
return True
@@ -178,7 +179,7 @@ class WecomClient:
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}"
url = f"{settings.WECOM_API_BASE}/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()
@@ -194,7 +195,7 @@ class WecomClient:
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}"
url = f"{settings.WECOM_API_BASE}/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()