feat: upgrade card send (#1688)

This commit is contained in:
91-enjoy
2026-07-02 19:46:11 +08:00
committed by GitHub
parent 578e2db4e0
commit 9f150670f3
35 changed files with 1760 additions and 1 deletions

View File

@@ -59,6 +59,8 @@ The four message-pulling shortcuts (`+messages-mget`, `+chat-messages-list`, `+m
### Card Messages (Interactive)
**Before sending or replying with any `interactive` card (`+messages-send` / `+messages-reply`), you MUST read [`references/card/lark-im-card-create.md`](references/card/lark-im-card-create.md) and follow its workflow.** The card JSON passed to `--msg-type interactive --content` must be the output of that workflow — never hand-write or copy a card payload.
Card messages (`interactive` type) are not yet supported for compact conversion in event subscriptions. The raw event data will be returned instead, with a hint printed to stderr.
`interactive` cards support callback events (`card.action.trigger`) — see [`references/lark-im-card-action-reply.md`](references/lark-im-card-action-reply.md).

View File

@@ -0,0 +1,107 @@
# 卡片 2.0 组件大纲
Card 2.0 组件按**容器 / 展示 / 交互**三类,均通过 `tag` 字段声明。先在下表按用途选组件,再点明细看字段:有明细文件的点 `components/<tag>.md`(完整字段+示例+易错点),低频组件点链接看官方文档。
## 根结构
顶层固定四字段,先搭骨架再往 `body.elements` 填组件。以下为**推荐完整骨架**(含 type scale、light/dark color token、header 三件套):
```json
{
"schema": "2.0",
"config": {
"update_multi": true,
"width_mode": "default",
"style": {
"text_size": {
"title": { "default": "heading-2", "pc": "heading-2", "mobile": "heading-3" },
"body": { "default": "normal", "pc": "normal", "mobile": "normal" },
"caption": { "default": "notation", "pc": "notation", "mobile": "notation" }
},
"color": {
"cus-primary": { "light_mode": "rgba(30,120,255,1)", "dark_mode": "rgba(80,150,255,1)" },
"cus-primary-bg": { "light_mode": "rgba(30,120,255,0.08)", "dark_mode": "rgba(80,150,255,0.12)" },
"cus-muted": { "light_mode": "rgba(100,106,115,1)", "dark_mode": "rgba(150,155,163,1)" }
}
}
},
"header": {
"title": { "tag": "plain_text", "content": "卡片标题" },
"subtitle": { "tag": "plain_text", "content": "副标题:一句上下文(时间/来源/状态)" },
"template": "blue",
"icon": { "tag": "standard_icon", "token": "notice_colorful" },
"text_tag_list": [
{ "tag": "text_tag", "text": { "tag": "plain_text", "content": "状态标签" }, "color": "blue" }
]
},
"body": { "direction": "vertical", "padding": "12px 12px 20px 12px", "elements": [] }
}
```
> **按需裁剪**`subtitle` / `text_tag_list` / color token 按实际诉求取舍,不强制全用。组件里用 `"text_size": "title"` / `"caption"` 引用 token用 `"font_color": "cus-muted"` 引用颜色 token主色系变化时只需改 config 里的 RGBA全卡自动跟随。
- `schema` 必须显式为 `"2.0"`,否则按 1.0 渲染。`header` 详见 `components/header.md`
- **元素通用字段**(所有 `elements[]` 组件):`tag`(必填) · `element_id`(卡内唯一字母开头、≤20 字符) · `margin`(外边距 [-99,99]px)。
- `card_link`(整卡跳转):`{url, pc_url, ios_url, android_url}`,至少填 `url`;某端禁跳设 `lark://msgcard/unsupported_action`
- 硬限制:单卡 ≤ **200** 元素;需客户端 **≥ 7.20**(旧版仅显示 header
- 颜色 / 图标枚举见 `resource/colors.md` · `resource/icons.md`
**config**(全局行为,可整体省略):
| 字段 | 默认 | 说明 |
|---|---|---|
| `update_multi` | true | 共享卡片v2 仅支持 true |
| `width_mode` | default | `default`(≤600px) / `compact`(400px) / `fill`(撑满) |
| `enable_forward` | true | 是否允许转发 |
| `summary` | — | 会话列表预览:`{content, i18n_content:{zh_cn,en_us,…}}` |
| `streaming_mode` | false | 流式更新模式(配 `streaming_config` |
| `style.text_size` | — | 自定义字号 token格式 `{"<名称>":{default,pc,mobile}}`;名称可自定义(如 `title`/`caption`),组件 `text_size` 引用该名称 |
| `style.color` | — | 自定义颜色 token格式 `{"<名称>":{light_mode,dark_mode}}`RGBA名称可自定义`cus-primary`),组件 `font_color`/`background_style` 等字段引用 |
> 多语言:`config.locales` 限定生效语种、`use_custom_translation` 优先用自带 i18n。
**body 布局字段**(均 v2 新增):`direction`(vertical/horizontal) · `padding`([0,99]px) · `horizontal_spacing`/`vertical_spacing`(`small`4/`medium`8/`large`12/`extra_large`16 或 px) · `horizontal_align`/`vertical_align`
---
## 容器类(布局 / 组织交互)
| 组件 | 用途 |
|---|---|
| [column_set](components/column_set.md) | 横向分栏,多列图文对齐(数据表、字段对、列表) |
| [collapsible_panel](components/collapsible_panel.md) | 折叠面板,收纳备注/长文本等次要信息 |
| [form](components/form.md) | 表单容器,批量录入表单项后一次提交 |
| [interactive_container](components/interactive_container.md) | 整块可点击区域,可统一定义样式与交互 |
| [循环容器](components/recycling_container.md) | 批量渲染同版式不同数据(仅搭建工具) |
## 展示类(无交互)
| 组件 | 用途 |
|---|---|
| [header](components/header.md) | 卡片标题区:主/副标题、后缀标签、主题色 |
| [div](components/div.md) | 普通文本,带前缀图标、字段对 |
| [markdown](components/markdown.md) | 富文本,最常用;@人、彩色、链接、列表、表格等 |
| [img](components/img.md) | 单图 |
| [img_combination](components/img_combination.md) | 多图拼排(双图/三图/宫格) |
| [person](components/person.md) | 单个人员头像/姓名 |
| [person_list](components/person_list.md) | 多个人员头像/姓名 |
| [chart](components/chart.md) | VChart 图表(折线/柱/饼/词云等) |
| [table](components/table.md) | 多列数据表(只能放根节点) |
| [hr](components/hr.md) | 分割线 |
## 交互类
| 组件 | 用途 |
|---|---|
| [button](components/button.md) | 按钮:回调 / 跳转 / 表单提交 |
| [input](components/input.md) | 文本输入框(多嵌在 form 内) |
| [overflow](components/overflow.md) | 折叠按钮组,收纳多个操作 |
| [select_static](components/select_static.md) | 下拉单选 |
| [multi_select_static](components/multi_select_static.md) | 下拉多选 |
| [select_person](components/select_person.md) | 人员单选 |
| [multi_select_person](components/multi_select_person.md) | 人员多选 |
| [date_picker](components/date_picker.md) | 日期选择器 |
| [picker_time](components/picker_time.md) | 时间选择器 |
| [picker_datetime](components/picker_datetime.md) | 日期时间选择器 |
| [select_img](components/select_img.md) | 图片选择(单/多选) |
| [checker](components/checker.md) | 勾选器,任务勾选回调 |

View File

@@ -0,0 +1,63 @@
# 按钮 `button`
交互按钮,支持跳转 / 回调 / 表单提交三类行为。**Card 2.0**。
## 最小示例
```json
{
"tag": "button",
"text": { "tag": "plain_text", "content": "确定" },
"type": "primary",
"behaviors": [{ "type": "callback", "value": { "action": "ok" } }]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `button` |
| `text` | 否 | Object | / | `{tag:"plain_text", content}`≤100 字符 |
| `type` | 否 | String | default | 见下方 type 枚举 |
| `size` | 否 | String | medium | `tiny` / `small` / `medium` / `large` |
| `width` | 否 | String | default | `default` / `fill` / `[100,∞)px` |
| `behaviors` | 是* | Array | / | 交互行为,见下;表单内按钮不用 behaviors 而用 `form_action_type` |
| `icon` | 否 | Object | / | 前缀图标(同 `div.icon` |
| `hover_tips` | 否 | Object | / | PC 端悬浮提示plain_text |
| `disabled` | 否 | Boolean | false | 是否禁用 |
| `disabled_tips` | 否 | Object | / | 禁用后悬浮提示plain_text |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}`(均 plain_texttitle 必填) |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
| `element_id` | 否 | String | / | 唯一标识,字母开头 ≤20 字符 |
**type 枚举**`default`(黑字描边) / `primary`(蓝字描边) / `danger`(红字描边) / `text` / `primary_text` / `danger_text`(无边框) / `primary_filled`(蓝底白字) / `danger_filled`(红底白字) / `laser`(镭射)。
## 按钮主次(强制)
- 全卡仅 1 个按钮 → `type: "primary_filled"`,并 `width: "fill"` 撑满成强焦点。
- 多个并列按钮 → 第一个(主操作)`primary_filled`,其余一律 `default`,形成「一主多次」层级。
- 删除 / 拒绝等危险操作用 `danger` 系(`danger``danger_filled`)。
## behaviors交互行为
```json
// 1. 服务端回调
{ "type": "callback", "value": { "key": "v" } }
// 2. 跳转链接(可与 callback 同数组共存)
{ "type": "open_url", "default_url": "https://x", "pc_url": "", "ios_url": "", "android_url": "" }
```
表单容器内的按钮 **不用 behaviors**,改用根字段:
| 字段 | 必填 | 说明 |
|---|---|---|
| `name` | 是 | 表单内唯一标识 |
| `form_action_type` | 是 | `submit`(提交表单)/ `reset`(重置) |
## 嵌套 / 易错点
- 可嵌套在 column_set / form / collapsible_panel / 循环容器 / interactive_container 内。
- 2.0 已废弃 `action` 交互模块,按钮直接放 `elements`,用间距控制排列。
- 旧式 `url`/`value` 顶层字段是 1.0 写法2.0 一律用 `behaviors`
- 点击触发 `card.action.trigger`,回传 `action.tag="button"` + `action.value`(即 callback 的 value

View File

@@ -0,0 +1,57 @@
# 图表 `chart`
基于 VChart 的可视化图表(折线/柱/饼/词云等)。**Card 2.0**。
## 最小示例
```json
{
"tag": "chart",
"chart_spec": {
"type": "line",
"title": { "text": "趋势" },
"data": { "values": [
{ "time": "周一", "value": 8 },
{ "time": "周二", "value": 14 }
] },
"xField": "time",
"yField": "value"
}
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `chart` |
| `chart_spec` | 是 | Object | / | VChart 图表定义,见下 |
| `aspect_ratio` | 否 | String | 16:9(PC)/1:1(移动) | `1:1` / `2:1` / `4:3` / `16:9` |
| `color_theme` | 否 | String | brand | `brand` / `rainbow` / `complementary` / `converse` / `primary`chart_spec 里声明了样式则此项无效 |
| `height` | 否 | String | auto | `auto`(按宽高比) 或 `[1,999]px`(设固定高则 aspect_ratio 失效) |
| `preview` | 否 | Boolean | true | 是否可独立窗口/全屏查看 |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
| `element_id` | 否 | String | / | 唯一标识,字母开头 ≤20 字符 |
## chart_spec 常用类型
`chart_spec` 是标准 VChart spec。核心字段`type``data.values`(数据数组)、`xField`/`yField`(轴字段)、`seriesField`(分组)、`title.text``legends`
| 图表 | type | 关键字段 |
|---|---|---|
| 折线 | `line` | `xField`, `yField` |
| 面积 | `area` | `xField`, `yField` |
| 柱状 | `bar` | `xField`, `yField`,分组加 `seriesField` |
| 条形(横向) | `bar` | `direction:"horizontal"``xField`=值,`yField`=类别 |
| 饼/环 | `pie` | `valueField`, `categoryField`,环图加 `innerRadius` |
| 散点 | `scatter` | `xField`, `yField` |
| 词云 | `wordCloud` | `nameField`, `valueField` |
完整属性参考 [VChart 官方文档](https://www.visactor.io/vchart/option/barChart)。
## 易错点
- 不支持 JavaScript 语法,`chart_spec` 必须是纯 JSON。
- 单卡建议 ≤5 个图表。
- 移动端不支持部分 VChart 属性(纹理 texture、conical 渐变、grid 词云布局等),用了会在移动端加载失败。
- 平台默认给 chart_spec 追加 media query 自适应;要自控可设 `"media": []`

View File

@@ -0,0 +1,38 @@
# 勾选器 `checker`
任务勾选场景的交互组件,支持配置回调响应。仅支持手写 JSON搭建工具不支持构建。**Card 2.0**。
## 最小示例
```json
{
"tag": "checker",
"name": "check_1",
"checked": false,
"text": { "tag": "plain_text", "content": "完成新品上市计划报告" },
"behaviors": [{ "type": "callback", "value": { "key": "todo1" } }]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `checker` |
| `name` | 否* | String | / | 唯一标识;**form 内必填且全局唯一** |
| `checked` | 否 | Boolean | false | 初始勾选状态 |
| `text` | 否 | Object | / | `{tag:"plain_text"\|"lark_md", content, text_size?, text_color?, text_align?}`text_color 见 `../resource/colors.md` |
| `overall_checkable` | 否 | Boolean | true | 悬浮时整体是否有阴影效果 |
| `button_area` | 否 | Object | / | `{pc_display_rule:"always"|"on_hover", buttons:[<=3 个 button]}` |
| `checked_style` | 否 | Object | / | `{show_strikethrough, opacity}`,勾选后的内容样式 |
| `disabled` / `disabled_tips` | 否 | Boolean/Object | false / 空 | 禁用及禁用提示 |
| `hover_tips` | 否 | Object | 空 | 悬浮提示;与 `disabled_tips` 同配时后者生效 |
| `behaviors` | 否 | Array | / | `[{type:"callback", value:{...}}]`**未配置时仅本地勾选生效,不触发回调** |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
| `padding`/`margin` | 否 | String | 0 | [-99,99]px |
## 嵌套 / 易错点
- 可嵌套在 form / 交互容器 / column_set / collapsible_panel 内。
- 不配置 `behaviors` 时勾选仅前端本地生效,不会触发服务端回调——需要业务侧感知必须显式配置。
- 回调:`action.tag="checker"` + `action.checked`布尔值form 内则读 `form_value[name]`

View File

@@ -0,0 +1,46 @@
# 折叠面板 `collapsible_panel`
折叠次要内容(备注、长文本),点标题展开/收起。**Card 2.0**。
## 最小示例
```json
{
"tag": "collapsible_panel",
"expanded": false,
"header": { "title": { "tag": "plain_text", "content": "面板标题" } },
"elements": [{ "tag": "markdown", "content": "折叠的内容" }]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `collapsible_panel` |
| `header` | 是 | Object | / | 标题区,见下 |
| `elements` | 否 | Array | / | 面板内组件;**不能放 `form`** |
| `expanded` | 否 | Boolean | false | 是否默认展开 |
| `background_color` | 否 | String | 透明 | 面板背景,颜色枚举(见 `../resource/colors.md` |
| `border` | 否 | Object | / | `{ color, corner_radius }` |
| `direction` | 否 | String | vertical | `vertical` / `horizontal` |
| `vertical_spacing`/`horizontal_spacing` | 否 | String | 8px | 间距枚举或 [0,99]px |
| `padding` | 否 | String | 0 | 内边距 [0,99]px |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
**header 字段**
| 字段 | 必填 | 说明 |
|---|---|---|
| `title` | 否 | `{tag:"plain_text"\|"markdown", content}` |
| `background_color` | 否 | 标题区背景,颜色枚举 |
| `width` | 否 | `fill` / `auto` / `auto_when_fold`(收起时自适应) |
| `vertical_align` | 否 | `top`/`center`/`bottom` |
| `icon` | 否 | 图标 `{tag, token, color, size}`(同 `div.icon`,多 `size` |
| `icon_position` | 否 | `left` / `right` / `follow_text` |
| `icon_expanded_angle` | 否 | 展开时图标旋转角:`-180`/`-90`/`90`/`180` |
## 嵌套 / 易错点
- 内部不支持 `form`;容器最多嵌套 5 层。
- 仅支持写 JSON搭建工具不支持。

View File

@@ -0,0 +1,53 @@
# 分栏 `column_set` + `column`
横向多列布局容器。`column_set` 装若干 `column`,每个 `column` 内再放组件。**Card 2.0**。
## 最小示例
```json
{
"tag": "column_set",
"flex_mode": "none",
"columns": [
{ "tag": "column", "width": "weighted", "weight": 1,
"elements": [{ "tag": "markdown", "content": "左列" }] },
{ "tag": "column", "width": "weighted", "weight": 1,
"elements": [{ "tag": "markdown", "content": "右列" }] }
]
}
```
## column_set 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `column_set` |
| `columns` | 是 | column[] | / | 列数组,子节点只能是 `column` |
| `flex_mode` | 否 | String | none | 窄屏自适应:`none`(按比例压缩) / `stretch`(变上下堆叠) / `flow`(自动换行) / `bisect`(两等分) / `trisect`(三等分) |
| `horizontal_spacing` | 否 | String | 8px | `small`(4)/`medium`(8)/`large`(12)/`extra_large`(16) 或 `[0,99]px` |
| `horizontal_align` | 否 | String | left | `left` / `center` / `right` |
| `background_style` | 否 | String | default | `default` 或颜色枚举/RGBA`../resource/colors.md`);嵌套时上层覆盖下层 |
| `action` | 否 | Object | / | 整块点击跳转 `{ multi_url:{url,pc_url,ios_url,android_url} }` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
## column 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `column` |
| `elements` | 否 | Element[] | / | 列内组件;**不能放 `form``table`**,可放 `column_set` |
| `width` | 否 | String | auto | 仅 `flex_mode:none` 生效:`auto` / `weighted`(配 weight) / `[16,600]px` |
| `weight` | 否 | Number | 1 | `width:weighted` 时的宽度占比1~5 整数 |
| `vertical_align` | 否 | String | top | `top` / `center` / `bottom` |
| `direction` | 否 | String | vertical | `vertical` / `horizontal` |
| `horizontal_spacing`/`vertical_spacing` | 否 | String | 8px | 同上间距枚举或 `[0,99]px` |
| `padding` | 否 | String | 0 | 内边距 [0,99]px |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
| `background_style` | 否 | String | default | 同上 |
| `action` | 否 | Object | / | 点击列跳转,同 column_set.action |
## 嵌套 / 易错点
- **column_set 的直接子节点只能是 `column`**;不能 `column_set → column_set`。二级分栏要走 `column_set → column → column_set`
- column 内可放除 `form` / `table` 外的所有组件。
- 最多嵌套 5 层,过深会压缩展示空间。

View File

@@ -0,0 +1,34 @@
# 日期选择器 `date_picker`
提供日期选项的交互组件,默认拥有交互能力(无需显式 `behaviors` 也会回调)。**Card 2.0**。
## 最小示例
```json
{
"tag": "date_picker",
"placeholder": { "tag": "plain_text", "content": "请选择" },
"initial_date": "2024-01-01"
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `date_picker` |
| `name` | 否* | String | / | 唯一标识;**form 内必填且全局唯一** |
| `required` | 否 | Boolean | false | 是否必选form 内生效) |
| `initial_date` | 否 | String | / | 初始值,格式 `yyyy-MM-dd`,会覆盖 `placeholder` |
| `placeholder` | 否 | Object | / | 占位文本plain_text未设 `initial_date` 时必填 |
| `width` | 否 | String | default | `default`/`fill`/`[100,∞)px` |
| `disabled` | 否 | Boolean | false | 是否禁用(需端版本 V7.4+ |
| `behaviors` | 否 | Array | / | `[{type:"callback", value:{...}}]` |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
| `margin` | 否 | String | 0 | [-99,99]px |
## 嵌套 / 易错点
- 可嵌套在 column_set / form / collapsible_panel / 循环容器 / 交互容器内;搭建工具中暂不支持嵌套在交互容器中。
- 提醒用户注意时区语境(如预定海外酒店用酒店所在地时区);服务端只返回用户当前时区作为参考,不代表用户选的就是该时区。
- 回调:`action.tag="date_picker"` + `action.option`(日期字符串,如 `"2025-06-10 +0800"`+ `action.timezone`form 内则读 `form_value[name]`

View File

@@ -0,0 +1,36 @@
# 普通文本 `div`
带样式的文本块,支持前缀图标和 label-value 字段对。**Card 2.0**。富文本用 `markdown` 组件。
## 最小示例
```json
{
"tag": "div",
"text": { "tag": "plain_text", "content": "示例文本" }
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `div` |
| `text` | 否 | Object | / | 文本对象,见下 |
| `text.tag` | 是 | String | plain_text | `plain_text``lark_md`(部分 Markdown语法见 `markdown.md` |
| `text.content` | 是 | String | / | 文本内容 |
| `text.text_size` | 否 | String | normal | `heading-0`~`heading-4` / `normal`(14px) / `notation`(12px) 等;可在 `config.style.text_size` 自定义 pc/mobile 不同字号 |
| `text.text_color` | 否 | String | default | 颜色枚举(见 `../resource/colors.md`),仅 `plain_text` 生效 |
| `text.text_align` | 否 | String | left | `left` / `center` / `right` |
| `text.lines` | 否 | Int | / | 最大显示行数,超出 `...` 省略 |
| `icon` | 否 | Object | / | 前缀图标,见下 |
| `icon.tag` | 否 | String | / | `standard_icon`(用 `token`+`color`token 见 `../resource/icons.md`)或 `custom_icon`(用 `img_key` |
| `width` | 否 | String | fill | `fill` / `auto` / `[16,999]px` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
| `element_id` | 否 | String | / | 唯一标识,字母开头 ≤20 字符;流式更新时 `text.element_id` 指定文本 |
> `fields` 字段(多列 label-value数组每项 `{ is_short, text:{tag,content} }``is_short:true` 可并排。
## 易错点
- `text_color` 只在 `text.tag``plain_text` 时生效;`lark_md` 用内联 `<font color=red>` 着色。

View File

@@ -0,0 +1,51 @@
# 表单容器 `form`
批量录入表单项后一次提交:用户在前端填写多个表单项,点击提交按钮后将所有值打包一次性回调到服务端。**Card 2.0**。
## 最小示例
```json
{
"tag": "form",
"name": "form_1",
"elements": [
{ "tag": "input", "name": "reason", "required": true },
{
"tag": "button",
"text": { "tag": "plain_text", "content": "提交" },
"type": "primary",
"form_action_type": "submit",
"name": "Button_submit"
}
]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `form` |
| `name` | 是 | String | / | 表单容器唯一标识,卡片内全局唯一,用于识别提交数据归属 |
| `elements` | 是 | Element[] | [] | 子节点,支持除 `table``form` 外的所有组件 |
| `direction` | 否 | String | vertical | `vertical` / `horizontal` |
| `horizontal_spacing`/`vertical_spacing` | 否 | String | 8px/12px | 间距枚举 `small`(4)/`medium`(8)/`large`(12)/`extra_large`(16) 或 `[0,99]px` |
| `horizontal_align` | 否 | String | left | `left`/`center`/`right` |
| `vertical_align` | 否 | String | top | `top`/`center`/`bottom` |
| `padding`/`margin` | 否 | String | 0 | [-99,99]px支持单值/双值/四值写法 |
| `element_id` | 否 | String | / | 唯一标识,字母开头 ≤20 字符 |
### 子组件内嵌字段(交互组件嵌在 form 内时生效)
| 字段 | 必填 | 说明 |
|---|---|---|
| `name` | 是 | 表单内组件唯一标识,卡片全局唯一,否则提交失败 |
| `required` | 否 | 是否必填;为 true 且未填时点提交会本地拦截,不发起回调 |
| `form_action_type` | 是(按钮) | `submit`(提交)/ `reset`(重置初始值);表单内按钮**不用** `behaviors` |
## 嵌套 / 易错点
- `form` 不支持嵌套 `table``form`;且 `form` 本身只能放卡片根节点下,不能被其他组件嵌套。
- form 内所有交互组件的 `name` 必须填且全局唯一,否则提交失败。
- 表单内必须包含一个 `form_action_type: submit` 的按钮。
- 回调来源:`card.action.trigger``action.tag="button"` + `action.form_value`(按组件 `name` 映射各字段值)。

View File

@@ -0,0 +1,34 @@
# 标题 `header`
卡片顶部标题区(主/副标题、后缀标签、图标、主题色)。**Card 2.0**。挂在卡片根的 `header` 键下,不在 `body.elements` 内,单卡仅一个。
## 最小示例
```json
{
"header": {
"title": { "tag": "plain_text", "content": "卡片标题" },
"template": "blue"
}
}
```
## 字段
| 字段 | 必填 | 类型 | 说明 |
|---|---|---|---|
| `title` | 是 | Object | 主标题,`{tag:"plain_text"\|"lark_md", content}`,最多 4 行 |
| `subtitle` | 否 | Object | 副标题,同 title最多 1 行;只配副标题会按主标题展示 |
| `template` | 否 | String | 主题色枚举,见下;默认 `default` |
| `text_tag_list` | 否 | Array | 后缀标签,最多 3 个,每项 `{tag:"text_tag", text:{tag:"plain_text",content}, color}` |
| `i18n_text_tag_list` | 否 | Object | 多语言后缀标签;与 `text_tag_list` 二选一,同配以多语言为准 |
| `icon` | 否 | Object | 前缀图标(同 `div.icon` |
| `padding` | 否 | String | 内边距,默认 12px[0,99]px |
**template 枚举**13 色):`blue` / `wathet` / `turquoise` / `green` / `yellow` / `orange` / `red` / `carmine` / `violet` / `purple` / `indigo` / `grey` / `default`
**标签 color 枚举**`neutral`/`blue`/`turquoise`/`lime`/`orange`/`violet`/`indigo`/`wathet`/`green`/`yellow`/`red`/`purple`/`carmine`。深浅档位及 RGBA 见 `../resource/colors.md`
## 选色建议
按场景选 template 颜色见 `../lark-im-card-style.md` 意图表。常见语义green=成功/完成orange=警告red=错误/危险grey=失效/归档blue=通用信息。

View File

@@ -0,0 +1,17 @@
# 分割线 `hr`
分隔卡片内容的水平线。**Card 2.0**1.0 同名 `hr`)。
## 最小示例
```json
{ "tag": "hr" }
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `hr` |
| `margin` | 否 | String | 0 | 外边距,范围 [-99,99]px`"8px 0"` |
| `element_id` | 否 | String | / | 组件唯一标识字母开头、≤20 字符 |

View File

@@ -0,0 +1,34 @@
# 图片 `img`
展示图片。需先调上传图片接口拿 `img_key`。**Card 2.0**。
## 最小示例
```json
{
"tag": "img",
"img_key": "img_v3_xxx",
"alt": { "tag": "plain_text", "content": "" }
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `img` |
| `img_key` | 是 | String | / | 图片 key上传图片接口获取 |
| `alt` | 是 | Object | / | hover 说明,`{tag:"plain_text", content:""}`,不需要传空 |
| `title` | 否 | Object | / | 图片标题plain_text 对象 |
| `scale_type` | 否 | String | crop_center | `crop_center` / `crop_top` / `fit_horizontal`(不裁剪) |
| `size` | 否 | String | / | 仅 `crop_*` 生效:`stretch`/`large`(160)/`medium`(80)/`small`(40)/`tiny`(16),或 `"100px 100px"` |
| `corner_radius` | 否 | String | / | 圆角,`[0,∞]px``[0,100]%` |
| `transparent` | 否 | Boolean | false | 是否透明底 |
| `preview` | 否 | Boolean | true | 点击是否放大;配 `card_link` 跳转时设 false |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
| `element_id` | 否 | String | / | 唯一标识,字母开头 ≤20 字符 |
## 易错点
- 通栏效果2.0 不再支持 `size: stretch_without_padding`,改用负 `margin`(如 `"4px -12px"`)。
- 上传规范≤10M、尺寸 ≤1500×3000px、高:宽 ≤16:9。

View File

@@ -0,0 +1,30 @@
# 多图混排 `img_combination`
多张图片按预设版式拼排。**Card 2.0**。
## 最小示例
```json
{
"tag": "img_combination",
"combination_mode": "double",
"img_list": [{ "img_key": "img_v3_a" }, { "img_key": "img_v3_b" }]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `img_combination` |
| `combination_mode` | 是 | String | / | `double`(≤2) / `triple`(≤3) / `bisect`(双列≤6) / `trisect`(三列≤9) |
| `img_list` | 是 | Array | / | 每项 `{ img_key }`,顺序即排列顺序 |
| `combination_transparent` | 否 | Boolean | false | 是否透明底 |
| `corner_radius` | 否 | String | / | 圆角,`[0,∞]px``[0,100]%` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
| `element_id` | 否 | String | / | 唯一标识,字母开头 ≤20 字符 |
## 易错点
- 图片数超过 mode 上限:只显示靠前的,其余丢弃;不足则留空白。
- 上传规范≤10M、≤1500×3000px、高:宽 ≤16:9。

View File

@@ -0,0 +1,43 @@
# 输入框 `input`
收集用户文本输入。常嵌在 `form` 内配合提交按钮使用。**Card 2.0**。
## 最小示例
```json
{
"tag": "input",
"name": "comment",
"placeholder": { "tag": "plain_text", "content": "请输入" },
"label": { "tag": "plain_text", "content": "备注:" }
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `input` |
| `name` | 否* | String | / | 唯一标识;**在 form 内必填且全局唯一**,用于识别提交数据 |
| `required` | 否 | Boolean | false | 是否必填(仅 form 内生效) |
| `placeholder` | 否 | Object | / | 占位文本plain_text≤100 字符 |
| `default_value` | 否 | String | / | 预填内容 |
| `label` | 否 | Object | / | 描述文本plain_text |
| `label_position` | 否 | String | top | `top` / `left`(窄屏自动转 top |
| `input_type` | 否 | String | text | `text` / `multiline_text`(多行,回调含 `\n`) / `password` |
| `rows` | 否 | Number | 5 | 多行时默认行数 |
| `auto_resize` | 否 | Boolean | false | 多行时高度自适应(仅 PC |
| `max_rows` | 否 | Number | / | `auto_resize` 时最大行数 |
| `max_length` | 否 | Number | 1000 | 最大字符数,[1,1000] |
| `show_icon` | 否 | Boolean | true | password 时是否显示前缀图标 |
| `width` | 否 | String | default | `default` / `fill` / `[100,∞)px` |
| `disabled` | 否 | Boolean | false | 是否禁用(配 `disabled_tips` plain_text |
| `behaviors` | 否 | Array | / | `[{type:"callback", value:{...}}]` |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
## 嵌套 / 易错点
- 可嵌套在 column_set / form / collapsible_panel / 循环容器 / interactive_container 内。
- 在 form 内为**异步提交**:用户填完点提交按钮才一次性回调全部表单数据。
- 回调里 `action.tag="input"` + `action.input_value`用户输入值form 提交则值在 `form_value` 内。

View File

@@ -0,0 +1,46 @@
# 交互容器 `interactive_container`
整块可点击区域统一定义内嵌内容的样式和交互callback/open_url适合卡片内的列表项、可点击卡片块。**Card 2.0**。
## 最小示例
```json
{
"tag": "interactive_container",
"width": "fill",
"has_border": true,
"border_color": "grey",
"corner_radius": "8px",
"padding": "4px 12px 4px 12px",
"behaviors": [{ "type": "callback", "value": { "key": "value" } }],
"elements": [
{ "tag": "markdown", "content": "帮我生成一篇产品方案的框架" }
]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `interactive_container` |
| `elements` | 是 | Element[] | [] | 子节点,支持除 `form`/`table` 外的所有组件 |
| `behaviors` | 是 | Array | / | 点击整容器的交互:`callback`(回传)/ `open_url`(跳转),可同数组共存 |
| `width` | 否 | String | fill | `fill`/`auto`/`[16,999]px` |
| `height` | 否 | String | auto | `auto`/`[10,999]px` |
| `direction` | 否 | String | vertical | `vertical`/`horizontal` |
| `horizontal_align`/`vertical_align` | 否 | String | left/top | 对齐方式 |
| `background_style` | 否 | String | default | `default`/`laser`/颜色枚举/RGBA`../resource/colors.md` |
| `has_border` | 否 | Boolean | false | 是否展示 1px 边框 |
| `border_color` | 否 | String | grey | `has_border` 为 true 时生效 |
| `corner_radius` | 否 | String | 0px | `[0,∞]px``[0,100]%` |
| `padding`/`margin` | 否 | String | 4px,12px / 0px | 同间距写法 |
| `disabled` / `disabled_tips` | 否 | Boolean/Object | false / 空 | 禁用整容器及禁用提示 |
| `hover_tips` | 否 | Object | 空 | PC 端悬浮提示 |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
## 嵌套 / 易错点
- 可嵌套除 `form`/`table` 外的所有组件,包括嵌套自身(列表项常见写法)。
- 若容器内有交互组件(如内部 `button`),优先响应该子组件的交互,容器级 `behaviors` 不会触发。
- 回调来源:`card.action.trigger``action.tag` 取决于内部触发的具体组件;容器本身被点击时 `action.value` 即容器 `behaviors.value`

View File

@@ -0,0 +1,56 @@
# 富文本 `markdown`
支持 Markdown + 部分 HTML 的富文本。最常用的内容组件。**Card 2.0**。
## 最小示例
```json
{
"tag": "markdown",
"content": "**标题**\n正文<font color='red'>红字</font>[链接](https://x)"
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `markdown` |
| `content` | 是 | String | / | Markdown 文本JSON 里用 `\n` 换行 |
| `text_size` | 否 | String | normal | `heading-0`~`heading-4` / `normal`(14px) / `notation`(12px) 等;可在 `config.style.text_size` 自定义 pc/mobile 字号 |
| `text_align` | 否 | String | left | `left` / `center` / `right` |
| `icon` | 否 | Object | / | 前缀图标(同 `div.icon` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
| `element_id` | 否 | String | / | 唯一标识,字母开头 ≤20 字符 |
## 常用语法
| 效果 | 语法 |
|---|---|
| 粗 / 斜 / 删除线 | `**粗**``*斜*``~~删~~`(前后留空格更稳) |
| 换行 | JSON 内 `\n`;或 `<br>` |
| 文字链接 | `[文字](https://x)`(必须带 http/https |
| 带图标链接 | `<link icon='chat_outlined' …>文案</link>`icon token 见 `../resource/icons.md` |
| 彩色文本 | `<font color='red'>红字</font>`color 枚举见 `../resource/colors.md`;链接文本不可着色) |
| 标签 | `<text_tag color='blue'>标签</text_tag>`colorneutral/blue/turquoise/lime/orange/violet/indigo/wathet/green/yellow/red/purple/carmine |
| @ 人 | `<at id=ou_xxx></at>``<at id=all></at>``<at ids=id1,id2></at>` |
| @所有人 | `<at id=all></at>`(需群主开权限,否则发送失败) |
| 人员卡片 | `<person id='ou_xxx' show_name=true show_avatar=true style='normal'></person>` |
| 数字角标 | `<number_tag>1</number_tag>`0-99可加 background_color/font_color/url |
| 国际化时间 | `<local_datetime millisecond='' format_type='date_num'></local_datetime>` |
| 标题 | `# 一级` ~ `###### 六级`(大标题显丑,正文优先用加粗,见易错点) |
| 列表 | `- 项`(无序)/ `1. 项`有序4 空格一层缩进 |
| 引用 | `> 引用文字` |
| 行内/块代码 | `` `code` `` / ```` ```go ... ``` ````(可指定语言) |
| 分割线 | `<hr>` 或 `---`(需单独一行) |
| 图片 | `![hover文案](img_key)` |
| 表格 | 标准 MD 表格;除标题最多 5 行(超出分页),单组件 ≤4 表 |
| 飞书表情 | `:DONE:`、`:OK:` |
## 易错点
- **慎用大标题**`#` / `##` / `###` 一~三级标题字号过大、显丑,正文里一律用 `**加粗**` 替代来突出重点。**唯一例外**是「指标卡」里用 `##` 放大数值(见 `../lark-im-card-style.md` 视觉规范)。
- **少用 `markdown` 的 `margin`**:间距优先交给父容器的 `vertical_spacing` / `padding`,多数情况置 `0px`;仅精细缩进时设非零值(见 `../lark-im-card-style.md` 间距纪律)。
- 2.0 不再支持旧的 `[xx]($urlVal)` + `href` 差异化跳转语法,改用 `<link>`。
- 要展示 Markdown 特殊字符(`* ~ > < [ ] ( ) # : _` 等)须 HTML 转义,如 `<`→`&#60;`、`*`→`&#42;`。
- `content` 里的引号注意与 JSON 转义;属性值用单引号可减少冲突。

View File

@@ -0,0 +1,40 @@
# 人员选择-多选 `multi_select_person`
从候选人员中多选。**Card 2.0**。字段与 `select_person` 基本一致,差别在多选默认值。
## 最小示例
```json
{
"tag": "multi_select_person",
"name": "reviewers",
"placeholder": { "tag": "plain_text", "content": "请选择" },
"options": [
{ "value": "ou_xxx" },
{ "value": "ou_yyy" }
]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `multi_select_person` |
| `options` | 否 | Array | / | 候选人 `{value: open_id}`;为空或全无效时候选项为会话全体成员 |
| `selected_values` | 否 | String[] | / | 默认选中的 open_id 数组 |
| `name` | 否* | String | / | 唯一标识;**form 内必填且全局唯一** |
| `required` | 否 | Boolean | false | 是否必选form 内生效) |
| `type` | 否 | String | default | `default`(带框) / `text`(纯文本) |
| `placeholder` | 否 | Object | / | 占位文本plain_text |
| `width` | 否 | String | default | `default` / `fill` / `[100,∞)px` |
| `disabled` | 否 | Boolean | false | 是否禁用 |
| `behaviors` | 否 | Array | / | `[{type:"callback", value:{...}}]` |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
## 嵌套 / 易错点
- 可嵌套在 column_set / form / collapsible_panel / 循环容器 / interactive_container 内。
- `options[].value` 只接受 **open_id**;默认选中用 `selected_values`(数组)。
- 回调返回选中的多个 open_id。

View File

@@ -0,0 +1,40 @@
# 下拉多选 `multi_select_static`
下拉菜单多选。**Card 2.0**。字段与 `select_static` 基本一致,差别在多选默认值。
## 最小示例
```json
{
"tag": "multi_select_static",
"name": "tags",
"placeholder": { "tag": "plain_text", "content": "请选择" },
"options": [
{ "text": { "tag": "plain_text", "content": "选项1" }, "value": "1" },
{ "text": { "tag": "plain_text", "content": "选项2" }, "value": "2" }
]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `multi_select_static` |
| `options` | 否 | Array | / | 选项 `{text:{plain_text}, value, icon?}``value` 不可重复 |
| `selected_values` | 否 | String[] | / | 默认选中的 value 数组 |
| `name` | 否* | String | / | 唯一标识;**form 内必填且全局唯一** |
| `required` | 否 | Boolean | false | 是否必选form 内生效) |
| `type` | 否 | String | default | `default`(带框) / `text`(纯文本) |
| `placeholder` | 否 | Object | / | 占位文本plain_text |
| `width` | 否 | String | default | `default`(带框固定282px) / `fill` / `[100,∞)px` |
| `disabled` | 否 | Boolean | false | 是否禁用 |
| `behaviors` | 否 | Array | / | `[{type:"callback", value:{...}}]` |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
## 嵌套 / 易错点
- 可嵌套在 column_set / form / collapsible_panel / 循环容器 / interactive_container 内。
- 选项 `value` 唯一;默认选中用 `selected_values`(数组)而非单选的 `initial_*`
- 回调返回选中的多个值。

View File

@@ -0,0 +1,36 @@
# 折叠按钮组 `overflow`
折叠多个选项按钮,点击展开。适用于操作较多的场景。**Card 2.0**。
## 最小示例
```json
{
"tag": "overflow",
"options": [
{ "text": { "tag": "plain_text", "content": "选项A" }, "value": "a" },
{ "text": { "tag": "plain_text", "content": "选项B" }, "value": "b" }
]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `overflow` |
| `options` | 是 | Array | / | 选项按钮,见下 |
| `options[].text` | 否 | Object | / | `{tag:"plain_text", content}`≤100 字符 |
| `options[].value` | 否 | String | / | 点击回传值,用于区分点了哪个选项(回调 `action.option` |
| `options[].multi_url` | 否 | Object | / | 跳转链接 `{url, pc_url, ios_url, android_url}` |
| `behaviors` | 否 | Array | / | 额外回传:`[{type:"callback", value:{...}}]` |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}`(均 plain_text |
| `width` | 否 | String | default | `default` / `fill` / `[100,∞)px` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
| `element_id` | 否 | String | / | 唯一标识,字母开头 ≤20 字符 |
## 嵌套 / 易错点
- 可嵌套在 form / collapsible_panel / 循环容器 / interactive_container / column_set 内。
- 多按钮时务必给每个 `options[].value`,否则回调无法区分点了哪个。
- 点击触发 `card.action.trigger`,回传 `action.tag = "overflow"` + `action.option`

View File

@@ -0,0 +1,30 @@
# 人员 `person`
展示单个用户的头像/姓名,点击可看名片。**Card 2.0**。
## 最小示例
```json
{
"tag": "person",
"user_id": "ou_xxx",
"show_name": true
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `person` |
| `user_id` | 是 | String | / | 人员 ID支持 open_id / union_id / user_id |
| `size` | 否 | String | medium | `extra_small` / `small` / `medium` / `large` |
| `show_avatar` | 否 | Boolean | true | 是否显示头像 |
| `show_name` | 否 | Boolean | false | 是否显示姓名 |
| `style` | 否 | String | normal | `normal` / `capsule`(胶囊) |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
| `element_id` | 否 | String | / | 唯一标识,字母开头 ≤20 字符 |
## 易错点
- 发卡应用需有访问用户 ID 的权限,否则人员信息无法展示。

View File

@@ -0,0 +1,31 @@
# 人员列表 `person_list`
展示多个用户的头像/姓名。**Card 2.0**。
## 最小示例
```json
{
"tag": "person_list",
"persons": [{ "id": "ou_xxx" }, { "id": "ou_yyy" }]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `person_list` |
| `persons` | 是 | Array | / | 每项 `{ id }`id 支持 open_id / union_id / user_id |
| `show_name` | 否 | Boolean | true | 是否显示姓名;关掉且多人时为"葫芦串"叠头像样式 |
| `show_avatar` | 否 | Boolean | false | 是否显示头像 |
| `size` | 否 | String | medium | `extra_small` / `small` / `medium` / `large` |
| `lines` | 否 | Int | / | 最大行数,不可为 0 |
| `drop_invalid_user_id` | 否 | Boolean | false | true 忽略无效 IDfalse 则有无效 ID 时报错 |
| `icon` / `ud_icon` | 否 | Object | / | 前缀图标(同 `div.icon`);两者同设以 `icon` 为准 |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
| `element_id` | 否 | String | / | 唯一标识,字母开头 ≤20 字符 |
## 易错点
- 发卡应用需有访问用户 ID 的权限,否则无法展示人员信息。

View File

@@ -0,0 +1,34 @@
# 日期时间选择器 `picker_datetime`
提供日期+时间选项的交互组件,默认拥有交互能力。**Card 2.0**。
## 最小示例
```json
{
"tag": "picker_datetime",
"placeholder": { "tag": "plain_text", "content": "请选择" },
"initial_datetime": "2024-01-01 08:00"
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `picker_datetime` |
| `name` | 否* | String | / | 唯一标识;**form 内必填且全局唯一** |
| `required` | 否 | Boolean | false | 是否必选form 内生效) |
| `initial_datetime` | 否 | String | / | 初始值,格式 `yyyy-MM-dd HH:mm`,会覆盖 `placeholder` |
| `placeholder` | 否 | Object | / | 占位文本plain_text未设 `initial_datetime` 时必填 |
| `width` | 否 | String | default | `default`/`fill`/`[100,∞)px` |
| `disabled` | 否 | Boolean | false | 是否禁用(需端版本 V7.4+ |
| `behaviors` | 否 | Array | / | `[{type:"callback", value:{...}}]` |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
| `margin` | 否 | String | 0 | [-99,99]px |
## 嵌套 / 易错点
- 可嵌套在 column_set / form / collapsible_panel / 循环容器 / 交互容器内;搭建工具中暂不支持嵌套在交互容器中。
- 提醒用户注意时区语境;服务端只返回用户当前时区作为参考,不代表用户选的就是该时区。
- 回调:`action.tag="picker_datetime"` + `action.option`(如 `"2025-06-10 19:19 +0800"`+ `action.timezone`form 内则读 `form_value[name]`

View File

@@ -0,0 +1,34 @@
# 时间选择器 `picker_time`
提供时间选项的交互组件,默认拥有交互能力。**Card 2.0**。
## 最小示例
```json
{
"tag": "picker_time",
"placeholder": { "tag": "plain_text", "content": "请选择" },
"initial_time": "09:00"
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `picker_time` |
| `name` | 否* | String | / | 唯一标识;**form 内必填且全局唯一** |
| `required` | 否 | Boolean | false | 是否必选form 内生效) |
| `initial_time` | 否 | String | / | 初始值,格式 `HH:mm`,会覆盖 `placeholder` |
| `placeholder` | 否 | Object | / | 占位文本plain_text未设 `initial_time` 时必填 |
| `width` | 否 | String | default | `default`/`fill`/`[100,∞)px` |
| `disabled` | 否 | Boolean | false | 是否禁用(需端版本 V7.4+ |
| `behaviors` | 否 | Array | / | `[{type:"callback", value:{...}}]` |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
| `margin` | 否 | String | 0 | [-99,99]px |
## 嵌套 / 易错点
- 可嵌套在 column_set / form / collapsible_panel / 循环容器 / 交互容器内;搭建工具中暂不支持嵌套在交互容器中。
- 提醒用户注意时区语境;服务端只返回用户当前时区作为参考,不代表用户选的就是该时区。
- 回调:`action.tag="picker_time"` + `action.option`(时间字符串,如 `"05:05 +0800"`+ `action.timezone`form 内则读 `form_value[name]`

View File

@@ -0,0 +1,35 @@
# 循环容器(搭建工具专属,无 JSON tag
批量渲染同版式不同数据的列表(如商品列表、推荐列表)。**仅支持在飞书卡片搭建工具中可视化构建,不支持手写卡片 JSON 代码实现**——因此没有 `tag` 字段可直接编排。
## 使用方式
1. 在[卡片搭建工具](https://open.feishu.cn/cardkit)中添加循环容器组件,绑定一个对象数组变量。
2. 在容器内添加任意展示/交互/分栏组件,并将其字段绑定到对象数组的子变量。
3. 发布卡片模板后,发送时通过 `template_variable` 传入实际数据数组,数组每个元素对应一条循环项。
## 发送示例(模板 + 变量赋值)
```json
{
"type": "template",
"data": {
"template_id": "AAqi6xJ8rabcd",
"template_version_name": "1.0.0",
"template_variable": {
"looping": [
{ "title": "**和风陶韵**", "description": "...", "image": { "img_key": "img_v3_xxx" } },
{ "title": "**匠心之作**", "description": "...", "image": { "img_key": "img_v3_yyy" } }
]
}
}
}
```
将以上 JSON 压缩转义后作为 `messages.create``content``msg_type``interactive`
## 嵌套 / 易错点
- 不支持再嵌套循环容器(对象数组变量不支持嵌套对象数组类型)。
- 数组元素个数即渲染条数,可直接控制列表长度。
- 若循环容器内嵌表单容器的交互组件(如 input交互组件的 `name`(表单项标识)必须绑定到不重复的子变量,否则预览/发送报错。

View File

@@ -0,0 +1,42 @@
# 多图选择 `select_img`
以图片为选项的交互组件,支持单选/多选如商品图、模板图、AI 生成图)。仅支持手写 JSON搭建工具不支持。**Card 2.0**。
## 最小示例
```json
{
"tag": "select_img",
"name": "select_img_1",
"layout": "bisect",
"aspect_ratio": "16:9",
"options": [
{ "img_key": "img_v2_xxx", "value": "picture1" },
{ "img_key": "img_v2_yyy", "value": "picture2" }
]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `select_img` |
| `options` | 是 | Array | / | 选项,每项 `{img_key, value, disabled?, disabled_tips?, hover_tips?}` |
| `multi_select` | 否 | Boolean | false | 多选仅支持异步提交,**必须**内嵌在 form 中,否则报错 |
| `layout` | 否 | String | bisect | 图片布局:`stretch`(撑满)/`bisect`(二等分)/`trisect`(三等分) |
| `aspect_ratio` | 否 | String | 16:9 | `1:1`/`16:9`/`4:3` |
| `name` | 否* | String | / | 唯一标识;**form 内必填且全局唯一** |
| `required` | 否 | Boolean | false | 是否必选form 内生效) |
| `can_preview` | 否 | Boolean | true | 点击图片是否弹窗放大(仅 form 内生效) |
| `disabled` | 否 | Boolean | false | 是否禁用整组件 |
| `value` | 否 | String/Object | / | 自定义回传参数 |
| `behaviors` | 是 | Array | / | `[{type:"callback", value:{...}}]` |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
## 嵌套 / 易错点
- 可嵌套在根节点 / column_set / form / 交互容器(搭建工具暂不支持嵌套交互容器)。
- **不在 form 内**:仅支持单选,点击立即提交触发回调,不支持多选/异步提交。
- **在 form 内**:支持单选/多选 + 异步提交(随表单一起提交)。
- 回调(非 form`action.tag="select_img"` + `action.options`单选时仍是该字段form 内则读 `form_value[name]`

View File

@@ -0,0 +1,39 @@
# 人员选择-单选 `select_person`
从候选人员中单选一人。**Card 2.0**。
## 最小示例
```json
{
"tag": "select_person",
"placeholder": { "tag": "plain_text", "content": "请选择" },
"options": [
{ "value": "ou_xxx" },
{ "value": "ou_yyy" }
]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `select_person` |
| `options` | 否 | Array | / | 候选人,每项 `{value: open_id}`**为空或全无效时,候选项为会话内全体成员** |
| `name` | 否* | String | / | 唯一标识;**form 内必填且全局唯一** |
| `required` | 否 | Boolean | false | 是否必选form 内生效) |
| `type` | 否 | String | default | `default`(带框) / `text`(纯文本) |
| `placeholder` | 否 | Object | / | 占位文本plain_text |
| `initial_option` | 否 | String | / | 初始选中的 open_id须在 options 内 |
| `width` | 否 | String | default | `default` / `fill` / `[100,∞)px` |
| `disabled` | 否 | Boolean | false | 是否禁用 |
| `behaviors` | 否 | Array | / | `[{type:"callback", value:{...}}]` |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
## 嵌套 / 易错点
- 可嵌套在 column_set / form / collapsible_panel / 循环容器 / interactive_container 内。
- `options[].value` 只接受 **open_id**
- 回调 `action.tag="select_person"` + `action.option`(选中人的 open_id

View File

@@ -0,0 +1,43 @@
# 下拉单选 `select_static`
下拉菜单单选。**Card 2.0**。
## 最小示例
```json
{
"tag": "select_static",
"placeholder": { "tag": "plain_text", "content": "请选择" },
"options": [
{ "text": { "tag": "plain_text", "content": "选项1" }, "value": "1" },
{ "text": { "tag": "plain_text", "content": "选项2" }, "value": "2" }
]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `select_static` |
| `options` | 否 | Array | / | 选项,见下 |
| `options[].text` | 是 | Object | / | 选项名plain_text |
| `options[].value` | 是 | String | / | 选项回调值,**同组件内不可重复** |
| `options[].icon` | 否 | Object | / | 选项前缀图标(同 `div.icon` |
| `name` | 否* | String | / | 唯一标识;**form 内必填且全局唯一** |
| `required` | 否 | Boolean | false | 是否必选form 内生效) |
| `type` | 否 | String | default | `default`(带框) / `text`(纯文本) |
| `placeholder` | 否 | Object | / | 占位文本plain_text |
| `initial_option` | 否 | String | / | 初始选中内容(覆盖 placeholder 和 initial_index |
| `initial_index` | 否 | Int | / | 初始选中序号0=不选1=第一个 |
| `width` | 否 | String | default | `default` / `fill` / `[100,∞)px` |
| `disabled` | 否 | Boolean | false | 是否禁用 |
| `behaviors` | 否 | Array | / | `[{type:"callback", value:{...}}]` |
| `confirm` | 否 | Object | / | 二次确认弹窗 `{title, text}` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
## 嵌套 / 易错点
- 可嵌套在 column_set / form / collapsible_panel / 循环容器 / interactive_container 内。
- 选项 `value` 必须唯一,否则交互异常、服务端无法区分选了哪个。
- 回调 `action.tag="select_static"` + `action.option`(选中项的 value

View File

@@ -0,0 +1,53 @@
# 表格 `table`
多列数据表,支持文本/数字/选项/人员/日期等列类型。**Card 2.0**。
## 最小示例
```json
{
"tag": "table",
"columns": [
{ "name": "city", "display_name": "城市", "data_type": "text" },
{ "name": "qty", "display_name": "数量", "data_type": "number" }
],
"rows": [
{ "city": "北京", "qty": 12 },
{ "city": "上海", "qty": 8 }
]
}
```
## 字段
| 字段 | 必填 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| `tag` | 是 | String | / | 固定 `table` |
| `columns` | 是 | column[] | / | 列定义≤50 列,见下 |
| `rows` | 是 | Object[] | / | 行数据,按 `列name: 值` 填充 |
| `page_size` | 否 | Number | 5 | 每页行数,[1,10] |
| `row_height` | 否 | String | low | `low`/`middle`/`high`/`auto`/`[32,124]px` |
| `row_max_height` | 否 | String | 124px | `row_height:auto` 时最大行高 [32,999]px |
| `freeze_first_column` | 否 | Boolean | false | 冻结首列 |
| `header_style` | 否 | Object | / | 表头样式:`{text_align, text_size, background_style:grey\|none, text_color, bold, lines}` |
| `margin` | 否 | String | 0 | 外边距 [-99,99]px |
**column 字段**`name`(必填,键名) / `display_name`(表头名) / `data_type`(见下) / `width`(`auto`/`[80,600]px`/`%`) / `horizontal_align` / `vertical_align``number` 列可加 `format:{precision, symbol, separator}``date` 列可加 `date_format`(如 `YYYY/MM/DD`)。
**data_type 与行值结构**
| data_type | 行值 |
|---|---|
| `text` | `"飞书"` |
| `lark_md` | `"[链接](https://x)"` |
| `number` | `168.23` |
| `options` | `[{text:"S2", color:"blue"}]`(颜色枚举见 `../resource/colors.md`,文本勿过长) |
| `persons` | `"ou_xxx"``["ou_a","ou_b"]` |
| `date` | `1699341315000`(毫秒时间戳,按本地时区显示) |
| `markdown` | `"![img](img_key)"` 完整 Markdown |
## 嵌套 / 易错点
- **table 只能放卡片根 `body.elements`**:不能被任何容器嵌套,自身也不能嵌别的组件。
- 单卡最多 5 个 table多语言每语言 5 个)。
- `rows` 的键必须与 `columns[].name` 对应。

View File

@@ -0,0 +1,180 @@
# 发送 Interactive 卡片工作流
用户需要发送一张飞书互动卡片时,遵循本工作流。每次都必须严格按步骤执行。
---
## 入口分支:文字 / 图片 / 图片+文字组合
判断用户输入类型:
- **纯文字诉求**(无图片)→ 跳到 Step 1「文字诉求路径」。
- **纯图片**(截图 / 设计稿,无额外文字说明内容)→ 走「以图片为输入」路径,图片既是内容源也是风格源。
- **图片 + 文字组合** → 走「以图片为输入」路径,但**图片仅当样式/布局参考,内容来源以文字为准**(见第 5 点)。
### 以图片为输入时的处理
1. **分析图片**:从图片中提取视觉风格信息——
- 配色方案(色环定位)、间距节奏、层级关系、分组方式、组件类型
- 图片类型(见第 2 点)
2. **判断图片类型**,决定保真策略:
| 图片类型 | 判断依据 | 构造策略 |
|---|---|---|
| **飞书卡片截图** | 能识别出 header / body / components 等飞书卡片结构特征 | **高保真复刻**:将截图中每一块视觉结构映射到相近的卡片 2.0 组件;复刻后仍需过 P0P7 硬 Gate |
| **其它设计稿 / 海报 / 网页 UI** | 无飞书卡片结构特征 | **风格萃取 + 按原则重构**:提取配色、间距、层级关系等风格 token布局按 P0P7 原则重构(**不像素级仿制**),产出说明偏差 |
3. **确定内容来源**
- **纯图片**:从图片提取内容/信息点(文字、字段、操作)作为诉求(喂给 P0
- **图片 + 文字组合****以文字/文档为内容来源**,图片仅提供样式和布局参考。将文字内容按图片风格组织进卡片
4. **冲突处理**:当图片样式与 P0P7 或卡片组件能力冲突时——
- 飞书卡片截图:在组件能力允许范围内**尽量保真**,冲突处微调并告知用户偏差原因
- 其它设计稿 / 海报 / UI**以 P0P7 为准**,图片仅当风格参考,冲突时不硬搬
5. 分析明确后,向用户简要说明你的**类型判断结论 + 保真策略 + 内容来源方案**。然后进入 Step 2 加载组件文档,进入构造。
---
## Step 1文字诉求路径分析意图输出设计方案
**目标**:在动手写 JSON 之前先明确所有决策并告知用户。Step 2 的文档加载量取决于这里的组件列表,所以要尽量在这一步想清楚。
分析以下内容并向用户简要说明:
1. **版本**Card 2.0 支持的组件更丰富,**推荐使用 Card 2.0**;仅当用户明确要求 1.0 时才用 1.0。
2. **组件组合**:在 `lark-im-card-style.md` 「意图 → 组件组合」表里匹配最接近的意图行,参考推荐组件组合和该行的 `header.template` 颜色(部分行为"无 header")。推荐组合仅供参考,**最终选型以符合用户意图为准**;使用 Card 2.0 时,可同时参考 `card-2.0-schema.md` 中的组件概述来补充或调整组件选择。
3. **交互类型**若有是否含会回调服务端的交互组件以及是否有纯跳转open_url。回调分两类`select` / `multi_select` / `input` / `picker` / `overflow` 操作即默认回调;② `button` / `checker` / `interactive_container` 需显式配置 `behaviors``form` 提交统一回调。细则见 Step 5。
4. **宽度模式**`compact`(400px) 适合通知/祝福/轻提醒(内容精简、单焦点);`default`(≤600px) 适合大多数场景;`fill`(撑满) 适合数据看板、含 `table` 的宽表格。默认 `default`,有明确理由才偏离。
> 输出示例:"Card 2.0header green`default`,组件:`column_set` / `column` / `markdown`,无交互。"
---
## Step 2按需加载组件文档
> ⚠️ **仅 Card 2.0 适用**`card-2.0-schema.md`、`components/` 明细都是 2.0 结构。若 Step 1 定为 **Card 1.0**(含 Step 4 降级场景),这些**不可参考**,跳过本步,直接按 1.0 结构构造。
**目标**:读组件明细 + 「好看的标准」,不全量加载。
> 组件列表来源:**文字路径** = Step 1 的设计方案;**图片路径** = 入口分支图片分析阶段确定的组件列表。
1. 阅读 `card-2.0-schema.md` —— 同时满足两个目的:① 了解组件概述,辅助组件选型;② 找到各组件的明细文档路由链接。**仅读一次,不重复加载。**
2. 按路由逐个读取 `components/<tag>.md`(如 `components/column_set.md``components/button.md`
3. 阅读 `lark-im-card-style.md` 开头的「**好看的标准P0P7**」和「视觉规范」——这是 Step 3 构造和自检的裁判基准,**构造前先内化**。
---
## Step 3构造卡片 JSON
按 Step 2 中对应版本的根结构骨架构造卡片,组件选型遵循 Step 1或图片分析阶段的设计方案。
- Card 2.0 必须有 `"schema": "2.0"`,否则卡片不渲染
- `form` 容器内按钮用 `form_action_type: "submit"`,不写 `behaviors`
- `column_set` 的子节点只能是 `column`,不能直接放其他组件
- `table` **只能放 body 根节点**,不能嵌套进 `column_set` / `interactive_container` 等容器
- `collapsible_panel` 内**不能包含 `form`**`interactive_container` 内**不能包含 `form`/`table`**
### 发送前硬 Gate按 P0P7 自检,不过不许进 Step 4
构造完成后,逐条用 `lark-im-card-style.md` 的「好看的标准」做**结构化自检**。**P0 + P1P3 是阻断项,任一不过必须回到本步修正后重判**,不得带病发送。
**阻断项(必须全过):**
- [ ] **P0 符合诉求**:把用户诉求拆成信息点清单,逐点在 JSON 里找到承载组件;需要的操作(按钮/表单/跳转)都齐备;无与诉求无关的填充
- [ ] **P1 层级**body 内有且仅有**一个**最强焦点;标题用 `**加粗**` 与正文拉开,次要信息用 grey
- [ ] **P2 分组**:同主题字段收进同一容器,不同主题分容器;**没有「一路 hr 平铺」或多主题挤在同一 markdown**
- [ ] **P3 复杂度适中**:视觉块 **25** 个、主色系 ≤3且 >1 个块、至少含一个非纯文本结构元素(背景块/指标卡/图标/表格)——**既不能纯文字流水账,也不能堆砌过载**
**基础卫生(应满足):**
- [ ] **P4 对比**:标题与正文在字号或粗细上至少差一档;正文不滥用 `#/##/###`(指标卡数值放大除外)
- [ ] **P5 对齐**:不滥用散设 `margin`,间距优先交容器;间距取值种类 ≤4非末尾顶级容器间距一致
**加分项(尽量满足):**
- [ ] **P6 语义一致**:同色同义(红=降/警、绿=升/成、grey=次要);主色系起始色与 header 一致、取邻近色环
- [ ] **P7 健壮**:并列/指标列默认 `weighted`/`none`、慎用 `stretch`;必要时配 `config.style.color` light/dark
---
## Step 4发送卡片
```bash
# 发送到群聊
lark-cli im +messages-send --chat-id oc_xxx --msg-type interactive --content '<card_json>'
# 发送给指定用户(私聊)
lark-cli im +messages-send --user-id ou_xxx --msg-type interactive --content '<card_json>'
```
**发送失败时**:先对照下方常见失败列表排查,若能匹配则按对应处理方式修复后重新发送;否则根据错误信息修复 JSON 后重新发送。最多尝试 **3 次**。若 3 次后仍失败,**降级为 Card 1.0 卡片**重新构造并发送。**不参考之前发送 2.0 的记忆**,完全根据用户意图重新构造 1.0 卡片。1.0 无本地参考文档components/、resource/ 均为 2.0)。
**常见失败列表**
| # | 错误信息 | 处理方式 |
|---|---|---|
| 1 | `there is an invalid user resource (at/person) in your card` | 卡片中含有 at/person 组件,但使用了无效的用户 ID。询问用户其真实的 open_id / user_id替换后重新发送。 |
---
## Step 5交互回调可选
若卡片含**会回调服务端的交互组件**,则**支持**监听 `card.action.trigger` 回调(是否监听由实际需求决定,非必须):
**需显式配置 `behaviors: [{type:"callback"}]` 才会回调:**
- `button`(带 callback behavior
- `checker` —— 未配置 behaviors 时仅本地勾选生效,不触发服务端回调
- `interactive_container` —— behaviors 为必填,支持 callback / open_url
**选中 / 输入即默认回调,无需显式 `behaviors`**
- `select_static` / `multi_select_static` / `select_person` / `multi_select_person`
- `overflow` / `input` / `date_picker` / `picker_time` / `picker_datetime`
**form 提交统一回调(按钮用 `form_action_type: "submit"`,无需 behaviors**
- form 内所有表单组件的值通过 `action.form_value` 一次性回传
> 纯 `open_url` 跳转按钮在客户端本地跳转,不回调服务端。
如需处理回调(监听事件、读取字段、更新卡片),见 `../lark-im-card-action-reply.md`
---
## Step 6用户反馈修正按需进入
用户看到已发送卡片后提出修改意见时,遵循以下流程。**不要整卡重做,外科手术式修改。**
### 1. 定位改动范围
把用户意见逐条映射到具体组件和字段:
| 用户反馈类型 | 映射目标 |
|---|---|
| 文案/措辞不满意 | 对应 `markdown.content` / `button.text` / `header.title` |
| 颜色/风格不满意 | 对应 `background_style` / `font_color` / `header.template` / config color token |
| 布局/排列不满意 | 对应 `column_set.flex_mode` / `width` / `weight` / `padding` |
| 缺少某个字段/信息 | 新增 `div.fields` 条目或 `markdown` 行 |
| 某个块太拥挤/太空 | 调整 `padding` / `vertical_spacing` / `margin` |
| 交互行为问题 | 对应 `behaviors` / `confirm` / `disabled` |
### 2. 最小改动原则
- 只改被指出的组件,不动周边结构。
- 改完后**只对被修改组件所涉及的 P 项重新自检**(改颜色 → 过 P6改分组 → 过 P1+P2改间距 → 过 P5
### 3. 重发
修正完成后,重新发送一张新卡(同 Step 4告知用户"已重新发送修正版"。
### 4. 执行前告知
向用户复述"我将修改 ×××",确认后再执行,不要静默改动。
---
## 执行清单
- [ ] 入口:判断是文字诉求(→ Step 1还是图片输入→ 图片分支 → 判断类型→保真策略→组件映射)
- [ ] Step 1分析意图输出设计方案版本 / 宽度模式 / 颜色 / 组件)
- [ ] Step 2读 schema.md + 组件明细 + 「好看的标准 P0P7」
- [ ] Step 3构造 JSON → 过 P0P7 硬 GateP0+P1P3 阻断),不过先修
- [ ] Step 4发送失败按常见失败表排查重试≤3 次);仍失败则降级 Card 1.0 重构发送
- [ ] Step 5若有交互参考 ../lark-im-card-action-reply.md
- [ ] Step 6用户提出修改意见时定位组件→最小改动→原地更新或重发

View File

@@ -0,0 +1,281 @@
# Card Style Guide
选择组件组合和视觉样式的决策指南。字段写法见 `card-2.0-schema.md`
---
## 好看的标准P0P7唯一裁判基准
**先读这一节。** 下面的「意图→组件」表和「视觉规范」都是为这套标准服务的手段;构造和自检卡片时**以 P0P7 为准**。
**目标函数**:一张好卡片 = 让收件人在**约 2 秒一瞥**内 get 到「这是什么 + 最重要的是什么 + 要不要操作」,且观感**有序、克制、不嘈杂**。高效传达与视觉舒适在此统一。
**用力分配**P0 必过(前置闸)→ P1P3 强约束(阻断)→ P4P5 基础卫生 → P6P7 加分。
每条都附**结构化验证句**——卡片不能渲染成图,只能对 JSON 结构推理,所以验证靠「数结构」而非「眯眼看」。
| | 准则 | 可操作要求 | 结构化验证(自检句) |
|---|---|---|---|
| **P0** | **符合诉求**(前置闸·阻断) | 精确承载用户要的信息/意图/操作,不缺、不多、不跑题;意图类型与组件组合匹配 | 把诉求拆成信息点清单,逐点在 JSON 里找到承载组件;操作诉求逐个找到交互组件。有缺=不过 |
| **P1** | **层级**(强约束·阻断) | header 承载「这是什么」body 内**有且仅有一个**最强焦点(最大字号/最重色/指标卡大数字),其余为支撑;标题用 `**加粗**`、次要信息用 grey | 列出所有文本的「字号+粗细+颜色」三元组,能否排出主>次>辅三层;焦点是否唯一 |
| **P2** | **分组**(强约束·阻断) | 同主题字段收进同一容器(`column_set`/`interactive_container`/背景块),不同主题分容器;块边界靠容器底色/描边/间距,**而非一路 `hr` 平铺** | 数顶层视觉块个数;是否存在「多主题挤在同一无分隔 markdown / 一路 hr 平铺」反模式 |
| **P3** | **复杂度适中**(强约束·阻断·双边带) | 下限:不得纯文字流水账,至少有分块+层级+适度色彩/图标;上限:视觉块 25、主色系 ≤3、组件不堆砌、焦点唯一 | ①是否 >1 个视觉块且含≥1 个非纯文本结构元素(背景块/指标卡/图标/表格);②块数 ≤5、主色系 ≤3。两端都满足才过 |
| **P4** | **对比**(基础卫生) | 标题与正文字号或粗细至少差一档;强调用色/放大;正文不滥用 `#/##/###`(数值焦点放大除外,见 P1 | 标题与正文是否在「字号或粗细」上至少差一档 |
| **P5** | **对齐**(基础卫生) | 间距优先交容器 `vertical_spacing`/`horizontal_spacing`/`padding`**不滥用散设 margin 造成疏密无规律**间距值收敛到一套档位2/4/8/12px顶层容器间距一致 | 是否存在无规律的散落 margin间距取值种类是否 ≤4 |
| **P6** | **语义一致**(加分) | 红=降/警/失败、绿=升/成/通过、grey=次要;主色系起始色由 header 决定、取邻近色环;同色同义 | 同一颜色是否对应同一语义header 模板色与块色是否同色系 |
| **P7** | **健壮**(加分) | 并列/指标列默认 `weighted``none`、**慎用 `stretch`**(防移动端拉伸);需要时配 `config.style.color` 的 light/dark不靠固定像素宽硬排 | 是否存在 stretch 拉伸风险;深浅色是否都可读 |
---
## 意图 → 组件组合
### 通知类(无交互或只读)
| 用户意图 | 推荐组件组合 | header.template |
|---|---|---|
| 纯文字通知 / 系统公告 | `column_set`(通知正文,带 `blue-50` 背景)+ `button(open_url)` | `blue` |
| 活动公告(带主视觉图) | `img`(主图)+ `markdown`(时间/地点)+ `column_set`(详情对)+ `button(open_url)` | `turquoise` / `blue` |
| 成功 / 完成状态通知 | `column_set`(关键字段,带 `green-50` 背景)+ `markdown`(结论加粗) | `green` |
| 审批结果反馈(已通过 / 已拒绝) | `column_set`(申请信息)+ `column_set`(审批结论 + icon`green-50`/`red-50` 背景) | `green` / `red` |
| 生日 / 节日祝福 | `img`(主图)+ `column_set`(人名/日期)+ `button(open_url)` | `orange` |
| 产品 / 功能上线推广 | `img`(主图)+ `markdown`(亮点)+ `column_set`(功能高亮块)+ `button(open_url)` | `blue` / `violet` |
| 多图展示图集、AI 生成图) | `img_combination` 或 多个 `img` + `markdown`(说明)+ `button(callback)` | `default` |
### 提醒 + 操作类
| 用户意图 | 推荐组件组合 | header.template |
|---|---|---|
| 提醒 + 一键操作 | `column_set`(详情,带 `yellow-50` 背景)+ `button(callback)` | `yellow` |
| 任务清单 / 待办跟踪 | `checker` × N每项带 `behaviors: callback`+ `button(callback)`(全部完成操作) | `blue` |
| 告警触发(需立即处理) | `column_set`(告警指标,带 `red-50` 背景)+ `column_set`(描述 + input 快速备注)+ `button(callback)` | `red` |
| 告警已解决 / 状态变更 | `column_set`(解决时间 / 负责人,带 `green-50` 背景)+ `markdown`(结论加粗) | `green` |
| 审批待处理(含备注输入) | `column_set`(申请信息,带 `grey-50` 背景)+ `column_set`input 审批意见)+ `button(callback)` × 2通过 / 拒绝) | `default` |
| 日历 / 日程提醒(含参与人) | `column_set`(时间 / 地点,带 `yellow-50` 背景)+ `person_list`(参与人)+ `button(callback)` | `yellow` |
| 危险操作确认 | `column_set`(说明,带 `red-50` 背景)+ `button(callback)` + `confirm` 弹窗配置 | `red` |
### 数据 / 报告类
| 用户意图 | 推荐组件组合 | header.template |
|---|---|---|
| 日报 / 工作汇报 | `column_set`(指标,带背景色)+ `interactive_container`(进展分块,带描边)× N内容过长的块用 `collapsible_panel` 折叠次要细节 | `blue` / `default` |
| 数据看板(含图表) | `column_set`(指标,带 `blue-50` 背景)+ `chart` + `table`(根节点,不可嵌套)+ `markdown`(说明) | `blue` |
| 排行榜 | `column_set` 固定列宽(序号 + 头像 `img` + 名字 + 指标)循环条目 | `grey` |
| 订单 / 工单详情 | `div.fields`(字段对)或 `column_set`(需彩色背景块时)+ `button(callback)` | `orange` |
### 表单 / 收集类
| 用户意图 | 推荐组件组合 | header.template |
|---|---|---|
| 纯文字表单收集 | `form`(内含 `input` + `button(form_action_type: submit)` | `blue` |
| 带下拉选择的表单(单选) | `form`(内含 `select_static` / `select_person` + `input` + `button` | `wathet` |
| 带多选的表单 | `form`(内含 `multi_select_static` / `multi_select_person` + `input` + `button` | `wathet` |
| 含日期 / 时间的表单 | `form`(内含 `date_picker` / `picker_time` / `picker_datetime` + `input` + `button` | `blue` |
| 设备 / 服务反馈 | `form`(内含 `select_static`(满意度)+ `input`(备注)+ `button` | `yellow` |
| 多步骤进度 / 引导 | `column_set`(横向步骤,带 `blue-50` 背景)+ `markdown`(当前状态)+ `button` | `blue` |
### 推荐 / 选择类
| 用户意图 | 推荐组件组合 | header.template |
|---|---|---|
| 推荐列表(带图卡片,可点击) | `interactive_container`(内含 `img` + `markdown`× N + `button(open_url)` | `blue` |
| AI 引导选项 / 功能菜单 | `markdown`(欢迎语)+ `interactive_container`(内含 `markdown` 选项说明)× N | 无 header |
| Bot 功能引导 / 教程 | `column_set`(步骤说明,带背景)+ `button` × 2主操作 / 次操作) | `blue` |
| 服务台 / 多操作入口 | `column_set`(说明,带背景)+ `button` × N≤3 个主操作,`type` 区分主次);次要操作超过 3 个时改用 `overflow`(折叠菜单) | 无 header |
### 社交 / 互动类
| 用户意图 | 推荐组件组合 | header.template |
|---|---|---|
| 工作圈 / 社交分享 | `img_combination`(多图)+ `markdown`(正文)+ `button(open_url)` × 2 | `blue` |
| 成交 / 业绩公告 | `img`(庆祝图)+ `markdown`(成绩)+ `column_set`(关键数字) | `green` |
---
## 视觉规范(实现 P0P7 的具体战术)
组件选型只解决「有没有」,下面各条是落地上面 P0P7 的具体手段,括号标注它主要服务的原则。
> **P3 特例 — 数据看板类**`chart + table + column_set + markdown` 是四种不同组件各出现一次不算「堆砌」P3 上限照常满足;但仍须保证每类只出现一次。
### 0. Header 图标(服务 P3 · 视觉质感底线)
**几乎所有卡片都应配 header icon**——这是提升「精致感」成本最低的一步,缺失会让 header 显得空洞、平价。
```json
"header": {
"title": { "tag": "plain_text", "content": "卡片标题" },
"template": "blue",
"icon": { "tag": "standard_icon", "token": "mail_colorful" }
}
```
- `token``resource/icons.md` 按场景选取;彩色图标用 `*_colorful` 后缀,单色用普通名称。
- 常用速查:通知 `notice_colorful`、告警 `warning_colorful`、审批 `approve_colorful`、日历 `calendar_colorful`、数据 `chart_colorful`、任务 `todo_colorful`、AI `myai_colorful`
### 1. 配色纪律(服务 P6 语义一致)
- **邻近色环**`Red → Carmine → Orange → Yellow → Green → Turquoise → Wathet → Blue → Violet → Purple →回到Red`。一张卡只能取色环上**相邻**的颜色,严禁跳跃(❌ blue + green + red
- **最多 3 种主色系**(不含 grey / white
- **起始色由 header 决定**
- header `blue` → blue / violet / purple
- header `green` → green / turquoise / wathet
- header `red` → red / carmine / orange
- 无 header → 默认 blue / violet / purple
- **深浅语义**(写法 `blue-50``blue-600``grey-500`
- `-50` 区块背景 · `-100` 标签背景 · `-500` 正文文字 · `-600`/`-700` 强调文字
### 2. 间距纪律(服务 P5 对齐 · 视觉决定性因素)
- **body padding 推荐**`"padding": "12px 12px 20px 12px"`(上右下左;底部 20px 留白更舒适)。
- **优先不用 `markdown` / `column``margin` 控间距**:交给父容器的 `vertical_spacing` / `horizontal_spacing` / `padding` 统一管理,多数情况显式置 `0px`;仅在需要精细缩进(如层级左缩进)时才设非零值。
- 容器内 `vertical_spacing` 推荐值:`2px`(高亮块内标题↔正文)/ `4px`(正文段落、列表项)/ `8px`(需拉开的元素)。
- **容器间智能 margin**:某个顶级容器若**不是** body 最后一个元素 → 设 `"margin": "0px 0px 12px 0px"`;若**是**最后一个 → `"0px"` 或不设,避免卡片底部多余留白。
### 3. 指标卡模式(服务 P1 焦点 · 出现 KPI / 数值 / 统计词时强制使用)
触发:内容含 `KPI/ROI/CTR/UV/PV/DAU/GMV/转化率/增长率/总数/营收` 等数值类信息。
- 多个指标并列放进一个 `column_set``flex_mode` **默认用 `"none"`、慎用 `"stretch"`**防移动端拉伸变形P7仅在各列内容等宽、确认移动端不变形时才用 stretch。
- 数值:用 `##` 放大(**唯一允许用 markdown 标题的特例**),可配 `<font>` 上色。
- 描述:`<font color='grey'>` + `text_size: "notation"`
- 居中 `text_align: "center"`;列背景 `background_style: "grey-50"``padding: "12px"``vertical_spacing: "2px"`
```json
{
"tag": "column_set",
"flex_mode": "none",
"horizontal_spacing": "12px",
"columns": [
{ "tag": "column", "width": "weighted", "weight": 1,
"background_style": "grey-50", "corner_radius": "8px",
"padding": "12px", "vertical_spacing": "2px",
"elements": [
{ "tag": "markdown", "content": "## <font color='blue'>5,483</font>", "text_align": "center" },
{ "tag": "markdown", "content": "<font color='grey'>GMV($)</font>", "text_align": "center", "text_size": "notation" }
] }
]
}
```
### 4. 描边卡片模式(服务 P2 分组 · 进展 / 事项 / 列表项分块展示)
`interactive_container` 给每个事项块加描边 + 圆角,视觉上比彩色底色更轻盈,适合进展/工单/任务列表等「多条目」场景。
```json
{
"tag": "interactive_container",
"width": "fill",
"has_border": true,
"border_color": "blue-100",
"corner_radius": "8px",
"background_style": "blue-50",
"padding": "12px 12px 12px 12px",
"vertical_spacing": "4px",
"margin": "0px 0px 12px 0px",
"elements": [
{
"tag": "markdown",
"content": "**<font color='blue'>事项标题</font>**"
},
{
"tag": "markdown",
"content": "事项正文内容……",
"text_size": "normal"
}
]
}
```
- `border_color` 跟随主色系(蓝系用 `blue-100`,绿系用 `green-100`)。
- 不需要交互时可省略 `behaviors`;需要点击回调时加 `"behaviors": [{"type":"callback","value":{...}}]`
- **不能在内部放 `form``table`**。
### 5. 高亮块模式(服务 P2 分组 · 多分类信息成块展示)
两层结构:外层 `column_set` 管布局,内层 `column` 管样式(彩色背景)。
- 每个 `column``background_style` 用浅色(如 `blue-50` / `green-50``padding: "12px 12px 12px 12px"``vertical_spacing: "4px"``weight: 1`
- 块内首行用 `**<font color='blue'>分类标题</font>**` 着色加粗,正文紧随。
- **布局选择**:分类 ≤ 3 个且内容简短 → 水平,优先用 `flex_mode: "bisect"`2 列)或 `"trisect"`3 列);各列字数严格等宽且已确认移动端不变形时才用 `stretch`(慎用,见 §9**分类 ≥ 4 个、奇数、或任一块内容 > 3 行 → 垂直**(每块独占一行)。配色按上面第 1 条邻近色环依次取色。
- ⚠️ **版本依赖**`column.background_style` 需客户端 **≥ v7.9**,旧版静默丢背景。要求强健壮性时改用 `interactive_container``background_style`(无版本限制)替代 column 背景色。
### 6. Header 三件套(服务 P1 层级 · 语境补全)
header 有三层能力,**尽量用满**(至少用 `title` + `icon``subtitle``text_tag_list` 按实际诉求取舍)——这是成本最低、语境最清晰的一步:
- `title`:这是什么(必填)
- `subtitle`:一句上下文(谁发 / 什么时间 / 什么状态≤1 行,`plain_text`
- `text_tag_list`状态标签≤3 个,颜色语义与 P6 保持一致(`blue`=信息、`yellow`=待处理、`red`=紧急、`green`=完成)
```json
"header": {
"title": { "tag": "plain_text", "content": "发版审批" },
"subtitle": { "tag": "plain_text", "content": "2026-06-25 · 后端服务" },
"template": "blue",
"icon": { "tag": "standard_icon", "token": "approve_colorful" },
"text_tag_list": [
{ "tag": "text_tag", "text": { "tag": "plain_text", "content": "待审批" }, "color": "yellow" }
]
}
```
**禁止**:在 `header.title` 里写 emoji把 subtitle 信息改塞进 body 第一行 markdown让 header 空洞;严肃场景(审批/告警/财务)在 title 或 body 标题里用装饰性 emoji。
### 7. 字段对用 `div.fields`,不要用 `column_set` 模拟(服务 P5 对齐)
详情型"label: value"(订单字段、审批信息、日程详情)首选 `div.fields`——原生对齐,结构更轻:
```json
{
"tag": "div",
"fields": [
{ "is_short": true, "text": { "tag": "lark_md", "content": "**提交人**\n张三" } },
{ "is_short": true, "text": { "tag": "lark_md", "content": "**部门**\n研发中台" } },
{ "is_short": true, "text": { "tag": "lark_md", "content": "**提交时间**\n2026-06-25 10:30" } },
{ "is_short": true, "text": { "tag": "lark_md", "content": "**优先级**\n<font color='red'>P0</font>" } }
]
}
```
`is_short: true` 的字段自动两两并排,对齐由组件保证。`column_set` 留给**需要彩色背景块 / 不等宽 / 嵌套复杂结构**的场景,不要用它模拟简单字段对。
### 8. 长文本必须设 `lines` 截断(服务 P3 复杂度上限)
凡接收动态数据的文本字段,必须设最大行数避免卡片被撑爆:
| 位置 | 字段 | 推荐上限 |
|---|---|---|
| `div.text` | `lines` | 正文 ≤4次要说明 ≤2 |
| `person_list` | `lines` | ≤2 |
| `table.header_style` | `lines` | ≤1 |
| `collapsible_panel` | 默认折叠 | 长文本优先用折叠面板而非截断 |
不设 `lines` 的动态文本 = P3 上限的隐患。
### 9. `flex_mode` 决策表(服务 P7 健壮)
| 场景 | 推荐 flex_mode | 原因 |
|---|---|---|
| 指标卡并列(内容不等长) | `none` + `width: weighted` | 防移动端拉伸;各列按比例压缩 |
| 2 列等宽内容(字数相近) | `bisect` | 语义最清晰的两等分 |
| 3 列等宽内容 | `trisect` | 三等分,不写 weight |
| 多 tag / 多图标横排,允许换行 | `flow` | 窄屏自动折行,不挤压 |
| 明确要求两端对齐撑满且内容等宽 | `stretch` | 慎用:移动端窄屏内容过长时会拉伸变形 |
> `stretch` 只在各列字数高度相近、且已确认移动端不变形时使用;其余场景默认 `none`。
### 10. `chart` 配色纳入 P6 纪律
`chart.color_theme` 必须与全卡色系保持一致:
- **默认**`brand`(单色系,跟随飞书品牌色)或 `primary`(主色单色系),安全选项。
- **禁止**`rainbow`——会把色环上的跳跃色全打进图表,直接击穿 P6 的"主色系 ≤3 + 邻近色环"约束。
- **例外**:数据维度 ≥4 个系列、且各系列无主次关系(如区域对比图)时,可用 `complementary` 或在 `chart_spec` 里自定义与主色系邻近的颜色数组。
### 11. `laser` 样式的克制规则(服务 P6 语义一致)
`button.type: "laser"``background_style: "laser"` 是高饱和渐变效果:
- **允许**AI 生成类、节日庆祝类、营销推广类,每卡 **≤1 处**,且位置在主操作按钮或视觉焦点块。
- **禁止**审批、告警、财务、工单、日程等严肃场景——laser 在这些场景里显得轻浮廉价。
- **默认不用**Step 1 设计方案里若要用,需显式说明"×× 场景适合 laser 风格"并得到确认。

View File

@@ -0,0 +1,34 @@
# 颜色枚举
卡片所有颜色字段(`font_color` / `text_color` / `background_style` / `border_color` / icon `color` 等)共用同一套枚举,按属性名区分用途,无单独的文字/背景色表。
## 基础色名14 色系)
`blue` `carmine` `green` `indigo` `lime` `orange` `purple` `red` `sunflower` `turquoise` `violet` `wathet` `yellow` `grey`
> **标签例外**`text_tag` / `<text_tag>` 的灰色用 `neutral`(不是 `grey`);标签枚举无 `grey`。
## 深浅后缀
- 彩色系13 个非 grey`-50 -100 -200 -300 -350 -400 -500 -600 -700 -800 -900`,数字越大越深。
- **无后缀基础名(如 `blue`= `-600`**(同色值)。
- grey 范围更细:`-00 -50 -100 … -650 … -950 -1000`
- 用法语义:`-50` 区块背景 · `-100` 标签背景 · `-500` 正文 · `-600/-700` 强调文字。
## 特殊值
`white`(白)· `bg-white`(背景白:浅色 #ffffff / 深色 #1A1A1A)。无 `transparent` 枚举。
## 自定义 RGBA
`config.style.color` 定义 token 再引用:
```json
"config": { "style": { "color": {
"cus-0": { "light_mode": "rgba(5,157,178,0.52)", "dark_mode": "rgba(...)" }
} } }
```
组件里写 `"font_color": "cus-0"`。RGBA 支持的属性同枚举font/text_color、background_style、border_color、icon color 等)。
> `column` 的 `background_style` 需客户端 v7.9+。配色搭配规则见 `../lark-im-card-style.md` 视觉规范。

View File

@@ -0,0 +1,38 @@
# 图标枚举
用于 `header.icon``div.icon``markdown``<link icon=...>` 等。
## 结构
```json
// 系统图标(推荐):用 token
{ "tag": "standard_icon", "token": "info_outlined", "color": "blue" }
// 自定义图标:用上传的 img_key
{ "tag": "custom_icon", "img_key": "img_v3_xxx" }
```
`color` 取颜色枚举(见 `colors.md`),仅对 `standard_icon` 生效。
## token 命名
- 线性:后缀 `_outlined`;面性(实心):后缀 `_filled`
- 主体 kebab-case`calendar-add_outlined``delete-trash_outlined`
## 常用 token业务卡片
| 含义 | token | 含义 | token |
|---|---|---|---|
| 完成/对勾 | `done_outlined` | 关闭/叉 | `close_outlined` |
| 新增 | `add_outlined` | 编辑 | `edit_outlined` |
| 删除 | `delete-trash_outlined` | 搜索 | `search_outlined` |
| 设置 | `setting_outlined` | 信息 | `info_outlined` |
| 警告 | `warning_outlined` | 时间 | `time_outlined` |
| 日历 | `calendar_outlined` | 成员 | `member_outlined` |
| 群组 | `group_outlined` | 会话 | `chat_outlined` |
| 邮件 | `mail_outlined` | 链接 | `link-copy_outlined` |
| 分享 | `share_outlined` | 下载 | `download_outlined` |
| 通知/铃铛 | `bell_outlined` | 定位 | `pin_outlined` |
| 附件 | `attachment_outlined` | 审批 | `approval_outlined` |
> token 必须与官方完全一致,否则图标不渲染。上表为常用项,全量(数百个,分系统/商务/沟通/用户/媒体/文档等类目)以官方图标库为准:
> https://open.larkoffice.com/document/feishu-cards/enumerations-for-icons

View File

@@ -155,6 +155,15 @@ lark-cli im +messages-reply --message-id om_xxx --text "Received" --idempotency-
# Preview the request without executing it
lark-cli im +messages-reply --message-id om_xxx --markdown $'## Test\n\nhello' --dry-run
# ===== Interactive Card =====
# 🚫 STOP — before constructing ANY interactive card JSON, you MUST read
# card/lark-im-card-create.md and follow its workflow. Do NOT
# hand-write or copy a card payload. The JSON passed to --content must be
# the OUTPUT of that workflow. This is non-negotiable.
# Once the workflow has produced the card JSON, reply with it:
lark-cli im +messages-reply --message-id om_xxx --msg-type interactive --content '<card_json_from_workflow>'
```
## Media Input Rules
@@ -265,3 +274,4 @@ Card content is **not** normalized — use the card-native `<at>` syntax inside
- `--as user` uses a user access token (UAT) and requires the `im:message.send_as_user` and `im:message` scopes; the reply is sent as the authorized end user
- `--as bot` uses a tenant access token (TAT), and requires the `im:message:send_as_bot` scope
- When using `--markdown` with images, pre-uploading via `images.create` to obtain an `image_key` is recommended for reliability; remote URLs may be auto-resolved at runtime, but if download/upload fails the image is removed with a warning; local paths are not supported
- **Interactive cards are gated:** you MUST read and follow the [`card/lark-im-card-create.md`](card/lark-im-card-create.md) workflow to produce the card JSON *before* replying. Do not hand-write or copy a card payload — the JSON given to `--msg-type interactive --content` must be the workflow's output. This applies every time, with no exception

View File

@@ -158,6 +158,15 @@ lark-cli im +messages-send --chat-id oc_xxx --text "Hello" --idempotency-key my-
# Preview the request without executing it
lark-cli im +messages-send --chat-id oc_xxx --markdown $'## Test\n\nhello' --dry-run
# ===== Interactive Card =====
# 🚫 STOP — before constructing ANY interactive card JSON, you MUST read
# card/lark-im-card-create.md and follow its workflow. Do NOT
# hand-write or copy a card payload from the examples below. The JSON passed
# to --content must be the OUTPUT of that workflow. This is non-negotiable.
# Once the workflow has produced the card JSON, send it:
lark-cli im +messages-send --chat-id oc_xxx --msg-type interactive --content '<card_json_from_workflow>'
```
## Media Input Rules
@@ -213,7 +222,9 @@ lark-cli im +messages-send --chat-id oc_xxx --markdown $'## Test\n\nhello' --dry
| `media` | `{"file_key":"file_xxx","image_key":"img_xxx"}` (video; `image_key` is the cover from `--video-cover`**required**) |
| `share_chat` | `{"chat_id":"oc_xxx"}` |
| `share_user` | `{"user_id":"ou_xxx"}` |
| `interactive` | Card JSON (see Feishu interactive card documentation) |
| `interactive` | Card JSON **MUST** be produced by the [`card/lark-im-card-create.md`](card/lark-im-card-create.md) workflow. Read it before writing any card; never hand-craft the JSON here |
> **`post` vs `interactive`:** `post` is a static rich-text message (title, paragraphs, @mentions, links, inline images) — content is fixed once sent. `interactive` is a card with structured layout and UI components (buttons, forms, selects, date pickers, charts) — content can be updated after sending and supports user-action callbacks. Use `post` for read-only content; use `interactive` when the message needs user interaction or dynamic updates.
`interactive` cards support callback events (`card.action.trigger`) — see [`lark-im-card-action-reply.md`](lark-im-card-action-reply.md).
@@ -265,3 +276,4 @@ Card content is **not** normalized — use the card-native `<at>` syntax inside
- `--as bot` uses a tenant access token (TAT) and requires the `im:message:send_as_bot` scope
- When sending as a bot, the app must already be in the target group or already have a direct-message relationship with the target user
- When using `--markdown` with images, pre-uploading via `images.create` to obtain an `image_key` is recommended for reliability; remote URLs may be auto-resolved at runtime, but if download/upload fails the image is removed with a warning; local paths are not supported
- **Interactive cards are gated:** you MUST read and follow the [`card/lark-im-card-create.md`](card/lark-im-card-create.md) workflow to produce the card JSON *before* sending. Do not hand-write or copy a card payload — the JSON given to `--msg-type interactive --content` must be the workflow's output. This applies every time, with no exception