- 11 个超 20KB 的 SKILL.md 拆分,大章节移入 references/details.md - 7 处非标准字段(arguments/user_invocable)移入 metadata - 修 req-dev 4 条相对链接;validate 跳过行内代码避免  误报 - validate-skills.py: 23 warns -> 0 warns,0 errors
13 KiB
13 KiB
name, description, metadata, disable-model-invocation
| name | description | metadata | disable-model-invocation | ||
|---|---|---|---|---|---|
| wecom | 企业微信集成。通过自然语言发送消息、管理群机器人、操作审批流程、管理通讯录。当用户提到企业微信、微信工作、群机器人、企业号、wecom相关任务时自动激活。 |
|
true |
功能概述
消息推送
- 应用消息: 向指定用户/部门发送文本、图片、文件等消息
- 群机器人: 通过 Webhook 向群聊发送消息
- 模板消息: 发送结构化的卡片消息
通讯录管理
- 部门管理: 查询、创建、更新部门
- 成员管理: 查询、创建、更新成员信息
审批流程
- 发起审批: 通过 API 发起审批申请
- 审批状态: 查询审批单状态
环境配置
已配置的企业微信应用
| 配置项 | 值 |
|---|---|
| 企业ID (CorpID) | ww8ab927306fa235d2 |
| 应用ID (AgentId) | 1000003 |
| 可信域名 | wecom.pipexerp.com |
环境变量
# ~/.zshrc 已配置
export WECOM_CORP_ID="ww8ab927306fa235d2"
export WECOM_AGENT_ID="1000003"
export WECOM_SECRET="Dts8BmENzjxCRK1Qn4qmkO6mU81FLVEkhI2LitcBcjI"
API 基础
获取 Access Token
import os
import requests
CORP_ID = os.environ.get("WECOM_CORP_ID")
CORP_SECRET = os.environ.get("WECOM_SECRET")
AGENT_ID = os.environ.get("WECOM_AGENT_ID")
def get_access_token():
"""获取企业微信 access_token(有效期 7200 秒)"""
url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
params = {
"corpid": CORP_ID,
"corpsecret": CORP_SECRET
}
resp = requests.get(url, params=params)
result = resp.json()
if result.get("errcode") == 0:
return result["access_token"]
else:
raise Exception(f"获取 token 失败: {result}")
消息推送
发送文本消息
def send_text(user_id: str, content: str):
"""发送文本消息给指定用户"""
token = get_access_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={token}"
data = {
"touser": user_id, # 用 "@all" 发送给所有人
"msgtype": "text",
"agentid": int(AGENT_ID),
"text": {"content": content}
}
resp = requests.post(url, json=data)
return resp.json()
# 使用示例
send_text("@all", "这是一条测试消息")
发送 Markdown 消息
def send_markdown(user_id: str, content: str):
"""发送 Markdown 格式消息"""
token = get_access_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={token}"
data = {
"touser": user_id,
"msgtype": "markdown",
"agentid": int(AGENT_ID),
"markdown": {"content": content}
}
resp = requests.post(url, json=data)
return resp.json()
发送卡片消息
def send_card(user_id: str, title: str, description: str, url: str):
"""发送文本卡片消息"""
token = get_access_token()
api_url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={token}"
data = {
"touser": user_id,
"msgtype": "textcard",
"agentid": int(AGENT_ID),
"textcard": {
"title": title,
"description": description,
"url": url,
"btntxt": "详情"
}
}
resp = requests.post(api_url, json=data)
return resp.json()
群机器人 Webhook
def send_to_group(webhook_url: str, content: str, mentioned_list: list = None):
"""通过 Webhook 发送群消息"""
data = {
"msgtype": "text",
"text": {
"content": content,
"mentioned_list": mentioned_list or []
}
}
resp = requests.post(webhook_url, json=data)
return resp.json()
# 使用示例
WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxx"
send_to_group(WEBHOOK_URL, "自动化任务完成通知", ["@all"])
通讯录管理
获取部门列表
def get_departments():
"""获取部门列表"""
token = get_access_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token={token}"
resp = requests.get(url)
return resp.json()
获取部门成员
def get_department_users(department_id: int):
"""获取部门成员列表"""
token = get_access_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/user/simplelist"
params = {"access_token": token, "department_id": department_id}
resp = requests.get(url, params=params)
return resp.json()
云文档操作
样式规范
企业微信云文档支持两种样式方案,根据文档类型选择:
| 文档类型 | 推荐方案 | 说明 |
|---|---|---|
| 合同、协议 | 带标题样式 | 使用 create_contract_doc() |
| 报告、记录 | 简单文本 | 使用 create_simple_doc() |
| 会议纪要 | 简单文本 | 使用 create_simple_doc() |
简单文本样式符号规范
文档标题 ← 由文档名称体现
━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ← 分隔线
【章节标题】 ← 用【】标记一级章节
内容正文...
【子章节】 ← 同样用【】
1.1 条款内容
1.2 条款内容
带标题样式(合同类)
- heading_level=1: 文档主标题(如"物流服务合同")
- heading_level=2: 章节标题(如"第一条"、"甲方")
- heading_level=0: 正文内容
创建文档
def create_doc(doc_name: str, doc_type: int = 3):
"""
创建企业微信文档
Args:
doc_name: 文档名称
doc_type: 文档类型 (3=文档, 4=表格)
Returns:
dict: {"docid": "xxx", "url": "https://doc.weixin.qq.com/..."}
"""
token = get_access_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/wedoc/create_doc?access_token={token}"
resp = requests.post(url, json={
"doc_type": doc_type,
"doc_name": doc_name
})
return resp.json()
# 使用示例
result = create_doc("项目文档")
print(f"文档链接: {result['url']}")
获取文档内容
def get_doc_content(docid: str):
"""获取文档内容"""
token = get_access_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/wedoc/document/get?access_token={token}"
resp = requests.post(url, json={"docid": docid})
return resp.json()
编辑文档内容
def update_doc(docid: str, text: str, index: int = 0):
"""
更新文档内容
Args:
docid: 文档ID
text: 要插入的文本内容
index: 插入位置 (0=开头)
"""
token = get_access_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/wedoc/document/batch_update?access_token={token}"
resp = requests.post(url, json={
"docid": docid,
"requests": [
{
"insert_text": {
"text": text,
"location": {"index": index}
}
}
]
})
return resp.json()
# 使用示例
update_doc("DOCID", "# 标题\n\n这是正文内容")
获取文档列表
def list_docs(limit: int = 20):
"""获取文档列表"""
token = get_access_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/wedoc/doc_list?access_token={token}"
resp = requests.post(url, json={"limit": limit})
return resp.json()
上传图片到文档
import base64
def upload_doc_image(docid: str, image_path: str):
"""
上传图片到文档(获取图片 URL)
Args:
docid: 文档ID
image_path: 本地图片路径
Returns:
dict: {"url": "https://wdcdn.qpic.cn/...", "width": 1280, "height": 800}
"""
token = get_access_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/wedoc/image_upload?access_token={token}"
with open(image_path, "rb") as f:
img_base64 = base64.b64encode(f.read()).decode()
resp = requests.post(url, json={
"docid": docid,
"base64_content": img_base64
})
return resp.json()
# 使用示例
result = upload_doc_image("DOCID", "/tmp/screenshot.png")
print(f"图片 URL: {result['url']}")
插入图片到文档
def insert_image_to_doc(docid: str, image_url: str, index: int = 1):
"""
插入图片到文档
Args:
docid: 文档ID
image_url: 图片 URL(从 upload_doc_image 获取)
index: 插入位置
注意:使用 insert_paragraph + elements + image 格式
"""
token = get_access_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/wedoc/document/batch_update?access_token={token}"
resp = requests.post(url, json={
"docid": docid,
"requests": [
{
"insert_paragraph": {
"elements": [
{"image": {"url": image_url}}
],
"location": {"index": index}
}
}
]
})
return resp.json()
# 使用示例
insert_image_to_doc("DOCID", "https://wdcdn.qpic.cn/xxx", index=1)
获取文档末尾位置
def get_doc_end_index(docid: str) -> int:
"""获取文档末尾索引(用于追加内容)"""
doc = get_doc_content(docid)
if doc.get("errcode") != 0:
return 1
body = doc.get("document", {}).get("body", {})
blocks = body.get("blocks", [])
end_index = 1
for block in blocks:
if "paragraph" in block:
for elem in block["paragraph"].get("elements", []):
if "text_run" in elem:
end_index = max(end_index, elem["text_run"].get("end_index", 1))
return end_index
完整示例:截图并插入文档
import base64
from playwright.sync_api import sync_playwright
def screenshot_and_insert(url: str, docid: str, title: str = "网页截图"):
"""
截取网页并插入到文档
Args:
url: 要截取的网页 URL
docid: 目标文档 ID
title: 截图标题
"""
token = get_access_token()
# 1. 截取网页
print(f"截取网页: {url}")
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={"width": 1280, "height": 800})
page.goto(url, wait_until="networkidle")
page.screenshot(path="/tmp/screenshot.png")
browser.close()
# 2. 上传图片
print("上传图片...")
with open("/tmp/screenshot.png", "rb") as f:
img_base64 = base64.b64encode(f.read()).decode()
upload_resp = requests.post(
f"https://qyapi.weixin.qq.com/cgi-bin/wedoc/image_upload?access_token={token}",
json={"docid": docid, "base64_content": img_base64}
).json()
img_url = upload_resp.get("url")
# 3. 获取文档末尾位置
end_index = get_doc_end_index(docid)
# 4. 插入标题
requests.post(
f"https://qyapi.weixin.qq.com/cgi-bin/wedoc/document/batch_update?access_token={token}",
json={
"docid": docid,
"requests": [
{"insert_text": {"text": f"\n\n{title}\n\n", "location": {"index": end_index}}}
]
}
)
# 5. 插入图片
new_end = get_doc_end_index(docid)
insert_resp = requests.post(
f"https://qyapi.weixin.qq.com/cgi-bin/wedoc/document/batch_update?access_token={token}",
json={
"docid": docid,
"requests": [
{
"insert_paragraph": {
"elements": [{"image": {"url": img_url}}],
"location": {"index": new_end}
}
}
]
}
).json()
if insert_resp.get("errcode") == 0:
print("✅ 截图已插入文档!")
else:
print(f"❌ 插入失败: {insert_resp}")
# 使用示例
screenshot_and_insert("https://www.baidu.com", "YOUR_DOCID", "百度首页截图")
常见错误码
| 错误码 | 说明 | 解决方案 |
|---|---|---|
| 40001 | access_token 无效 | 重新获取 token |
| 40058 | 请求参数错误 | 检查 API 参数格式 |
| 48002 | API 未授权 | 在应用设置中开启对应 API 权限 |
| 60011 | 用户不存在 | 检查 userid 是否正确 |
| 60020 | IP 不在白名单 | 在应用设置中添加可信 IP |
| 81013 | 缺少通讯录权限 | 在应用权限中开启通讯录读取权限 |
| 44001 | 文档不存在 | 检查 docid 是否正确 |
| 2050065 | 插入位置无效 | 使用 get_doc_end_index 获取正确位置 |
| 2400001 | 请求参数错误 | 检查 insert_paragraph 格式 |
| 93017 | JSON 格式错误 | 图片上传需要使用 base64_content |
相关资源
| 资源 | 链接 |
|---|---|
| API 文档 | https://developer.work.weixin.qq.com/document/ |
| 调试工具 | https://developer.work.weixin.qq.com/devtool/interface |
| 管理后台 | https://work.weixin.qq.com/wework_admin/ |
详细内容
以下章节已移到 references/details.md:
- 通用函数封装