机器人显示名与站点标题可配;多段联运列表投影;协同群监听对账;工单附件落存;模板与工单后台补强

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-10-19 09:41:59 +08:00
co-authored by Cursor
parent 277cdc1c28
commit 2b528758b4
119 changed files with 6760 additions and 3516 deletions
+32 -1
View File
@@ -8,10 +8,12 @@
from __future__ import annotations
import json
import logging
import threading
import time
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Optional
import httpx
@@ -19,6 +21,7 @@ import httpx
logger = logging.getLogger(__name__)
@dataclass
class WeComSendResult:
"""企微发送结果(通道层)。"""
@@ -496,7 +499,7 @@ class WeComAppClient:
"""
解散应用群:官方无 dismiss,改为 appchat/update 移出成员。
不抛给回调。移完人不改工单六态。
群主会留在空群壳(企微限制,与历史行为一致)。不抛给回调。不改六态。
"""
users = [str(x).strip() for x in (userids or []) if str(x).strip()]
if not chat_id or not users:
@@ -506,6 +509,7 @@ class WeComAppClient:
except Exception as exc: # noqa: BLE001
logger.exception("解散群取 token 失败")
return {"ok": False, "error": str(exc)}
before = self._appchat_info(chat_id=chat_id, token=token)
url = f"{self._api_base}/cgi-bin/appchat/update"
body = {"chatid": chat_id, "del_user_list": users}
try:
@@ -516,12 +520,39 @@ class WeComAppClient:
logger.exception("企微解散群网络失败")
return {"ok": False, "error": str(exc)}
errcode = int(data.get("errcode") or 0)
after = self._appchat_info(chat_id=chat_id, token=token) if errcode == 0 else {}
if errcode != 0:
logger.warning("企微解散群失败 errcode=%s", errcode)
return {"ok": False, "error": str(data.get("errmsg") or f"errcode_{errcode}")}
logger.info("企微群已移出成员 chat=%s", chat_id)
return {"ok": True, "error": ""}
def _appchat_info(self, *, chat_id: str, token: str = "") -> dict[str, Any]:
"""读应用群群主与成员。失败回空字典,不抛。仅调试/核对用。"""
raw_token = (token or "").strip()
if not raw_token:
try:
raw_token = self._get_token()
except Exception: # noqa: BLE001
return {}
url = f"{self._api_base}/cgi-bin/appchat/get"
try:
with httpx.Client(timeout=self._timeout) as client:
resp = client.get(url, params={"access_token": raw_token, "chatid": chat_id})
data = resp.json()
except Exception: # noqa: BLE001
return {}
if int(data.get("errcode") or 0) != 0:
return {}
info = data.get("chat_info") or data.get("chatinfo") or {}
return {
"owner": str(info.get("owner") or "").strip(),
"userlist": [
str(x).strip()
for x in (info.get("userlist") or info.get("user_list") or [])
if str(x).strip()
],
}
def _post_appchat(self, body: dict[str, Any]) -> dict[str, Any]:
"""appchat/send 公共发送。失败不抛。"""
if not self._corp_id or not self._secret: