# 使用飞书消息卡片变量功能，批量数据快速录入消息卡片

- Link: https://www.ixiqin.com/2023/08/22/use-the-feishu-message-card-variable-function-to-quickly/
- Published: 2023-08-22T06:38:48+08:00
- Author: 白宦成

文章目录

 [Toggle](https://www.ixiqin.com/2023/08/22/use-the-feishu-message-card-variable-function-to-quickly/#)

 * [解构消息卡片](https://www.ixiqin.com/2023/08/22/use-the-feishu-message-card-variable-function-to-quickly/#%e8%a7%a3%e6%9e%84%e6%b6%88%e6%81%af%e5%8d%a1%e7%89%87)
 * [代码片段](https://www.ixiqin.com/2023/08/22/use-the-feishu-message-card-variable-function-to-quickly/#%e4%bb%a3%e7%a0%81%e7%89%87%e6%ae%b5)
    - [文章中构建的出的卡片](https://www.ixiqin.com/2023/08/22/use-the-feishu-message-card-variable-function-to-quickly/#%e6%96%87%e7%ab%a0%e4%b8%ad%e6%9e%84%e5%bb%ba%e7%9a%84%e5%87%ba%e7%9a%84%e5%8d%a1%e7%89%87)
    - [完整代码参考](https://www.ixiqin.com/2023/08/22/use-the-feishu-message-card-variable-function-to-quickly/#%e5%ae%8c%e6%95%b4%e4%bb%a3%e7%a0%81%e5%8f%82%e8%80%83)

在开发短链助手的时候，我需要实现一个查看当前用户创建的所有短链接的能力。这个依然
希望通过消息卡片来完成。而作为一个 JSON，想要构建一套合适的内容，就变得十分的麻烦
和复杂。

![](https://postimg.aliavv.com/m1/ql9bov.png)

## 解构消息卡片

我要发送的消息卡片当中，可以区分为动态内容和静态内容，对于静态内容，我可能长期都
不会变化，而静态内容，则会根据用户的数据发生变化。

![](https://postimg.aliavv.com/m1/wsyp71.png)

如果整体都放在代码中生成，我就需要有一段又臭又长的代码来维护其中的变化的 JSON ，
而我希望整个代码的简洁，不要有比较长的代码只是用来生成卡片的逻辑，所以就用上了消息
卡片的新功能：循环对象数组。

而进一步看动态内容，则我们可以将其视为是变量 A 和变量 B 在不断的被重复赋予，最终
形成了一行一行的结果。

![](https://postimg.aliavv.com/m1/k7xizt.png)

而我们想要实现这样功能。首先，需要在卡片搭建工具中创建一个循环对象数组，并将其绑
定在一个「多列布局」上。

![](https://postimg.aliavv.com/m1/dg2nvw.png)

绑定完成后，你的多列布局就有了被循环的可能性。

接下来你需要在多列布局中去构建你的每一行的结果，并在对应的位置绑定上变量，比如我
这里就给多列布局防止了一个 Markdown 文本组件，并在这个文本组件中，填入了 `${source}`
作为变量 A 进行填充。

![](https://postimg.aliavv.com/m1/e3w12l.png)

当你根据你的需要，构建出需要的卡片结构后，点击右上角的保存并发布，就可以准备写代码
来实现批量发送数据的逻辑了。

## 代码片段

这里的逻辑不复杂，首先需要从数据库中提取出需要用用作列表循环的数据，这里以 data.
data 为例，data.data 是一个包含了 Object 的 Array，其中每一个 Object 都有 Postfix
和 Link 两个字段。这两个字段就是我们稍后要塞在卡片中的。

    ```javascript
           // data.data = [{Postfix:"a",Link:"https://amazon.cn"}]
            let links = data.data.map(item => {
              return {
                source: `[${item.Postfix}](https://link.feishu.io/${item.Postfix})`,
                target: item.Link
              }
            })
            await client.request({
              method: "POST",
              url: "https://open.feishu.cn/open-apis/im/v1/messages",
              data: {
                receive_id: ctx.body.event.operator.operator_id.open_id,
                msg_type: 'interactive',
                content: JSON.stringify({
                  "type": "template",
                  "data": {
                    "template_id": "ctp_AAmFBm5vnHfs",
                    "template_variable": {
                      "CONTENT": links
                    }
                  }
                }),
              },
              params: {
                receive_id_type: 'open_id',
              },
            })
    Code language: JavaScript (javascript)
    ```

最终我们构建出来，发给飞书服务器的 JSON 其实是这样子的，这段 JSON 就会和我们在卡片
搭建工具中构建的 JSON 租和，自动进行拼接，从而实现我们想要的循环效果。

    ```shcb-line-numbers
    {
      "type": "template",
      "data": {
        "template_id": "ctp_AAmFBm5vnHfs",
        "template_variable": {
          "CONTENT": [
            {
              "source":"a",
              "target":"https://amazon.cn"
            },
            {
              "source":"b",
              "target":"https://baidu.com"
            }
          ]
        }
      }
    }
    Code language: JSON / JSON with Comments (json)
    ```

### 文章中构建的出的卡片

构建出的卡片 JSON 是这样的，方便你参考：

    ```shcb-line-numbers
    {
      "elements": [
        {
          "tag": "markdown",
          "content": "你创建的链接如下："
        },
        {
          "tag": "column_set",
          "flex_mode": "none",
          "background_style": "grey",
          "columns": [
            {
              "tag": "column",
              "width": "weighted",
              "weight": 1,
              "vertical_align": "top",
              "elements": [
                {
                  "tag": "div",
                  "text": {
                    "content": "${source}",
                    "tag": "lark_md"
                  }
                }
              ]
            },
            {
              "tag": "column",
              "width": "weighted",
              "weight": 4,
              "vertical_align": "top",
              "elements": [
                {
                  "tag": "div",
                  "text": {
                    "content": "${target}",
                    "tag": "lark_md"
                  }
                }
              ]
            }
          ],
          "_varloop": "${CONTENT}"
        }
      ],
      "header": {
        "template": "turquoise",
        "title": {
          "content": "链接清单",
          "tag": "plain_text"
        }
      },
      "card_link": {
        "url": "",
        "pc_url": "",
        "android_url": "",
        "ios_url": ""
      }
    }
    Code language: JSON / JSON with Comments (json)
    ```

### 完整代码参考

    ```javascript
    import cloud from '@lafjs/cloud'
    import axios from 'axios'

    let appid = "";
    let secret = ""

    const lark = require('@larksuiteoapi/node-sdk');

    const client = new lark.Client({
      appId: appid,
      appSecret: secret
    });


    export default async function (ctx: FunctionContext) {

      console.log("event",ctx.body);

      if (ctx.body.challenge) {
        return ctx.body
      }

      if (Object.hasOwn(ctx.body, "action") && ctx.body.action) {
        if (ctx.body.action.name != "submit") return { code: 1 };
        try {
          // function to create link

          if (status == 200) {
            return JSON.stringify({
              "type": "template",
              "data": {
                "template_id": "ctp_AAmFBm5vnlt0",
                "template_variable": {
                  "source": ctx.body.action.form_value.postfix,
                  "target": ctx.body.action.form_value.link
                }
              }
            })
          }
          return {};
        } catch (e) {
          return JSON.stringify({
            "type": "template",
            "data": {
              "template_id": "ctp_AAmFBm5vZYuo",
              "template_variable": {
                "POSTFIX": ctx.body.action.form_value.postfix
              }
            }
          });
        }
      }

      if (Object.hasOwn(ctx.body, "header") && ctx.body.header.event_type == 'application.bot.menu_v6') {
        // 处理按钮
        if (ctx.body.event.event_key == "help") {
          try {
            let content = JSON.stringify({
              template_id: "ctp_AAmFBFOpYX0S"
            });
            await client.request({
              method: "POST",
              url: "https://open.feishu.cn/open-apis/im/v1/messages",
              data: {
                receive_id: ctx.body.event.operator.operator_id.open_id,
                msg_type: 'interactive',
                content: JSON.stringify({
                  "type": "template",
                  "data": {
                    "template_id": "ctp_AAmFBFOpYX0S",
                  }
                }),
              },
              params: {
                receive_id_type: 'open_id',
              },
            })
            return {};
          } catch (e) {
            console.log(`key: ${ctx.body.event.event_key}, user:${ctx.body.event.operator.operator_id.open_id},error`, e);
            return {};
          }
        }
        if (ctx.body.event.event_key == "mylink") {
          try {
            // function to get all my link 
            let links = data.data.map(item => {
              return {
                source: `[${item.Postfix}](https://link.feishu.io/${item.Postfix})`,
                target: item.Link
              }
            })
            await client.request({
              method: "POST",
              url: "https://open.feishu.cn/open-apis/im/v1/messages",
              data: {
                receive_id: ctx.body.event.operator.operator_id.open_id,
                msg_type: 'interactive',
                content: JSON.stringify({
                  "type": "template",
                  "data": {
                    "template_id": "ctp_AAmFBm5vnHfs",
                    "template_variable": {
                      "CONTENT": links
                    }
                  }
                }),
              },
              params: {
                receive_id_type: 'open_id',
              },
            })
            return {};
          } catch (e) {
            console.log(`key: ${ctx.body.event.event_key}, user:${ctx.body.event.operator.operator_id.open_id},error`, e);
            return {};
          }
        }
        if (ctx.body.event.event_key == "create") {
          try {
            await client.request({
              method: "POST",
              url: "https://open.feishu.cn/open-apis/im/v1/messages",
              data: {
                receive_id: ctx.body.event.operator.operator_id.open_id,
                msg_type: 'interactive',
                content: "{\"header\":{\"template\":\"turquoise\",\"title\":{\"content\":\"创建短链接\",\"tag\":\"plain_text\"}},\"elements\":[{\"tag\":\"form\",\"name\":\"form_1\",\"elements\":[{\"tag\":\"input\",\"name\":\"postfix\",\"placeholder\":{\"tag\":\"plain_text\",\"content\":\"请输入后缀\"},\"max_length\":10,\"label\":{\"tag\":\"plain_text\",\"content\":\"请输入后缀:\"},\"label_position\":\"left\",\"value\":{\"k\":\"v\"}},{\"tag\":\"input\",\"name\":\"link\",\"placeholder\":{\"tag\":\"plain_text\",\"content\":\"请输入要跳转链接\"},\"label\":{\"tag\":\"plain_text\",\"content\":\"请输入要跳转链接:\"},\"label_position\":\"left\",\"value\":{\"k\":\"v\"}},{\"action_type\":\"form_submit\",\"name\":\"submit\",\"tag\":\"button\",\"text\":{\"content\":\"提交\",\"tag\":\"lark_md\"},\"type\":\"primary\",\"confirm\":{\"title\":{\"tag\":\"plain_text\",\"content\":\"创建短链接\"},\"text\":{\"tag\":\"plain_text\",\"content\":\"确认提交吗\"}}}]}]}",
              },
              params: {
                receive_id_type: 'open_id',
              },
            })
            return {};
          } catch (e) {
            console.log(`key: ${ctx.body.event.event_key}, user:${ctx.body.event.operator.operator_id.open_id},error`, e);
            return {};
          }
        }
      }
      return { data: 'hi, laf' }
    }
    Code language: JavaScript (javascript)
    ```
