本文介绍如何使用 Teams SDK (Teams AI 库) 调用和关闭 (以前称为任务) 模块的对话。 在 Teams SDK 中,使用 TaskFetchAction 从自适应卡片操作调用对话框,并通过对话打开和提交类上的 App 事件进行处理。
事件注册因语言而异:
-
TypeScript:
app.on('dialog.open', ...)和app.on('dialog.submit', ...) -
C#:
teamsApp.OnTaskFetch(...)和teamsApp.OnTaskSubmit(...) -
Python:
@app.on_dialog_open和@app.on_dialog_submit
对话内容可以是自适应卡片或基于 URL 的网页。
还可以通过其他方法调用对话框,具体取决于应用体系结构:
- 使用 TeamsJS 客户端库从选项卡。 请参阅 在选项卡中使用对话框。
- 从使用 Bot Framework 或深层链接的机器人。 请参阅 将对话框与机器人配合使用。
- 从深层链接 URL。 请参阅 深层链接以打开对话框。
有关从 Bot Framework 迁移到 Teams SDK 的指南,请参阅 从 BotBuilder 迁移。
下表总结了对话在 Teams SDK 中的工作方式:
| 步骤 | 具有自适应卡片的对话 | 包含网页 URL 的对话框 |
|---|---|---|
| 触发对话框 | 1. 向用户发送带有按钮的 TaskFetchAction 自适应卡片。 操作 value 的数据指定要打开的对话的类型。 2.当用户选择按钮时,Teams 会向应用发送任务提取调用。 |
1. 向用户发送带有按钮的 TaskFetchAction 自适应卡片。 2.当用户选择按钮时,Teams 会向应用发送任务提取调用。 |
| 处理对话框打开事件 | 3. 在对话打开处理程序中,返回一个任务模块继续响应,其中包含对话框元数据 (标题、维度和自适应卡片以显示) 。 在 C# 中,将 与 TaskInfo 包装一起使用 ContinueTask 。 在 TypeScript 中,使用 CardTaskModuleTaskInfo。 在 Python 中,在 中使用 CardTaskModuleTaskInfoTaskModuleContinueResponse。 |
3. 在对话打开处理程序中,返回一个任务模块继续响应,其中包含具有指向网页的属性的对话元数据 url 。 URL 域必须位于 validDomains 应用清单的 数组中。 在 C# 中,使用 TaskInfo。 在 TypeScript 中,使用 UrlTaskModuleTaskInfo。 在 Python 中,在 中使用 UrlTaskModuleTaskInfoTaskModuleContinueResponse。 |
| 处理对话框提交 | 4. 当用户按下 Action.Submit 某个按钮时,Teams 会向应用发送包含表单数据的任务提交调用。 5. 你可以通过以下方式做出响应: • 不执行任何操作 (完成任务) • 显示 (C#: 的消息: MessageTask,TypeScript/Python: TaskModuleMessageResponse) • 链接到另一个对话框 (C#: ContinueTask、TypeScript/Python: TaskModuleContinueResponse) |
4. 网页调用 Teams JS 客户端库以提交回数据。 Teams 使用结果向应用发送任务提交调用。 |
下一部分介绍定义对话框的内容和外观的对话元数据。
对话框元数据
对话元数据定义对话的内容和外观。 每种语言都使用自己的类型来表示此元数据:
-
C#:
TaskInfo从Microsoft.Teams.Api.TaskModules) ( -
TypeScript:
CardTaskModuleTaskInfo或UrlTaskModuleTaskInfo从@microsoft/teams.api) ( -
Python:
CardTaskModuleTaskInfo或UrlTaskModuleTaskInfo从microsoft_teams.api) (
下表列出了所有语言的通用属性:
| 属性 | 类型 | 说明 |
|---|---|---|
title |
string | 此属性显示在应用名称下方和应用图标右侧。 |
height |
number or string | 此属性可以是表示对话框高度(以像素为单位)的数字,或者 small、 medium或 large。 在 C# 中,使用 Union<int, Size>。 |
width |
number or string | 此属性可以是表示对话框宽度(以像素为单位)的数字,或者 small、 medium或 large。 在 C# 中,使用 Union<int, Size>。 |
url |
string | 在对话框中作为 <iframe> 加载的页面的 URL。 URL 的域必须位于应用清单中应用的 validDomains 数组 中。 在 UrlTaskModuleTaskInfo TypeScript/Python 中使用,或在 C# 中设置 Url 属性 TaskInfo 。 |
card |
Attachment | 要显示在对话框中的自适应卡片。 在 C# 中,使用 Attachment设置 Card 上的 TaskInfo 属性。 在 TypeScript 中,将 与 一起使用cardAttachment()CardTaskModuleTaskInfo。 在 Python 中,将 与 一起使用card_attachment(AdaptiveCardAttachment(...))CardTaskModuleTaskInfo。 |
注意
对话框功能要求要加载的任何 URL 的域包含在应用清单的 validDomains 数组中。
下一部分指定对话框大小调整,使用户能够设置对话框的高度和宽度。
对话框大小调整
和 height 的值width设置对话框的高度和宽度(以像素为单位)。 根据 Teams 窗口的大小和屏幕分辨率,这些值可能会按比例减少,同时保持纵横比。
如果 width 和 height 为 small、medium 或 large,则下图中红色矩形的大小是可用空间的比例,width 分别为 20%、50% 和 60%,height 分别为 20%、50% 和 66%:
下一部分提供了使用 Teams SDK 触发和处理对话的示例。
使用 TaskFetchAction 触发对话框
若要打开对话框,请发送带有按钮的 TaskFetchAction 自适应卡片。 当用户选择按钮时,Teams 会向应用发送任务提取调用。 每个按钮 value 的数据指定要打开 (对话框的类型, { "data": "AdaptiveCard" } 例如,) 。
using Microsoft.Teams.Api.Activities;
using Microsoft.Teams.Cards;
teamsApp.OnMessage(async (context) =>
{
var card = new AdaptiveCard
{
Body = new List<CardElement>
{
new TextBlock("Task Module Invocation from Adaptive Card")
{
Weight = TextWeight.Bolder,
Size = TextSize.Large
}
},
Actions = new List<Action>
{
new TaskFetchAction(new Dictionary<string, object?> { { "data", "AdaptiveCard" } })
{ Title = "Adaptive Card" },
new TaskFetchAction(new Dictionary<string, object?> { { "data", "CustomForm" } })
{ Title = "Custom Form" },
new TaskFetchAction(new Dictionary<string, object?> { { "data", "MultiStep" } })
{ Title = "Multi-step Form" }
}
};
await context.Send(new MessageActivity
{
Attachments = new List<Attachment>
{
new Attachment
{
ContentType = new ContentType("application/vnd.microsoft.card.adaptive"),
Content = card
}
}
});
});
处理对话框打开事件
当 Teams 发送任务提取调用时,你的应用将返回对话内容。 内容可以是自适应卡片或网页 URL。 在 C# 中,将对话框元数据包装在响应中 ContinueTask 。 在 TypeScript 中,返回 带有 TaskModuleResponse 的 type: 'continue'。 在 Python 中,返回 InvokeResponse 包含 的 TaskModuleContinueResponse。
using System.Text.Json;
using Microsoft.Teams.Api.TaskModules;
using Microsoft.Teams.Cards;
using Microsoft.Teams.Common;
teamsApp.OnTaskFetch(async (context) =>
{
var activity = context.Activity;
var json = JsonSerializer.Deserialize<JsonElement>(JsonSerializer.Serialize(activity));
var data = json.GetProperty("value").GetProperty("data").GetProperty("data").GetString();
TaskInfo taskInfo;
if (data == "CustomForm")
{
taskInfo = new TaskInfo
{
Title = "Custom Form",
Width = new Union<int, Size>(510),
Height = new Union<int, Size>(450),
Url = $"{botEndpoint}/customform",
FallbackUrl = $"{botEndpoint}/customform"
};
}
else if (data == "MultiStep")
{
var step1Card = new AdaptiveCard
{
Body = new List<CardElement>
{
new TextBlock("Step 1 of 2 - Your Name") { Size = TextSize.Large, Weight = TextWeight.Bolder },
new TextInput { Id = "name", Label = "Name", Placeholder = "Enter your name", IsRequired = true }
},
Actions = new List<Action>
{
new SubmitAction().WithTitle("Next").WithData(
new Union<string, SubmitActionData>(new SubmitActionData
{
NonSchemaProperties = new Dictionary<string, object?> { { "submissiontype", "multi_step_1" } }
}))
}
};
taskInfo = new TaskInfo
{
Title = "Multi-step Form",
Width = new Union<int, Size>(400),
Height = new Union<int, Size>(300),
Card = new Attachment
{
ContentType = new ContentType("application/vnd.microsoft.card.adaptive"),
Content = step1Card
}
};
}
else
{
var dialogCard = new AdaptiveCard
{
Body = new List<CardElement>
{
new TextBlock("Enter Text Here") { Weight = TextWeight.Bolder },
new TextInput { Id = "usertext", Placeholder = "add some text and submit", IsMultiline = true }
},
Actions = new List<Action> { new SubmitAction { Title = "Submit" } }
};
taskInfo = new TaskInfo
{
Title = "Adaptive Card: Inputs",
Width = new Union<int, Size>(400),
Height = new Union<int, Size>(200),
Card = new Attachment
{
ContentType = new ContentType("application/vnd.microsoft.card.adaptive"),
Content = dialogCard
}
};
}
return new Response(new ContinueTask(taskInfo));
});
处理对话框提交
当用户在对话框中按下 Action.Submit 时,Teams 会向应用发送任务提交调用。 可以通过完成任务、显示消息或打开另一个对话框(例如,将多步骤表单链接) ) (做出响应。
using System.Text.Json;
using Microsoft.Teams.Api.TaskModules;
using Microsoft.Teams.Cards;
using Microsoft.Teams.Common;
teamsApp.OnTaskSubmit(async (context) =>
{
var activity = context.Activity;
var json = JsonSerializer.Deserialize<JsonElement>(JsonSerializer.Serialize(activity));
var submitData = JsonSerializer.Deserialize<Dictionary<string, object>>(
json.GetProperty("value").GetProperty("data").GetRawText());
var submissionType = submitData?.GetValueOrDefault("submissiontype")?.ToString();
if (submissionType == "multi_step_1")
{
var name = submitData["name"]?.ToString();
var step2Card = new AdaptiveCard
{
Body = new List<CardElement>
{
new TextBlock("Step 2 of 2 - Your Email") { Size = TextSize.Large, Weight = TextWeight.Bolder },
new TextInput { Id = "email", Label = "Email", Placeholder = "Enter your email", IsRequired = true }
},
Actions = new List<Action>
{
new SubmitAction().WithTitle("Submit").WithData(
new Union<string, SubmitActionData>(new SubmitActionData
{
NonSchemaProperties = new Dictionary<string, object?>
{
{ "submissiontype", "multi_step_2" },
{ "name", name! }
}
}))
}
};
var taskInfo = new TaskInfo
{
Title = "Multi-step Form: Step 2",
Width = new Union<int, Size>(400),
Height = new Union<int, Size>(300),
Card = new Attachment
{
ContentType = new ContentType("application/vnd.microsoft.card.adaptive"),
Content = step2Card
}
};
return new Response(new ContinueTask(taskInfo));
}
if (submissionType == "multi_step_2")
{
await context.Send($"Hi {submitData["name"]}, thanks for submitting! Your email is {submitData["email"]}");
return new Response(new MessageTask("Multi-step form completed!"));
}
var usertext = submitData?.GetValueOrDefault("usertext")?.ToString();
await context.Send($"You submitted: {usertext}");
return new Response(new MessageTask("Thanks for submitting!"));
});
键盘和辅助功能指南
对于加载 HTML 内容的基于 URL 的对话,请确保键盘可访问性:
- 使用 HTML 标记中的 tabindex 属性 可以控制哪些元素可以聚焦,并使用 Tab 和 Shift-Tab 键定义顺序键盘导航。
- 在对话框页的 JavaScript 中适当处理 Esc 键。
Microsoft Teams 可确保键盘导航从对话框标题正确进入 HTML,反之亦然。
代码示例
| 示例名称 | Description | .NET | Node.js | Python |
|---|---|---|---|---|
| 机器人任务模块 | 此示例应用演示如何使用 Teams AI SDK (TeamsJS v1.x) 中称为任务模块的对话。 | View | View | View |