You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Webhook为MS Teams生成带层级格式的动态Adaptive Cards

优化MS Teams自适应卡片的嵌套对象结构化展示

目前通过Webhook发送自适应卡片到Teams时,嵌套对象会被渲染成无差别的长列表,无法区分父子层级。需要优化代码,让卡片展示接近JSON.stringify(value, null, 2)的结构化样式,清晰区分层级关系。

原代码

export function contextToFormattedAdCard(objToParse: any): Array<Record<string, any>> {
  const attachments: Array<Record<string, any>> = [
    {
      "contentType":"application/vnd.microsoft.card.adaptive",
      "contentUrl":null,
      "content":{
        "$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
        "type":"AdaptiveCard",
        "version":"1.2",
        "body":[        ]
      }
    }
  ];

  let newCard = {
    "type":"Message",
    "version":"1.2",
    "body":[]
  }

  function processObject(objToFormat: Record<string, any>): any {
    for (const key in objToFormat) {
      const value = objToFormat[key];
      const keyValuePair = `${key} : ${value}`;

      if (typeof value === 'object') {

        const nestedObj =  {
          type: "Container",
          items: [
            {
              contentType: "application/vnd.microsoft.card.adaptive",
              content: {
                $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
                type: "AdaptiveCard",
                version: "1.2",
                body: contextToFormattedAdCard(value),
              },
            },
          ],
        };
        attachments[0].content.body.push(nestedObj);
      } else {

        attachments[0].content.body.push({
          type: "TextBlock",
          text: keyValuePair,
          wrap: true,
        });
      }
    }
  }

  processObject(objToParse);
  return attachments;
}

优化后的代码

export function contextToFormattedAdCard(objToParse: any): Array<Record<string, any>> {
  const attachments: Array<Record<string, any>> = [
    {
      "contentType": "application/vnd.microsoft.card.adaptive",
      "contentUrl": null,
      "content": {
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "type": "AdaptiveCard",
        "version": "1.2",
        "body": []
      }
    }
  ];

  // 递归处理对象/数组,传递层级参数控制样式
  function processItem(item: any, level: number = 0): Array<any> {
    const elements: Array<any> = [];
    const indentPadding = level * 16; // 每层缩进16px

    if (Array.isArray(item)) {
      // 处理数组:显示索引+元素
      item.forEach((value, index) => {
        // 数组索引标签
        elements.push({
          type: "TextBlock",
          text: `*[${index}]*`,
          wrap: true,
          size: "small",
          color: "accent",
          padding: { top: 4, bottom: 0, left: indentPadding }
        });

        if (typeof value === 'object' && value !== null) {
          // 递归处理数组内的嵌套对象/数组
          elements.push(...processItem(value, level + 1));
        } else {
          // 数组内的基础值
          elements.push({
            type: "TextBlock",
            text: `${value}`,
            wrap: true,
            padding: { top: 0, bottom: 8, left: indentPadding + 16 }
          });
        }
      });
    } else if (typeof item === 'object' && item !== null) {
      // 处理对象:显示key+值
      Object.entries(item).forEach(([key, value]) => {
        // 对象key标签(加粗区分)
        elements.push({
          type: "TextBlock",
          text: `**${key}**:`,
          wrap: true,
          weight: "bold",
          padding: { top: 4, bottom: 0, left: indentPadding }
        });

        if (typeof value === 'object' && value !== null) {
          // 递归处理嵌套对象/数组
          elements.push(...processItem(value, level + 1));
        } else {
          // 对象的基础值
          elements.push({
            type: "TextBlock",
            text: `${value}`,
            wrap: true,
            padding: { top: 0, bottom: 8, left: indentPadding + 16 }
          });
        }
      });
    }

    return elements;
  }

  // 初始化处理根对象
  attachments[0].content.body.push(...processItem(objToParse));
  return attachments;
}

关键优化点

  • 层级缩进:通过level参数控制每个层级的左内边距,模拟JSON格式化的缩进效果
  • 视觉区分:
    • 对象的key用加粗文本块突出
    • 数组索引用斜体+强调色标注
    • 基础值相对于key/索引再缩进一级
  • 递归逻辑:统一处理对象和数组,避免嵌套生成新的自适应卡片,保持内容在同一张卡片内
  • 特殊值处理:排除null类型的误判,避免显示[object Object]

效果示例

传入以下测试对象:

const testObj = {
  "user": {
    "name": "John Doe",
    "age": 30,
    "tags": ["admin", "user"],
    "contact": {
      "email": "john@example.com",
      "phone": "123-456-7890"
    }
  },
  "status": "active"
};

卡片会渲染为结构化的层级样式:

  • user:
    • name:
      John Doe
    • age:
      30
    • tags:
      [0]
      admin
      [1]
      user
    • contact:
      • email:
        john@example.com
      • phone:
        123-456-7890
  • status:
    active

内容的提问来源于stack exchange,提问作者Greythos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 16:15:36