如何通过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
- email:
- name:
- status:
active
内容的提问来源于stack exchange,提问作者Greythos
相关产品推荐
相关产品推荐

