feat: 飞书多维表格(bitable)操作 skill:建表/字段/记录 CRUD、批量写入与踩坑要点

This commit is contained in:
NightStar
2026-08-03 18:34:17 +08:00
commit 09d8ddb65b
+101
View File
@@ -0,0 +1,101 @@
---
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,...`