Files
teamai-global/skills/feishu-bitable/SKILL.md
T
NightStar 3d3dd79df0 Add 39 shared skills from local agent inventory
Sources: ~/.openclaw/skills, ~/.agents/skills, workshop-skills, workspace/skills
2026-09-10 16:54:57 +08:00

102 lines
5.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-bitable"
description: "飞书多维表格(bitable)全流程操作:建表、字段/记录 CRUD、批量写入,含主字段改名与删字段防丢数据等踩坑要点。"
metadata:
author: xf
version: "1.0.0"
---
# 飞书多维表格(Bitable)操作
创建/维护飞书多维表格的完整流程。基于 2026-08-03 创建「雨云 API 接口管理表」(437 条记录)实战验证。
## 前置条件
- 应用已开通 `bitable:app` 权限(未开通会报 `99991672 Access denied`,需去开放平台申请)
- 可复用 `feishu-wiki-tools` 的 `init_token.py` 获取 tenant_access_token:
```bash
cd ~/.openclaw/workspace/skills/feishu-wiki-tools
python3 - <<'EOF'
import json, subprocess, requests
r = subprocess.run(['python3', 'scripts/init_token.py'], capture_output=True, text=True)
token = json.loads(r.stdout)['token']
h = {'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}
EOF
```
## 核心 API
| 操作 | 端点 | 说明 |
|------|------|------|
| 创建应用 | `POST /open-apis/bitable/v1/apps` | body `{name}`,返回 `app_token` + `default_table_id` |
| 建字段 | `POST /apps/{APP}/tables/{TBL}/fields` | body `{field_name, type}` |
| 改字段 | `PUT /apps/{APP}/tables/{TBL}/fields/{fid}` | **改主字段名必须带 `type` + `ui_type`** |
| 删字段 | `DELETE /apps/{APP}/tables/{TBL}/fields/{fid}` | ⚠️ 连带删除该列全部数据 |
| 列字段 | `GET /apps/{APP}/tables/{TBL}/fields?page_size=100` | 响应含 `is_primary` 标记 |
| 批量写入 | `POST /apps/{APP}/tables/{TBL}/records/batch_create` | body `{records:[{fields:{...}}]}`,≤100/批稳妥 |
| 批量更新 | `POST /apps/{APP}/tables/{TBL}/records/batch_update` | 同上 |
| 批量删除 | `POST /apps/{APP}/tables/{TBL}/records/batch_delete` | body `{records:[record_id...]}` |
| 列表分页 | `GET /apps/{APP}/tables/{TBL}/records?page_size=500&page_token=...` | 循环直到 `has_more=false` |
| 搜索统计 | `POST /apps/{APP}/tables/{TBL}/records/search` | body `{page_size:1}`,`data.total` 拿总数 |
## 字段类型速查
`1=Text`、`3=SingleSelect`、`5=DateTime`、`17=Attachment`
## ⚠️ 建表标准流程(顺序很重要)
1. **创建应用** → 拿到 `app_token`、`default_table_id`
2. **先清默认行**:新建表自带 10 条空记录,`batch_delete` 删掉
3. **先删默认字段**:自带「文本/单选/日期/附件」4 列中,**「文本」是主字段删不掉**,其余 3 个直接删掉
4. **改造主字段**:把删不掉的主字段「文本」改造成自己需要的列(如「接口路径」)——`PUT /fields/{fid}`,body 必须带 `type` + `ui_type`(如 `{"field_name":"接口路径","type":1,"ui_type":"Text"}`)
5. **添加剩余自己的字段**:`POST /fields` 逐个建(方法、摘要、参数…)
6. **写入数据**:`batch_create` 分批(100/批 + `time.sleep(0.3)` 限速)
7. **验证**:`records/search` 拿 total 核对 == 写入条数
## 🕳️ 踩坑记录(全部实战踩过)
1. **主字段(Primary Field)不可删除**(报 `1254046 The Primary Field cannot be deleted`)。只能改名复用:`PUT /fields/{fid}`,**body 必须带 `type` + `ui_type`**(如 `{"field_name":"接口路径","type":1,"ui_type":"Text"}`),否则报 `99992402 field validation failed`。所以正确姿势是**先把它改造成自己的字段**,而不是新建一个同义字段再删旧的。
2. **删字段 = 删数据**:删除字段会把该列所有记录值一起删掉,不可恢复。删之前必须:① 确认本地有备份,或 ② 先把数据迁到别的字段(batch_update 逐批迁移后再删)。
3. **改名失败后不要连锁删字段**:字段改名失败(99992402)时,后续依赖新字段名的操作会全部失败(1254045 field not found),此时若顺手把旧字段删了会造成数据丢失。改名前先验证字段存在。
4. **批量写入上限**:官方上限 500/次,实测 100/批最稳;批量间加 0.3s 间隔避免限流。
5. **记录顺序对应**:批量创建后按列表顺序取回,与源数据顺序一致,可用于按序回填/迁移。
## 完整示例(标准流程)
```python
APP = 'xxx' # 创建返回的 app_token
TBL = 'xxx' # default_table_id
h = {'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}
# 1. 读默认空记录并删除(10 条自带空行)
recs = ... # GET records 分页拉全
empty = [r['record_id'] for r in recs if not r['fields']]
requests.post(f'.../records/batch_delete', headers=h, json={'records': empty})
# 2. 删默认字段(跳过 is_primary 的「文本」)
for f in fields:
if not f.get('is_primary') and f['field_name'] in ('单选','日期','附件'):
requests.delete(f'.../fields/{f["field_id"]}', headers=h)
# 3. 改造主字段「文本」→ 自己的字段
requests.put(f'.../fields/{primary_fid}', headers=h,
json={'field_name': '接口路径', 'type': 1, 'ui_type': 'Text'})
# 4. 添加剩余字段
for name, ftype in [('方法',3),('接口摘要',1),('参数',1)]:
requests.post(f'.../apps/{APP}/tables/{TBL}/fields', headers=h,
json={'field_name': name, 'type': ftype})
# 5. 批量写数据
rows = [...] # [{fields: {...}}, ...]
for i in range(0, len(rows), 100):
requests.post(f'.../records/batch_create', headers=h, json={'records': rows[i:i+100]})
time.sleep(0.3)
```
## 关联
- `feishu-wiki-tools` — 知识库/docx 写入,本 skill 专注 bitable 多维表格
- 权限申请链接格式:`https://open.feishu.cn/app/{app_id}/auth?q=bitable:app,...`