ai_member_xiaoyan/skills/feishu-embedded-sheet/SKILL.md

225 lines
7.5 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: feishu-embedded-sheet
version: 1.0.0
description: |
飞书云文档中内嵌电子表格Sheet的读取与写入技能。
当飞书 docx 文档中包含 `<sheet token="xxx"/>` 内嵌表格时,使用本技能进行精准的行列级读写操作。
**触发场景:**
- 需要读取飞书文档中内嵌的 Excel/Sheet 表格数据
- 需要向飞书文档中内嵌的 Sheet 写入/更新数据
- 用户提到"文档里的表格"、"内嵌表格"、"剧本表格"等
- 从文档 markdown 中看到 `<sheet token="xxx_yyy"/>` 标签
metadata:
requires:
permissions: ["sheets:spreadsheet:readonly", "sheets:spreadsheet"]
identity: bot
---
# 飞书文档内嵌 Sheet 读写技能
## 核心概念
飞书 docx 文档可以内嵌电子表格Sheet。通过 `lark-cli docs +fetch` 获取文档 markdown 时,内嵌表格会渲染为:
```
<sheet token="WreDs73X1hrgdFtxdpJcItj2n5c_RuQopk"/>
```
**Token 结构解析:**
- 完整 token`WreDs73X1hrgdFtxdpJcItj2n5c_RuQopk`
- `_` 前面部分 = `spreadsheet_token``WreDs73X1hrgdFtxdpJcItj2n5c`
- `_` 后面部分 = `sheet_id``RuQopk`
同一个文档内嵌的多个 Sheet 共享同一个 `spreadsheet_token`,通过不同的 `sheet_id` 区分。
## 前置步骤:获取 Bot Token
所有操作均使用 **Bot 身份**执行,禁止触发用户授权。
```bash
APP_ID="cli_a931175d41799cc7"
APP_SECRET=$(jq -r '.apps[0].appSecret' /root/.openclaw/credentials/xiaoyan/config.json)
TOKEN=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
-H "Content-Type: application/json" \
-d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}" \
| jq -r '.tenant_access_token')
```
Token 有效期 2 小时,过期需重新获取。
## 完整执行链路
### 第一步:从文档中提取 Sheet Token
1. 先通过 `lark_wiki_operate_as_bot` 技能获取文档内容
2. 在返回的 markdown 中查找 `<sheet token="xxx"/>` 标签
3. 解析出 `spreadsheet_token``sheet_id`
```bash
# 获取文档内容(以 wiki 文档为例)
LARKSUITE_CLI_CONFIG_DIR=/root/.openclaw/credentials/xiaoyan \
lark-cli wiki spaces get_node --params '{"token":"<wiki_token>"}' --as bot
LARKSUITE_CLI_CONFIG_DIR=/root/.openclaw/credentials/xiaoyan \
lark-cli docs +fetch --doc <obj_token> --as bot
```
### 第二步:获取 Sheet 元数据(了解表结构)
```bash
curl -s -X GET \
"https://open.feishu.cn/open-apis/sheets/v3/spreadsheets/${SPREADSHEET_TOKEN}/sheets/query" \
-H "Authorization: Bearer $TOKEN" | jq '.'
```
返回信息包括:
- `sheet_id`:每个子表的 ID
- `title`:子表名称
- `grid_properties.row_count`:总行数
- `grid_properties.column_count`:总列数
- `grid_properties.frozen_row_count`:冻结行数(通常表头行)
- `merges`:合并单元格信息
### 第三步:读取数据
#### 读取指定范围
```bash
# 格式:{sheet_id}!{起始单元格}:{结束单元格}
curl -s -X GET \
"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values/${SHEET_ID}!A1:J196?valueRenderOption=ToString" \
-H "Authorization: Bearer $TOKEN" | jq '.data.valueRange.values'
```
**参数说明:**
- `valueRenderOption=ToString`:所有值转为字符串返回(推荐,避免类型混乱)
- Range 格式:`{sheet_id}!{列字母}{行号}:{列字母}{行号}`
- 行号从 1 开始列用字母表示A=1, B=2, ..., Z=26, AA=27...
#### 读取全表
先从元数据获取 `row_count``column_count`,然后构造完整 range
```bash
# 例10列196行
curl -s -X GET \
"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values/${SHEET_ID}!A1:J196?valueRenderOption=ToString" \
-H "Authorization: Bearer $TOKEN"
```
#### 读取结果处理
返回的 `values` 是二维数组,每个元素是一行:
```json
{
"data": {
"valueRange": {
"values": [
["类型", "组件配置", "ID", ...], // 第1行表头
["TL\nxxx", "S1前置xxx", null, ...], // 第2行
...
]
}
}
}
```
- `null` 表示空单元格
- 换行符在值中以 `\n` 表示
- 合并单元格:只有左上角单元格有值,其余为 `null`
### 第四步:写入数据
#### 写入/更新指定行
```bash
curl -s -X PUT \
"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"valueRange": {
"range": "'${SHEET_ID}'!A197:J197",
"values": [
["对话测试", "S99主线\n自动\n对话测试", "9999901", "剧情描述", "User", "台词", "User", "润色台词", null, "知识点"]
]
}
}'
```
#### 批量写入多行
```bash
curl -s -X PUT \
"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"valueRange": {
"range": "'${SHEET_ID}'!A197:J199",
"values": [
["行1列A", "行1列B", ...],
["行2列A", "行2列B", ...],
["行3列A", "行3列B", ...]
]
}
}'
```
#### 更新指定单元格
```bash
# 只更新单个单元格
curl -s -X PUT \
"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"valueRange": {
"range": "'${SHEET_ID}'!H50:H50",
"values": [["更新后的台词润色内容"]]
}
}'
```
#### 清空单元格
写入空字符串 `""` 即可清空单元格内容。
### 第五步:写入后验证
**必须回读验证**,确保写入内容与预期一致:
```bash
curl -s -X GET \
"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values/${SHEET_ID}!A197:J197?valueRenderOption=ToString" \
-H "Authorization: Bearer $TOKEN" | jq '.data.valueRange.values'
```
## 注意事项
1. **身份限制**:所有操作使用 Bot 身份,需要 Bot 应用对目标文档有编辑权限
2. **权限要求**Bot 需在飞书开发者后台开通 `sheets:spreadsheet` 权限;目标文档/知识空间需将 Bot 添加为成员并授予编辑权限
3. **合并单元格**:写入合并单元格区域时,只写入左上角单元格即可,其余位置保持 null
4. **行数限制**:单次读取/写入建议不超过 500 行,超大表格请分批操作
5. **并发写入**:避免同时多次写入同一个 Sheet可能导致数据覆盖
6. **数据类型**:写入时,数字直接用 number 类型,文本用 string空值用 null
7. **换行符**:需要在单元格内换行时,在字符串中使用 `\n`
## 异常处理
| 错误码 | 含义 | 处理方式 |
|--------|------|---------|
| `1310251` | spreadsheet_token 格式错误 | 检查是否正确从 sheet token 中拆分出 spreadsheet_token |
| `1310201` | 无权限 | Bot 未被添加为文档/知识空间成员,需用户授权 |
| `1310212` | Range 格式错误 | 检查 sheet_id 和单元格范围格式 |
| `1310214` | 超出表格范围 | 检查行列号是否超出实际表格大小 |
## 与其他技能的配合
- **读取文档内容**:先用 `lark_wiki_operate_as_bot` 技能获取文档 markdown从中提取 `<sheet>` 标签
- **多维表格操作**如果目标是独立的多维表格Bitable应使用 `lark_bitable_operate_as_bot` 技能,而非本技能
- **文档写入**:如果需要修改文档中 Sheet 以外的内容(文本、表格等),使用 `feishu-update-doc` 技能