Files
ai-proj-helper/skills-integration/wecom-plugin/skills/SKILL.md
T
johnQ 237631147a chore(skill): 清理全部 23 条历史校验警告
- 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
2026-10-31 22:21:07 +08:00

514 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: wecom
description: 企业微信集成。通过自然语言发送消息、管理群机器人、操作审批流程、管理通讯录。当用户提到企业微信、微信工作、群机器人、企业号、wecom相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
## 功能概述
### 消息推送
- **应用消息**: 向指定用户/部门发送文本、图片、文件等消息
- **群机器人**: 通过 Webhook 向群聊发送消息
- **模板消息**: 发送结构化的卡片消息
### 通讯录管理
- **部门管理**: 查询、创建、更新部门
- **成员管理**: 查询、创建、更新成员信息
### 审批流程
- **发起审批**: 通过 API 发起审批申请
- **审批状态**: 查询审批单状态
---
## 环境配置
### 已配置的企业微信应用
| 配置项 | 值 |
|--------|-----|
| 企业ID (CorpID) | `ww8ab927306fa235d2` |
| 应用ID (AgentId) | `1000003` |
| 可信域名 | `wecom.pipexerp.com` |
### 环境变量
```bash
# ~/.zshrc 已配置
export WECOM_CORP_ID="ww8ab927306fa235d2"
export WECOM_AGENT_ID="1000003"
export WECOM_SECRET="Dts8BmENzjxCRK1Qn4qmkO6mU81FLVEkhI2LitcBcjI"
```
---
## API 基础
### 获取 Access Token
```python
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}")
```
---
## 消息推送
### 发送文本消息
```python
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 消息
```python
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()
```
### 发送卡片消息
```python
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
```python
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"])
```
---
## 通讯录管理
### 获取部门列表
```python
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()
```
### 获取部门成员
```python
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: 正文内容
---
### 创建文档
```python
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']}")
```
### 获取文档内容
```python
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()
```
### 编辑文档内容
```python
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这是正文内容")
```
### 获取文档列表
```python
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()
```
### 上传图片到文档
```python
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']}")
```
### 插入图片到文档
```python
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)
```
### 获取文档末尾位置
```python
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
```
### 完整示例:截图并插入文档
```python
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](references/details.md):
- 通用函数封装