|
|
@@ -7,15 +7,16 @@
|
|
|
// · pullLake — 把 AI 表格记录拉回本地湖(其他机器补数据用,云端为准)
|
|
|
// 业务键:日期|账号名|维度|门店ID(与本地 rowKey 语义对齐,幂等可重跑)。
|
|
|
//
|
|
|
-// 钉钉侧契约(企业内部应用 access_token,域 api.dingtalk.com):
|
|
|
-// token: POST /v1.0/oauth2/accessToken {appKey, appSecret} → {accessToken, expireIn}
|
|
|
-// 记录: /v1.0/notable/bases/{baseId}/sheets/{sheetName}/records
|
|
|
-// POST 批量新增 / PUT 批量更新 / GET 分页列表
|
|
|
-// ⚠ 所有 notable 接口必须在 query 上带 operatorId=操作人 unionId(企业内部应用
|
|
|
-// 无法从 token 推出用户身份;unionId 用 scripts/aitable-discover.js 发现一次后
|
|
|
-// 配到 config 的 aitable.operatorId,同一组织内固定不变)。
|
|
|
-// ⚠ 端点形态与批量上限在首次真机联调时核对——所有钉钉细节都收敛在本文件,
|
|
|
-// 如有偏差只需改这里的常量与两个 transport 方法。
|
|
|
+// 钉钉侧契约(企业内部应用 access_token,域 api.dingtalk.com;2026-10-17 真机核对):
|
|
|
+// token: POST /v1.0/oauth2/accessToken {appKey, appSecret} → {accessToken, expireIn}
|
|
|
+// 列记录: GET …/records?operatorId&maxResults&nextToken → {records:[{id,fields}],nextToken,hasMore}
|
|
|
+// 新增: POST …/records {records:[{fields}]} → {value:[{id}]}(响应键是 value)
|
|
|
+// 更新: PUT …/records {records:[{id,fields}]}(记录标识键是 id,不是 record_id)
|
|
|
+// 删除: POST …/records/delete {recordIds:[…]}(同步语义只 upsert,用不到)
|
|
|
+// · 所有 notable 接口 query 必带 operatorId=操作人 unionId(scripts/aitable-discover.js 发现)
|
|
|
+// · 数值字段读回是字符串("12345.67"),recordToRow 已做 Number() 归一
|
|
|
+// · number 列 formatter=INT 只影响显示,存储小数保真
|
|
|
+// ⚠ 批量上限(100)是保守值,首推大批量时如遇限流再调。
|
|
|
|
|
|
const fs = require('fs');
|
|
|
const path = require('path');
|
|
|
@@ -251,12 +252,12 @@ function createAitableService(ctx) {
|
|
|
let created = 0;
|
|
|
let updated = 0;
|
|
|
const toCreate = [];
|
|
|
- const toUpdate = []; // {recordId, fields}
|
|
|
+ const toUpdate = []; // {id, fields}(更新接口的记录标识键是 id,不是 record_id)
|
|
|
for (const row of rows) {
|
|
|
const rec = rowToRecord(row, accountName);
|
|
|
const k = recordKey(rec.fields);
|
|
|
const rid = existing.get(k);
|
|
|
- if (rid) toUpdate.push({ record_id: rid, fields: rec.fields });
|
|
|
+ if (rid) toUpdate.push({ id: rid, fields: rec.fields });
|
|
|
else toCreate.push(rec);
|
|
|
}
|
|
|
for (const part of chunk(toCreate, INSERT_CHUNK)) {
|