37c 多维表格自动化
上一篇: 37b 飞书机器人与 MCP 搭建 | 下一篇: 37d Agent 管理与 Skill 体系
本篇设计飞书多维表格的 Schema 体系,实现 Skill 自动创建表格、MCP CRUD 操作、Webhook 事件触发,以及数据同步到 PostgreSQL 分析层。多维表格是团队日常操作的数据入口,PostgreSQL 是跨表分析的计算引擎。
1. 多维表格 Schema 设计
以 HackQuest 团队为例,设计 4 张核心管理表。所有表格放在同一个多维表格应用中,便于跨表关联。
1.1 需求表(Requirements)
| 字段名 | 字段类型 | 说明 | 示例值 |
|---|---|---|---|
| 标题 | 文本 | 需求标题,不超过 50 字 | 新增 Solana 课程模块 |
| 描述 | 多行文本 | 包含背景和验收标准 | 背景:用户对 Solana 生态学习需求增长… |
| 优先级 | 单选 | P0/P1/P2/P3 | P1 |
| 状态 | 单选 | 待评审/已通过/设计中/开发中/测试中/待部署/已上线/已关闭 | 开发中 |
| 负责人 | 人员 | 飞书用户 | 张三 |
| 所属模块 | 单选 | 课程/Hackathon/社区/基础设施/运营 | 课程 |
| 迭代 | 关联 | 关联迭代表 | Sprint 2026-W28 |
| PRD 链接 | 超链接 | 关联 PRD 文档 | https://xxx.feishu.cn/docx/ … |
| 创建时间 | 创建时间 | 自动填充 | 2026-07-15 |
| 创建人 | 创建人 | 自动填充 | 李四 |
| 预计工时 | 数字 | 人天 | 5 |
| 实际工时 | 数字 | 人天 | 7 |
1.2 缺陷表(Bugs)
| 字段名 | 字段类型 | 说明 | 示例值 |
|---|---|---|---|
| 标题 | 文本 | 缺陷标题 | 课程进度条在 Safari 上显示异常 |
| 描述 | 多行文本 | 复现步骤 + 预期 + 实际 | 步骤:1. 打开 Safari… |
| 严重程度 | 单选 | S0-致命/S1-严重/S2-一般/S3-轻微 | S2 |
| 状态 | 单选 | 待确认/已确认/修复中/待验证/已关闭 | 修复中 |
| 负责人 | 人员 | 飞书用户 | 王五 |
| 关联需求 | 关联 | 关联需求表 | 新增 Solana 课程模块 |
| 环境 | 多选 | 生产/预发/测试 | 生产 |
| 创建时间 | 创建时间 | 自动填充 | 2026-07-16 |
| 修复时间 | 日期 | 手动或 Agent 填写 | 2026-07-17 |
1.3 迭代表(Sprints)
| 字段名 | 字段类型 | 说明 | 示例值 |
|---|---|---|---|
| 迭代名称 | 文本 | 格式:Sprint YYYY-Wxx | Sprint 2026-W28 |
| 开始日期 | 日期 | 迭代开始 | 2026-07-13 |
| 结束日期 | 日期 | 迭代结束 | 2026-07-27 |
| 状态 | 单选 | 规划中/进行中/已完成 | 进行中 |
| 目标 | 多行文本 | 迭代目标描述 | 完成 Solana 课程第一阶段 |
| 需求数 | 公式 | 自动统计关联需求数 | 8 |
| 完成率 | 公式 | 已上线需求数/总需求数 | 62.5% |
1.4 人员表(Team)
| 字段名 | 字段类型 | 说明 | 示例值 |
|---|---|---|---|
| 姓名 | 文本 | 成员姓名 | 张三 |
| 角色 | 单选 | 前端/后端/产品/设计/测试/运维/运营 | 前端 |
| 部门 | 单选 | 产品部/工程部/运营部/人事部 | 工程部 |
| 飞书 ID | 文本 | 飞书 open_id | ou_xxxxxxxxxx |
| GitHub ID | 文本 | GitHub 用户名 | zhangsan-dev |
| 入职日期 | 日期 | 2025-03-01 | |
| 状态 | 单选 | 在职/离职/试用期 | 在职 |
2. Skill 自动创建多维表格
编写一个初始化 Skill,自动创建上述 4 张表格。这个 Skill 通常只在项目初始化时执行一次。
2.1 初始化 Skill
创建 skills/setup-bitable.md:
# setup-bitable
初始化 HackQuest 项目管理多维表格,创建需求表、缺陷表、迭代表、人员表。
## 触发条件
用户消息包含"初始化表格"、"创建项目表格"、"setup bitable"。
## 执行步骤
1. 调用 lark-mcp 创建一个新的多维表格应用,名称为"HackQuest 项目管理"
2. 在该应用中依次创建 4 张表:需求表、缺陷表、迭代表、人员表
3. 为每张表按照预定义 Schema 创建字段
4. 在需求表和缺陷表之间建立关联关系
5. 在需求表和迭代表之间建立关联关系
6. 创建完成后,将多维表格的 app_token 写入记忆,供后续 Skill 使用
7. 在飞书群发送创建成功的通知,附上多维表格链接
## 字段定义
### 需求表字段
- 标题(文本)
- 描述(多行文本)
- 优先级(单选:P0, P1, P2, P3)
- 状态(单选:待评审, 已通过, 设计中, 开发中, 测试中, 待部署, 已上线, 已关闭)
- 负责人(人员)
- 所属模块(单选:课程, Hackathon, 社区, 基础设施, 运营)
- PRD 链接(超链接)
- 预计工时(数字)
- 实际工时(数字)
### 缺陷表字段
- 标题(文本)
- 描述(多行文本)
- 严重程度(单选:S0-致命, S1-严重, S2-一般, S3-轻微)
- 状态(单选:待确认, 已确认, 修复中, 待验证, 已关闭)
- 负责人(人员)
- 环境(多选:生产, 预发, 测试)
### 迭代表字段
- 迭代名称(文本)
- 开始日期(日期)
- 结束日期(日期)
- 状态(单选:规划中, 进行中, 已完成)
- 目标(多行文本)
### 人员表字段
- 姓名(文本)
- 角色(单选:前端, 后端, 产品, 设计, 测试, 运维, 运营)
- 部门(单选:产品部, 工程部, 运营部, 人事部)
- 飞书 ID(文本)
- GitHub ID(文本)
- 入职日期(日期)
- 状态(单选:在职, 离职, 试用期)
## 输出格式
创建成功后回复:
✅ 项目管理表格已创建完成
- 需求表:[链接]
- 缺陷表:[链接]
- 迭代表:[链接]
- 人员表:[链接]
## 权限要求
- 飞书多维表格写入权限(bitable:app)2.2 字段类型映射
飞书多维表格 API 中的字段类型编号:
| 字段类型 | type 值 | 说明 |
|---|---|---|
| 文本 | 1 | 单行文本 |
| 数字 | 2 | 数字 |
| 单选 | 3 | 下拉单选 |
| 多选 | 4 | 下拉多选 |
| 日期 | 5 | 日期时间 |
| 复选框 | 7 | 布尔值 |
| 人员 | 11 | 飞书用户 |
| 超链接 | 15 | URL |
| 关联 | 18 | 关联其他表 |
| 创建时间 | 1001 | 自动填充 |
| 修改时间 | 1002 | 自动填充 |
| 创建人 | 1003 | 自动填充 |
| 修改人 | 1004 | 自动填充 |
| 公式 | 20 | 计算字段 |
| 多行文本 | 22 | 富文本 |
注意:字段类型编号以飞书开放平台最新文档为准,不同 API 版本可能有差异。
3. MCP CRUD 操作示例
通过 lark-mcp 对多维表格进行增删改查操作。以下展示 Agent 在 Skill 执行过程中调用 MCP 工具的典型场景。
3.1 创建记录(需求)
当用户说”创建一个 P1 需求:新增 Solana 课程模块”时,需求收集 Skill 会调用 lark-mcp 创建记录:
{
"tool": "create_bitable_record",
"arguments": {
"app_token": "bascnxxxxxxxxxx",
"table_id": "tblxxxxxxxxxx",
"fields": {
"标题": "新增 Solana 课程模块",
"描述": "背景:用户对 Solana 生态学习需求增长,需要新增完整的 Solana 开发课程。\n验收标准:包含 Solana 基础、智能合约、DApp 开发三个阶段。",
"优先级": "P1",
"状态": "待评审",
"所属模块": "课程"
}
}
}3.2 查询记录
查询当前迭代的所有进行中需求:
{
"tool": "list_bitable_records",
"arguments": {
"app_token": "bascnxxxxxxxxxx",
"table_id": "tblxxxxxxxxxx",
"filter": {
"conjunction": "and",
"conditions": [
{ "field_name": "状态", "operator": "is", "value": ["开发中"] },
{ "field_name": "迭代", "operator": "is", "value": ["Sprint 2026-W28"] }
]
},
"sort": [
{ "field_name": "优先级", "order": "asc" }
]
}
}3.3 更新记录
需求状态流转(从”开发中”到”测试中”):
{
"tool": "update_bitable_record",
"arguments": {
"app_token": "bascnxxxxxxxxxx",
"table_id": "tblxxxxxxxxxx",
"record_id": "recxxxxxxxxxx",
"fields": {
"状态": "测试中"
}
}
}3.4 批量操作
批量创建迭代计划中的需求:
{
"tool": "batch_create_bitable_records",
"arguments": {
"app_token": "bascnxxxxxxxxxx",
"table_id": "tblxxxxxxxxxx",
"records": [
{
"fields": {
"标题": "Solana 基础概念课程",
"优先级": "P1",
"状态": "待评审",
"所属模块": "课程"
}
},
{
"fields": {
"标题": "Solana 智能合约开发课程",
"优先级": "P1",
"状态": "待评审",
"所属模块": "课程"
}
}
]
}
}注意:以上 MCP 工具名称和参数格式以 lark-mcp 实际提供的工具为准。可通过
openclaw mcp tools lark-mcp查看完整工具列表和参数定义。
4. Webhook 事件触发
多维表格的变更事件可以触发 Agent 自动执行后续操作,实现事件驱动的工作流。
4.1 事件类型
| 事件 | 触发时机 | 典型用途 |
|---|---|---|
| 记录创建 | 新增一条记录 | 新需求通知评审群 |
| 记录更新 | 修改记录字段 | 状态变更触发下一步流程 |
| 记录删除 | 删除一条记录 | 记录删除日志 |
4.2 事件处理 Skill
创建 skills/requirement-status-change.md:
# requirement-status-change
监听需求表状态变更事件,自动触发对应的下一步操作。
## 触发条件
飞书多维表格记录变更事件(drive.file.bitable_record_changed_v1),
且变更的表为需求表,且变更的字段包含"状态"。
## 执行步骤
### 状态:待评审 → 已通过
1. 在需求评审群发送通知:"需求 [标题] 已通过评审,负责人 [负责人]"
2. 自动创建设计任务(如果需要设计)
3. 更新记忆中的需求状态
### 状态:已通过 → 开发中
1. 通知开发负责人
2. 检查是否有关联的 GitHub Issue,如果没有则自动创建
### 状态:开发中 → 测试中
1. 通知测试负责人
2. 关联相关 PR 信息
### 状态:测试中 → 待部署
1. 通知运维团队
2. 生成部署清单
### 状态:待部署 → 已上线
1. 在项目群发送上线通知
2. 更新迭代完成率
## 权限要求
- 飞书消息发送权限
- 飞书多维表格读取权限
- GitHub MCP(创建 Issue)4.3 事件过滤策略
不是所有多维表格变更都需要处理。在 Skill 中定义过滤条件:
## 事件过滤
- 只处理需求表和缺陷表的变更,忽略人员表和迭代表的变更
- 只处理"状态"字段的变更,忽略其他字段的修改
- 忽略 Agent 自身触发的变更(通过操作人 ID 判断),避免循环触发5. 数据同步到 PostgreSQL
5.1 为什么需要同步
飞书多维表格适合日常操作,但不适合复杂分析:
| 需求 | 多维表格 | PostgreSQL |
|---|---|---|
| 团队成员查看和编辑需求 | ✅ 直接操作 | ❌ 需要额外界面 |
| 跨表 JOIN 查询 | ❌ 关联字段能力有限 | ✅ 标准 SQL |
| 聚合统计(GROUP BY) | ❌ 不支持 | ✅ 完整支持 |
| 时序趋势分析 | ❌ 无窗口函数 | ✅ 窗口函数 |
| 数据量 > 5万行 | ❌ 单表上限 | ✅ 无限制 |
| 与业务数据关联 | ❌ 数据隔离 | ✅ 同库查询 |
5.2 PostgreSQL Schema
-- 需求表
CREATE TABLE requirements (
id SERIAL PRIMARY KEY,
bitable_record_id VARCHAR(50) UNIQUE NOT NULL, -- 多维表格记录 ID
title VARCHAR(200) NOT NULL,
description TEXT,
priority VARCHAR(10), -- P0/P1/P2/P3
status VARCHAR(20),
assignee VARCHAR(100),
module VARCHAR(50),
sprint_name VARCHAR(50),
prd_link TEXT,
estimated_hours DECIMAL(5,1),
actual_hours DECIMAL(5,1),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
synced_at TIMESTAMP DEFAULT NOW() -- 最后同步时间
);
-- 缺陷表
CREATE TABLE bugs (
id SERIAL PRIMARY KEY,
bitable_record_id VARCHAR(50) UNIQUE NOT NULL,
title VARCHAR(200) NOT NULL,
description TEXT,
severity VARCHAR(20), -- S0/S1/S2/S3
status VARCHAR(20),
assignee VARCHAR(100),
requirement_id INTEGER REFERENCES requirements(id),
environment TEXT[], -- PostgreSQL 数组类型
created_at TIMESTAMP DEFAULT NOW(),
fixed_at TIMESTAMP,
synced_at TIMESTAMP DEFAULT NOW()
);
-- 迭代表
CREATE TABLE sprints (
id SERIAL PRIMARY KEY,
bitable_record_id VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(50) NOT NULL,
start_date DATE,
end_date DATE,
status VARCHAR(20),
goal TEXT,
synced_at TIMESTAMP DEFAULT NOW()
);
-- 人员表
CREATE TABLE team_members (
id SERIAL PRIMARY KEY,
bitable_record_id VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
role VARCHAR(50),
department VARCHAR(50),
feishu_id VARCHAR(100),
github_id VARCHAR(100),
join_date DATE,
status VARCHAR(20),
synced_at TIMESTAMP DEFAULT NOW()
);
-- 索引
CREATE INDEX idx_requirements_status ON requirements(status);
CREATE INDEX idx_requirements_sprint ON requirements(sprint_name);
CREATE INDEX idx_requirements_assignee ON requirements(assignee);
CREATE INDEX idx_bugs_status ON bugs(status);
CREATE INDEX idx_bugs_severity ON bugs(severity);5.3 同步方案
创建 skills/sync-bitable-to-pg.md:
# sync-bitable-to-pg
定时将飞书多维表格数据同步到 PostgreSQL 分析层。
## 触发条件
- 定时触发:每小时执行一次
- 手动触发:用户消息包含"同步数据"、"sync data"
## 执行步骤
1. 从记忆中读取多维表格 app_token 和各表 table_id
2. 通过 lark-mcp 读取需求表全部记录
3. 对比 PostgreSQL 中已有记录(通过 bitable_record_id 匹配)
4. 执行 UPSERT 操作:新记录插入,已有记录更新
5. 对缺陷表、迭代表、人员表重复步骤 2-4
6. 记录同步结果到记忆(同步时间、记录数、变更数)
7. 如果同步失败,在飞书群发送告警
## 同步策略
- 使用 bitable_record_id 作为唯一标识进行 UPSERT
- 只同步最近 24 小时有变更的记录(增量同步)
- 每周日凌晨执行一次全量同步
- 同步过程中不阻塞其他 Skill 执行
## 错误处理
- 单条记录同步失败不影响其他记录
- 连续 3 次同步失败后发送告警到运维群5.4 UPSERT SQL 示例
-- 需求表 UPSERT
INSERT INTO requirements (
bitable_record_id, title, description, priority, status,
assignee, module, sprint_name, prd_link,
estimated_hours, actual_hours, updated_at, synced_at
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, NOW(), NOW()
)
ON CONFLICT (bitable_record_id) DO UPDATE SET
title = EXCLUDED.title,
description = EXCLUDED.description,
priority = EXCLUDED.priority,
status = EXCLUDED.status,
assignee = EXCLUDED.assignee,
module = EXCLUDED.module,
sprint_name = EXCLUDED.sprint_name,
prd_link = EXCLUDED.prd_link,
estimated_hours = EXCLUDED.estimated_hours,
actual_hours = EXCLUDED.actual_hours,
updated_at = NOW(),
synced_at = NOW();5.5 数据一致性保障
| 策略 | 说明 |
|---|---|
| 幂等同步 | UPSERT 保证重复执行不会产生重复数据 |
| 增量 + 全量 | 日常增量同步 + 每周全量同步,防止数据漂移 |
| 同步日志 | 每次同步记录到 OpenClaw 记忆,可追溯 |
| 冲突处理 | 以多维表格为主数据源,PostgreSQL 为只读副本 |
| 延迟容忍 | 分析层数据最多延迟 1 小时,对报表场景可接受 |
6. 实用查询示例
同步到 PostgreSQL 后,数据分析 Skill 可以执行复杂查询:
-- 当前迭代需求完成率
SELECT
s.name AS sprint,
COUNT(*) AS total,
COUNT(*) FILTER (WHERE r.status = '已上线') AS completed,
ROUND(COUNT(*) FILTER (WHERE r.status = '已上线') * 100.0 / COUNT(*), 1) AS completion_rate
FROM requirements r
JOIN sprints s ON r.sprint_name = s.name
WHERE s.status = '进行中'
GROUP BY s.name;
-- 各模块缺陷密度
SELECT
r.module,
COUNT(DISTINCT r.id) AS requirement_count,
COUNT(DISTINCT b.id) AS bug_count,
ROUND(COUNT(DISTINCT b.id) * 1.0 / NULLIF(COUNT(DISTINCT r.id), 0), 2) AS bug_density
FROM requirements r
LEFT JOIN bugs b ON b.requirement_id = r.id
GROUP BY r.module
ORDER BY bug_density DESC;
-- 团队成员工作负载
SELECT
tm.name,
tm.role,
COUNT(r.id) FILTER (WHERE r.status IN ('开发中', '测试中')) AS active_tasks,
SUM(r.estimated_hours) FILTER (WHERE r.status IN ('开发中', '测试中')) AS estimated_hours
FROM team_members tm
LEFT JOIN requirements r ON r.assignee = tm.name
WHERE tm.status = '在职'
GROUP BY tm.name, tm.role
ORDER BY active_tasks DESC;下一篇: 37d Agent 管理与 Skill 体系 — Skill 文件规范、版本管理、权限控制和质量保障体系