ForcePilot/backend/package/yuxi/channels/adapters/dingding/cards.py
Kris 9c01d480cc feat(dingding): 完整实现钉钉适配器功能模块
- 新增钉钉工具调用审计日志功能
- 新增参数校验装饰器与基础工具集(文档、审批、多维表格)
- 完善事件类型映射与会话ID生成逻辑
- 新增消息去重、访问策略匹配、配置校验与UI提示
- 新增酷应用卡片、目录管理、表情反应支持
- 优化消息发送逻辑,添加401重试机制
- 新增配置化的权限控制与流式输出支持
2026-05-13 16:06:10 +08:00

180 lines
4.7 KiB
Python

from __future__ import annotations
import uuid
from typing import Any
TEXT_CHUNK_LIMIT = 4096
def generate_card_biz_id(prefix: str = "fp") -> str:
suffix = uuid.uuid4().hex[:12]
return f"{prefix}_{suffix}"
def build_dingding_text_payload(content: str) -> dict[str, Any]:
return {"content": str(content)[:TEXT_CHUNK_LIMIT]}
def build_dingding_markdown_payload(title: str, text: str) -> dict[str, Any]:
return {
"title": str(title),
"text": str(text),
}
def build_dingding_action_card(
title: str,
text: str,
*,
single_title: str | None = None,
single_url: str | None = None,
buttons: list[dict[str, str]] | None = None,
btn_orientation: str = "0",
) -> dict[str, Any]:
msg_key = "sampleActionCard1" if single_title else "sampleActionCard2"
params: dict[str, Any] = {
"title": str(title),
"text": str(text),
}
if single_title and single_url:
params["singleTitle"] = single_title
params["singleURL"] = single_url
if buttons:
params["btns"] = buttons
params["btnOrientation"] = btn_orientation
return {"msg_key": msg_key, "msg_param": params}
def build_dingding_feed_card(links: list[dict[str, str]]) -> dict[str, Any]:
return {
"msg_key": "sampleFeedCard",
"msg_param": {"links": links},
}
def build_standard_card(
*,
card_biz_id: str | None = None,
title: str = "",
markdown_content: str = "",
buttons: list[dict[str, Any]] | None = None,
status: str = "",
private_data: dict[str, Any] | None = None,
pc_slide_open: str = "0",
) -> dict[str, Any]:
biz_id = card_biz_id or generate_card_biz_id()
card_data: dict[str, Any] = {
"cardBizId": biz_id,
}
if title:
card_data["header"] = {
"title": {"type": "text", "text": title},
}
components: list[dict[str, Any]] = []
if markdown_content:
components.append({
"componentType": "markdown",
"text": markdown_content,
})
if status:
components.append({
"componentType": "status",
"status": status,
})
if buttons:
button_list: list[dict[str, Any]] = []
for btn in buttons:
button_item: dict[str, Any] = {
"actionType": btn.get("action_type", "CALLBACK"),
"title": btn.get("title", ""),
}
if "url" in btn:
button_item["url"] = btn["url"]
if "callback_key" in btn:
button_item["callbackKey"] = btn["callback_key"]
if "params" in btn:
button_item["params"] = btn["params"]
btn_color = btn.get("color", "")
if btn_color:
button_item["buttonStyle"] = {"color": btn_color}
button_list.append(button_item)
if button_list:
components.append({
"componentType": "actionGroup",
"actions": button_list,
})
if components:
card_data["body"] = components
card_data["pcSlideOpen"] = pc_slide_open
payload: dict[str, Any] = {
"cardData": card_data,
"cardBizId": biz_id,
}
if private_data:
payload["privateData"] = private_data
send_options: dict[str, Any] = {
"atAll": False,
"atUserListJson": "[]",
}
payload["sendOptions"] = send_options
return payload
def build_card_template(
template_id: str,
*,
card_biz_id: str | None = None,
variables: dict[str, Any] | None = None,
private_data: dict[str, Any] | None = None,
) -> dict[str, Any]:
biz_id = card_biz_id or generate_card_biz_id("tmpl")
payload: dict[str, Any] = {
"cardData": {
"cardBizId": biz_id,
"templateId": template_id,
"cardTemplateVariableParams": variables or {},
},
"cardBizId": biz_id,
}
if private_data:
payload["privateData"] = private_data
return payload
def build_approved_card_params(
card_data: dict[str, Any],
*,
card_instance_id: str = "",
) -> dict[str, Any]:
params: dict[str, Any] = {
"msgKey": "actionCard",
"msgParam": card_data,
}
if card_instance_id:
params["cardInstanceId"] = card_instance_id
return params
def parse_card_private_data(card_callback_data: dict[str, Any]) -> dict[str, Any]:
return card_callback_data.get("cardPrivateData", card_callback_data.get("privateData", {}))
def parse_card_callback_params(card_callback_data: dict[str, Any]) -> dict[str, Any]:
return card_callback_data.get("actionParameter", card_callback_data.get("params", {}))