11 KiB
发送 Interactive 卡片工作流
用户需要发送一张飞书互动卡片时,遵循本工作流。每次都必须严格按步骤执行。
入口分支:文字 / 图片 / 图片+文字组合
判断用户输入类型:
- 纯文字诉求(无图片)→ 跳到 Step 1「文字诉求路径」。
- 纯图片(截图 / 设计稿,无额外文字说明内容)→ 走「以图片为输入」路径,图片既是内容源也是风格源。
- 图片 + 文字组合 → 走「以图片为输入」路径,但图片仅当样式/布局参考,内容来源以文字为准(见第 5 点)。
以图片为输入时的处理
-
分析图片:从图片中提取视觉风格信息——
- 配色方案(色环定位)、间距节奏、层级关系、分组方式、组件类型
- 图片类型(见第 2 点)
-
判断图片类型,决定保真策略:
图片类型 判断依据 构造策略 飞书卡片截图 能识别出 header / body / components 等飞书卡片结构特征 高保真复刻:将截图中每一块视觉结构映射到相近的卡片 2.0 组件;复刻后仍需过 P0–P7 硬 Gate 其它设计稿 / 海报 / 网页 UI 无飞书卡片结构特征 风格萃取 + 按原则重构:提取配色、间距、层级关系等风格 token;布局按 P0–P7 原则重构(不像素级仿制),产出说明偏差 -
确定内容来源:
- 纯图片:从图片提取内容/信息点(文字、字段、操作)作为诉求(喂给 P0)
- 图片 + 文字组合:以文字/文档为内容来源,图片仅提供样式和布局参考。将文字内容按图片风格组织进卡片
-
冲突处理:当图片样式与 P0–P7 或卡片组件能力冲突时——
- 飞书卡片截图:在组件能力允许范围内尽量保真,冲突处微调并告知用户偏差原因
- 其它设计稿 / 海报 / UI:以 P0–P7 为准,图片仅当风格参考,冲突时不硬搬
-
分析明确后,向用户简要说明你的类型判断结论 + 保真策略 + 内容来源方案。然后进入 Step 2 加载组件文档,进入构造。
Step 1(文字诉求路径):分析意图,输出设计方案
目标:在动手写 JSON 之前,先明确所有决策并告知用户。Step 2 的文档加载量取决于这里的组件列表,所以要尽量在这一步想清楚。
分析以下内容并向用户简要说明:
- 版本:Card 2.0 支持的组件更丰富,推荐使用 Card 2.0;仅当用户明确要求 1.0 时才用 1.0。
- 组件组合:在
lark-im-card-style.md「意图 → 组件组合」表里匹配最接近的意图行,参考推荐组件组合和该行的header.template颜色(部分行为"无 header")。推荐组合仅供参考,最终选型以符合用户意图为准;使用 Card 2.0 时,可同时参考card-2.0-schema.md中的组件概述来补充或调整组件选择。 - 交互类型(若有):是否含会回调服务端的交互组件,以及是否有纯跳转(open_url)。回调分两类:①
select/multi_select/input/picker/overflow操作即默认回调;②button/checker/interactive_container需显式配置behaviors;form提交统一回调。细则见 Step 5。 - 宽度模式:
compact(400px) 适合通知/祝福/轻提醒(内容精简、单焦点);default(≤600px) 适合大多数场景;fill(撑满) 适合数据看板、含table的宽表格。默认default,有明确理由才偏离。
输出示例:"Card 2.0,header 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 的设计方案;图片路径 = 入口分支图片分析阶段确定的组件列表。
- 阅读
card-2.0-schema.md—— 同时满足两个目的:① 了解组件概述,辅助组件选型;② 找到各组件的明细文档路由链接。仅读一次,不重复加载。 - 按路由逐个读取
components/<tag>.md(如components/column_set.md、components/button.md) - 阅读
lark-im-card-style.md开头的「好看的标准(P0–P7)」和「视觉规范」——这是 Step 3 构造和自检的裁判基准,构造前先内化。
Step 3:构造卡片 JSON
按 Step 2 中对应版本的根结构骨架构造卡片,组件选型遵循 Step 1(或图片分析阶段)的设计方案。
- Card 2.0 必须有
"schema": "2.0",否则卡片不渲染 form容器内按钮用form_action_type: "submit",不写behaviorscolumn_set的子节点只能是column,不能直接放其他组件table只能放 body 根节点,不能嵌套进column_set/interactive_container等容器collapsible_panel内不能包含form;interactive_container内不能包含form/table
发送前硬 Gate(按 P0–P7 自检,不过不许进 Step 4)
构造完成后,逐条用 lark-im-card-style.md 的「好看的标准」做结构化自检。P0 + P1–P3 是阻断项,任一不过必须回到本步修正后重判,不得带病发送。
阻断项(必须全过):
- P0 符合诉求:把用户诉求拆成信息点清单,逐点在 JSON 里找到承载组件;需要的操作(按钮/表单/跳转)都齐备;无与诉求无关的填充
- P1 层级:body 内有且仅有一个最强焦点;标题用
**加粗**与正文拉开,次要信息用 grey - P2 分组:同主题字段收进同一容器,不同主题分容器;没有「一路 hr 平铺」或多主题挤在同一 markdown
- P3 复杂度适中:视觉块 2–5 个、主色系 ≤3;且 >1 个块、至少含一个非纯文本结构元素(背景块/指标卡/图标/表格)——既不能纯文字流水账,也不能堆砌过载
基础卫生(应满足):
- P4 对比:标题与正文在字号或粗细上至少差一档;正文不滥用
#/##/###(指标卡数值放大除外) - P5 对齐:不滥用散设
margin,间距优先交容器;间距取值种类 ≤4;非末尾顶级容器间距一致
加分项(尽量满足):
- P6 语义一致:同色同义(红=降/警、绿=升/成、grey=次要);主色系起始色与 header 一致、取邻近色环
- P7 健壮:并列/指标列默认
weighted/none、慎用stretch;必要时配config.style.colorlight/dark
Step 4:发送卡片
# 发送到群聊
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_personoverflow/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 + 组件明细 + 「好看的标准 P0–P7」
- Step 3:构造 JSON → 过 P0–P7 硬 Gate(P0+P1–P3 阻断),不过先修
- Step 4:发送,失败按常见失败表排查重试(≤3 次);仍失败则降级 Card 1.0 重构发送
- Step 5:若有交互,参考 ../lark-im-card-action-reply.md
- Step 6:用户提出修改意见时,定位组件→最小改动→原地更新或重发