From bea4c746ae7079a24aedffc06f7df180290f3243 Mon Sep 17 00:00:00 2001 From: zhengzhijie Date: Tue, 26 May 2026 19:29:44 +0800 Subject: [PATCH 1/2] =?UTF-8?q?docs(sheets):=20sync=20float-image=20refere?= =?UTF-8?q?nce=20from=20spec=20=E2=80=94=20fix=20non-runnable=20examples?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two examples in skills/lark-sheets/references/lark-sheets-float-image.md didn't actually run against PPE; sync brings them in line with CLI behavior: - +float-image-create local-path example missed --image-name (CLI rejects with `required flag(s) "image-name" not set` even when path basename already has the filename). Add `--image-name "logo.png"` + inline note. - +float-image-update "only change position" example missed image source (CLI rejects with `one of --image, --image-token, or --image-uri is required`). Expand to two steps: list with --jq pulls the current image_token, then update re-passes --image-token to satisfy the guard. - Leading warning realigned: image source is mandatory on every update call; "keep original image" still requires passing the token explicitly. Upstream change: sheet-skill-spec MR fix/float-image-reference-examples. --- .../references/lark-sheets-chart.md | 132 ++++++++++++++++-- .../references/lark-sheets-float-image.md | 26 ++-- 2 files changed, 140 insertions(+), 18 deletions(-) diff --git a/skills/lark-sheets/references/lark-sheets-chart.md b/skills/lark-sheets/references/lark-sheets-chart.md index b477e7742..23819ffa5 100644 --- a/skills/lark-sheets/references/lark-sheets-chart.md +++ b/skills/lark-sheets/references/lark-sheets-chart.md @@ -162,27 +162,139 @@ _创建/更新的图表属性_ ### `+chart-create` -示例: +> **`snapshot.data` 必填 `dim1.serie.index` 或 `dim2.series[].index` 之一**(1-based,对应 `refs.value` 范围内的列序)。schema 允许传空 `{}` 但 server 运行时强制:缺则被拒为 `snapshot.data.dim1.serie.index and dim2.series[].index are both missing; at least one must be set`,即便侥幸通过也只会渲染空图。 + +最小可用列图(inline 模式:refs 含表头行): ```bash -# 内联 JSON —— 最小列图骨架(inline 模式:refs 含表头行,首列/首行即类别/系列名) -# 完整字段(堆叠/数据标签/detached/坐标轴等)跑 --print-schema --flag-name properties lark-cli sheets +chart-create --url "https://example.feishu.cn/sheets/shtXXX" \ - --sheet-name "Sheet1" --properties '{"position":{"row":42,"col":"A"},"size":{"width":600,"height":400},"snapshot":{"data":{"refs":[{"value":"Sheet1!A1:B10"}]},"plotArea":{"plot":{"type":"column"}}}}' + --sheet-name "Sheet1" --properties '{ + "position":{"row":42,"col":"A"}, + "size":{"width":600,"height":400}, + "snapshot":{ + "data":{ + "refs":[{"value":"Sheet1!A1:B10"}], + "dim1":{"serie":{"index":1}}, + "dim2":{"series":[{"index":2}]} + }, + "plotArea":{"plot":{"type":"column"}} + } + }' # 走文件(推荐配置较多时) -lark-cli sheets +chart-create --url "https://example.feishu.cn/sheets/shtXXX" \ - --sheet-name "Sheet1" --properties @chart-config.json +lark-cli sheets +chart-create --url "..." --sheet-name "Sheet1" --properties @chart-config.json ``` -> **`--properties` JSON 关键字段**(结构见上方 `## Schemas` 段;详见语义内容章节): -> - `position.row` / `position.col` 必须留足空间,越界会被 API 拒 -> - `snapshot.data.headerMode`:默认 inline;当 refs 仅覆盖数据子集且语义表头在子集之外,必须 `detached` + `nameRef` +**饼图专属示例**(`sectors` 必须嵌在 `plotArea.plot.series[i].sectors.sector[]`,且 `sector[].index` 1-based): + +饼图比 column / bar 更复杂:`sectors` 是 object,里面再包一个**单数** `sector` 数组——CLI 不替你 normalize,写错路径会被 server schema 直接拒。 + +```bash +lark-cli sheets +chart-create --url "..." --sheet-name "Sheet1" --properties '{ + "position":{"row":24,"col":"F"}, + "size":{"width":600,"height":450}, + "snapshot":{ + "title":{"text":"各部门员工人数占比"}, + "plotArea":{"plot":{ + "type":"pie", + "series":[{ + "index":1, + "sectors":{"sector":[{"index":1,"offsetRadius":0.05}]} + }] + }}, + "data":{ + "refs":[{"value":"Sheet1!A1:B11"}], + "dim1":{"serie":{"index":1,"aggregate":true}}, + "dim2":{"series":[{"index":2,"aggregateType":"sum"}]} + } + } +}' +``` + +**数据与表头分离(必须用 `detached` + `nameRef`)**: + +场景:周度销量明细表,真实表头在第 1 行(A1=周次、C1=订单量、D1=退款量),数据按 B 列"店铺"分段;用户只要"3 号店"那一段(第 11–17 行)。 + +```bash +lark-cli sheets +chart-create --url "..." --sheet-name "Sheet2" --properties '{ + "position":{"row":7,"col":"F"}, + "size":{"width":600,"height":360}, + "snapshot":{ + "title":{"text":"3 号店周度订单/退款"}, + "plotArea":{"plot":{"type":"column"}}, + "data":{ + "headerMode":"detached", + "direction":"column", + "refs":[{"value":"Sheet2!A11:D17"}], + "dim1":{"serie":{"index":1,"nameRef":"Sheet2!A1"}}, + "dim2":{"series":[ + {"index":3,"nameRef":"Sheet2!C1"}, + {"index":4,"nameRef":"Sheet2!D1"} + ]} + } + } +}' +``` + +约束: +- `refs` 只覆盖纯数据 `A11:D17`,**不要**把表头行 A1 并进来 +- `nameRef` 在 detached 模式下**必填**,缺了被校验报 `headerMode=detached requires ... nameRef` +- `index` 按 refs 内的列序算(A=1、B=2、C=3、D=4),**不是**全表列号 +- `nameRef` 必须配对应的 `index`;单写 `nameRef` 不传 `index` 直接报参数错 + +**多张图共享同一组表头(按维度拆图,必须用 detached)**: + +场景:销售明细表头在 A1:E1(月份/区域/销售额/订单数/客单价),数据按区域分 3 段(华北 A2:E9、华东 A10:E17、华南 A18:E25),要分别画 3 张图。 + +❌ 常见错误: + +```jsonc +// 错误 1:refs 含全局表头但跨段 —— 多个区域被混进同一张图 +{"data":{"refs":[{"value":"Sheet!A1:E17"}], ... }} // 华东图混进华北 8 行 +// 错误 2:inline + refs 只取数据段、不写 detached/nameRef —— 图例显示成具体数据值 +{"data":{"refs":[{"value":"Sheet!A10:E17"}],"dim1":{"serie":{"index":1}}, ... }} +``` + +✅ 正确模式:3 张图各自 detached、refs 干净不重叠: + +```jsonc +// 图 1:华北 +{"data":{ + "headerMode":"detached","direction":"column", + "refs":[{"value":"Sheet!A2:E9"}], + "dim1":{"serie":{"index":1,"nameRef":"Sheet!A1"}}, + "dim2":{"series":[ + {"index":3,"nameRef":"Sheet!C1"}, + {"index":4,"nameRef":"Sheet!D1"} + ]} +}} +// 图 2:华东 —— refs 改 Sheet!A10:E17,其余同上 +// 图 3:华南 —— refs 改 Sheet!A18:E25,其余同上 +``` + +> `--properties` JSON 关键字段: +> - `position.row` / `position.col` 必须留足空间,越界会被 API 拒(按本文件"图表位置选择"四步走) +> - `snapshot.data.headerMode`:默认 inline;当 refs 仅覆盖数据子集而语义表头在子集之外,必须 `detached` + `nameRef` > - chart 引用 pivot 输出时,`snapshot.data.refs` 必须排除总计 / 小计行 ### `+chart-update` -> 更新前必须先 `+chart-list --chart-id ` 回读完整配置,再在其基础上修改,避免漏字段把图表回退到默认状态。 +**Update 三步法**(缺一步会丢字段): + +1. `+chart-list --chart-id ` 拿到完整 snapshot +2. 在拿到的 snapshot 上**局部**修改要改的字段,其余保持不变 +3. 把**完整 snapshot** 整个回写到 `--properties.snapshot` + +```bash +lark-cli sheets +chart-update --url "..." --sheet-id "$SID" --chart-id "chrXXX" \ + --properties '{ + "position":{"row":0,"col":"A"}, + "size":{"width":480,"height":320}, + "snapshot": <完整快照(由 +chart-list 取回后局部修改)> + }' +``` + +> 关键:**不能只提交局部 snapshot**,否则未传字段会被还原为默认值。`+chart-update` 的语义是 PUT(整体覆盖),不是 PATCH。 ### `+chart-delete` diff --git a/skills/lark-sheets/references/lark-sheets-float-image.md b/skills/lark-sheets/references/lark-sheets-float-image.md index 2ddf06479..6743a31bd 100644 --- a/skills/lark-sheets/references/lark-sheets-float-image.md +++ b/skills/lark-sheets/references/lark-sheets-float-image.md @@ -30,7 +30,7 @@ - `--image-token`:复用**已存在**的图片 file_token。常见来源:① `+float-image-list` 返回的 `image_token`(适合"换皮不换位置"复用同一张图);② `+cells-set-image` 成功返回里的 `file_token`(它也是 `sheet_image` 上传句柄)。适合"同一张图复用到多处",省去重复上传。 - `--image-uri`:图片 reference_id(image URI),由系统自动转 file_token。 -> ⚠️ **`--image` 仅 `+float-image-create` 支持**。`+float-image-update` 换图仍只接受 `--image-token` / `--image-uri`(patch 模式:不传则保留原图);要在 update 里换一张本地新图,先用 `+cells-set-image` 上传到任意临时单元格、从返回取 `file_token`,再把它传给 update 的 `--image-token`。 +> ⚠️ **`--image` 仅 `+float-image-create` 支持**。`+float-image-update` 换图只接受 `--image-token` / `--image-uri`,**且即使不换图也必传其一**(CLI 强制;要保留原图就把 list 回读的 `image_token` 回填);要在 update 里换一张本地新图,先用 `+cells-set-image` 上传到任意临时单元格、从返回取 `file_token`,再把它传给 update 的 `--image-token`。 ## Shortcuts @@ -111,8 +111,9 @@ lark-cli sheets +float-image-list --url "..." --sheet-id "$SID" ```bash # 首选:直接给本地图片路径,CLI 自动上传(无需手动拿 token) +# 注意:--image-name 是 required(即使路径 basename 已经是 logo.png 也要显式传) lark-cli sheets +float-image-create --url "..." --sheet-id "$SID" \ - --image ./logo.png \ + --image ./logo.png --image-name "logo.png" \ --position-row 2 --position-col B --size-width 300 --size-height 200 --z-index 1 # 用已有 file_token(从 +float-image-list 的 image_token 或 +cells-set-image 返回的 file_token) @@ -130,14 +131,23 @@ lark-cli sheets +float-image-create --url "..." --sheet-id "$SID" \ > **patch 模式**:除了 `--float-image-id`(必填,定位目标图片)外,其它字段都可选——只传你需要改的那几个,未传的字段保持原值不变。至少传一个改动字段。 > -> 推荐流程:先 `+float-image-list --float-image-id ` 回读当前完整属性,再针对要改的字段调一次 `+float-image-update`。 +> ⚠️ **图片来源必传**:CLI 强制要求 `--image-token` / `--image-uri` 之一(即使本次不换图)。要"保留原图"也得显式传当前 `image_token`——先用 `+float-image-list --float-image-id ` 回读拿到 `image_token`,再传给 update。 +> +> 推荐流程:`+float-image-list --float-image-id ` → 抽 `image_token` → 调一次 `+float-image-update` 传完整图片来源 + 想改的字段。 ```bash -# 只改位置,保留其它属性 -lark-cli sheets +float-image-update --url "..." --sheet-id "$SID" \ - --float-image-id "$IMG_ID" --position-row 5 --position-col C +# 第 1 步:list 回读当前 image_token(必拿,下一步要用) +lark-cli sheets +float-image-list --url "..." --sheet-id "$SID" \ + --float-image-id "$IMG_ID" --jq '.data.sheets[0].float_images[0].image_token' +# 拿到 e.g. "boxbn...",赋给 shell 变量 IMG_TOKEN -# 只换图,位置/尺寸不变 +# 第 2 步:只改位置,图片来源原样回填(不传 --image-token 会被 CLI 拒) +lark-cli sheets +float-image-update --url "..." --sheet-id "$SID" \ + --float-image-id "$IMG_ID" \ + --image-token "$IMG_TOKEN" --image-name "logo.png" \ + --position-row 5 --position-col C + +# 只换图,位置/尺寸不变(image-name 必传;旧位置/尺寸字段不传则按 patch 语义保留) lark-cli sheets +float-image-update --url "..." --sheet-id "$SID" \ --float-image-id "$IMG_ID" --image-name "new-logo.png" --image-token "$NEW_TOKEN" ``` @@ -150,6 +160,6 @@ lark-cli sheets +float-image-delete --url "..." --sheet-id "$SID" --float-image- ### Validate / DryRun / Execute 约束 -- `Validate`:XOR 公共四件套;`+float-image-create` 要求 `--image` / `--image-token` / `--image-uri` **恰好给一个**,`--position-row/col` 与 `--size-width/height` 必填且为合法整数;传 `--image` 时还会校验路径安全(绝对路径 / 越出工作目录会被拒,`--dry-run` 同样拦)。`+float-image-update` 必须 `--float-image-id`,其余字段至少传 1 个(patch 模式:未传字段保持原值,换图只接受 `--image-token` / `--image-uri`);`+float-image-delete` 强制 `--yes` 或 `--dry-run`。 +- `Validate`:XOR 公共四件套;`+float-image-create` 要求 `--image` / `--image-token` / `--image-uri` **恰好给一个** + `--image-name` 必填,`--position-row/col` 与 `--size-width/height` 必填且为合法整数;传 `--image` 时还会校验路径安全(绝对路径 / 越出工作目录会被拒,`--dry-run` 同样拦)。`+float-image-update` 必须 `--float-image-id`,**并且必须传 `--image-token` 或 `--image-uri` 之一**(patch 模式只是说"未传字段保持原值",但图片来源仍是硬必填——只改位置 / 尺寸时也要把 list 回读的 `image_token` 回填);`+float-image-delete` 强制 `--yes` 或 `--dry-run`。 - `DryRun`:写操作输出"将要 POST/PATCH/DELETE 的 float_image 请求模板";传 `--image` 时会多打印一步本地图片上传(`POST /open-apis/drive/v1/medias/upload_all`,`parent_type=sheet_image`)。 - `Execute`:写后调用 `+float-image-list --float-image-id ` 回读,envelope.meta.verification 给出新位置 / 尺寸对比。 From 55ccbc5f6ae8e19112d70a632538daf306a37a8d Mon Sep 17 00:00:00 2001 From: zhengzhijie Date: Tue, 26 May 2026 21:34:04 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=90=8C=E6=AD=A5=20tools-schema.j?= =?UTF-8?q?son=20=E6=94=B9=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shortcuts/sheets/data/flag-schemas.json | 42 +++++++++++++++---- .../references/lark-sheets-chart.md | 2 +- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/shortcuts/sheets/data/flag-schemas.json b/shortcuts/sheets/data/flag-schemas.json index c4d5e5987..4a909314d 100644 --- a/shortcuts/sheets/data/flag-schemas.json +++ b/shortcuts/sheets/data/flag-schemas.json @@ -1610,7 +1610,10 @@ ] } } - } + }, + "required": [ + "plot" + ] }, "data": { "type": "object", @@ -1676,7 +1679,10 @@ "type": "string", "description": "可选。维度名称的单元格引用(A1 表示法,如 'Sheet1!A1')。当维度名称不直接来自 refs 首行/首列时,可通过此字段把维度名显式指向目标表头单元格,图表会以该单元格当前值作为类别维度名展示。" } - } + }, + "required": [ + "index" + ] }, "field": { "type": "object", @@ -1735,7 +1741,10 @@ "type": "string", "description": "可选。系列名称的单元格引用(A1 表示法,如 'Sheet1!C1')。当系列名称不直接来自 refs 首行/首列时,可通过此字段把系列名显式指向目标表头单元格,图表会以该单元格当前值作为系列名(图例/tooltip)展示。" } - } + }, + "required": [ + "index" + ] } }, "fields": { @@ -1769,7 +1778,11 @@ } } } - } + }, + "required": [ + "plotArea", + "data" + ] } }, "required": [ @@ -2640,7 +2653,10 @@ ] } } - } + }, + "required": [ + "plot" + ] }, "data": { "type": "object", @@ -2706,7 +2722,10 @@ "type": "string", "description": "可选。维度名称的单元格引用(A1 表示法,如 'Sheet1!A1')。当维度名称不直接来自 refs 首行/首列时,可通过此字段把维度名显式指向目标表头单元格,图表会以该单元格当前值作为类别维度名展示。" } - } + }, + "required": [ + "index" + ] }, "field": { "type": "object", @@ -2765,7 +2784,10 @@ "type": "string", "description": "可选。系列名称的单元格引用(A1 表示法,如 'Sheet1!C1')。当系列名称不直接来自 refs 首行/首列时,可通过此字段把系列名显式指向目标表头单元格,图表会以该单元格当前值作为系列名(图例/tooltip)展示。" } - } + }, + "required": [ + "index" + ] } }, "fields": { @@ -2799,7 +2821,11 @@ } } } - } + }, + "required": [ + "plotArea", + "data" + ] } }, "required": [ diff --git a/skills/lark-sheets/references/lark-sheets-chart.md b/skills/lark-sheets/references/lark-sheets-chart.md index 23819ffa5..5793d5456 100644 --- a/skills/lark-sheets/references/lark-sheets-chart.md +++ b/skills/lark-sheets/references/lark-sheets-chart.md @@ -150,7 +150,7 @@ _创建/更新的图表属性_ - `position` (object) — 必填 { row: number, col: string } - `offset` (object?) — 可选 { row_offset?: number, col_offset?: number } - `size` (object) — 必填 { width: number, height: number } -- `snapshot` (object?) — 图表快照配置 { title?: object, subTitle?: object, style?: object, legend?: oneOf, plotArea?: object, …共 6 项 } +- `snapshot` (object?) — 图表快照配置 { title?: object, subTitle?: object, style?: object, legend?: oneOf, plotArea: object, …共 6 项 } ## Examples