Github: https://github.com/autable/autable
主页以及文档: https://autable.github.io/
最近我在尝试把一些公司内部的流程迁移到钉钉 AI 表格, 然而发现并不顺利
- 钉钉审批流程同步到 AI 表格之后, 会产生多条相同编号的记录, 钉钉的表单和自动化没有任何办法处理这个问题, 因为钉钉并没有把 unique 的 record id 暴露出来
- 钉钉 AI 表格的 AI 非常傻, 经常做不到一些简单的表单定义和自动化流程定义
- nocode 的自动化对于会写代码的人完全是负生产力
- 最大的问题, 即使付费, 默认最高也只有单表 5 万条记录
我也调研了一下开源方案, 一个问题就是 OIDC 登录基本都是付费功能, 商业版 self-host 普遍定价比钉钉/飞书的最高级别的订阅还贵
最终, 我搓了一个符合我需求的 AI 表格
- 支持表格, 自动化, 表单和字段级别的权限配置
- 自动化, 表格都使用简单的 js 定义, AI 友好的方式
- 支持公式字段, 公式同样使用 js 表达
- 存储使用 sqlite, 运维成本低, 最初的容灾方案每天备份一次就行了
- 支持 OIDC, GPL 3.0 license, 永远不用担心开原版缺失关键功能
目前刚跑通一个使用案例, 可以使用自动化同步钉钉 AI 表格的数据, 已经可以渐进式迁移, 并且可以借助这个打通钉钉内部所有数据的同步
下面是一个周期性同步钉钉 AI 表格的 workflow.js 例子
function instances(info) {
return {
timer: "time.schedule",
dingTable: "dingtalk.notable.records.list",
fields: "table.field.create",
rows: "table.row.upsert"
};
}
function trigger(info) {
return {
instance: "timer",
params: {
interval_ms: 5 * 60 * 1000
}
};
}
function run(info) {
const table = "同步表";
let nextToken = "";
while (true) {
const page = info.instance("dingTable").exec({
max_results: 100,
...(nextToken ? { next_token: nextToken } : {})
});
const records = page.records || [];
info.instance("fields").exec({
table,
fields: fieldsOf(records)
});
for (const record of records) {
info.instance("rows").exec({
table,
match_field: "dingtalk_record_id",
values: valuesOf(record)
});
}
nextToken = page.next_token || "";
if (!page.has_more || !nextToken) break;
}
return { ok: true, table };
}
function fieldsOf(records) {
const fields = {
dingtalk_record_id: "string"
};
for (const record of records) {
for (const name of Object.keys(record.fields || {})) {
fields[name] = "string";
}
}
return fields;
}
function valuesOf(record) {
return {
dingtalk_record_id: String(record.id || ""),
...Object.fromEntries(
Object.entries(record.fields || {}).map(([name, value]) => [
name,
stableStringify(value)
])
)
};
}