Teams Bot App 用户互动
上一篇文章我们解析了 teams bot 的主体代码逻辑,深入的了解它是怎么运作起来的。我们这篇文章来详细讲一下 adaptive card 在 Teams 里的互动,我们用上一个 app 里的 learn 卡片为例。
我们先运行我们的 Hello World Bot,然后给bot发送 learn 文字后,会等到一个回复的卡片,卡片上的 Like Count 是 0,我们点击一下 “I Like This!” 按钮。
稍等 1,2 秒后,我们就可以看到这个卡片的刷新了,Like Count 变成了 1。
再多点击几次后,数字会一直增加。
这实际上就让 bot 和用户之间有了一种互动,用户可以通过 adaptive card 上的按钮和 bot 进行沟通。
我们来看一下这是怎么做到的。先打开 learn.json
文件,看看这个卡片有什么特别的地方。
可以看到,在卡片的json文件中,那个数字是一个 placeholder ${likeCount}
,我们后面会讲它是怎么和代码联动的。对于 “I Like This!” 按钮,它的 type 是 Action.Execute
,verb 是 userlike
,fallback 是 Action.Submit
,看到这里我们可以隐隐约约感觉到它像是给 bot 发了一个指令,让bot 去 execute 一个叫 userlike的指令。
{
"type": "Action.Execute",
"title": "I Like This!",
"verb": "userlike",
"fallback": "Action.Submit"
}
我们再来看一下 teamsBot.ts
里的代码,看看它是如何和 adaptive card 联动的。由于这个文件比较长,我挑了和这个操作相关的代码,让大家看得更加清楚简单一些。
import rawLearnCard from "./adaptiveCards/learn.json";
export interface DataInterface {
likeCount: number;
}
export class TeamsBot extends TeamsActivityHandler {
// record the likeCount
likeCountObj: { likeCount: number };
constructor() {
super();
this.likeCountObj = { likeCount: 0 };
this.onMessage(async (context, next) => {
let txt = context.activity.text;
switch (txt) {
case "learn": {
this.likeCountObj.likeCount = 0;
const card = AdaptiveCards.declare<DataInterface>(rawLearnCard).render(this.likeCountObj);
await context.sendActivity({ attachments: [CardFactory.adaptiveCard(card)] });
break;
}
}
});
}
async onAdaptiveCardInvoke(
context: TurnContext,
invokeValue: AdaptiveCardInvokeValue
): Promise<AdaptiveCardInvokeResponse> {
// The verb "userlike" is sent from the Adaptive Card defined in adaptiveCards/learn.json
if (invokeValue.action.verb === "userlike") {
this.likeCountObj.likeCount++;
const card = AdaptiveCards.declare<DataInterface>(rawLearnCard).render(this.likeCountObj);
await context.updateActivity({
type: "message",
id: context.activity.replyToId,
attachments: [CardFactory.adaptiveCard(card)],
});
return { statusCode: 200, type: undefined, value: undefined };
}
}
}
首先代码里先申明了一个 interface DataInterface
,这个主要是为了填充 adaptive card 里的那个placeholder ${likeCount}
所使用。
在 class TeamsBot
里先弄了一个 likeCountObj: { likeCount: number }
,likeCountObject
实际上是一个 interface DataInterface
的实例,它记录了一共被 like 了几次,我觉得这句改成 likeCountObj: DataInterface;
更加清楚,所以我 raise 了一个 pr 给微软产品组 https://github.com/OfficeDev/TeamsFx-Samples/pull/491,看看能不能 merge 成功。
在 TeamsBot
的构造函数中,当用户发送了 learn
文字后,新建了一个 card,并且把当前的 like count 值填入到 card 中。由于 DataInterface 里的 likeCount 的名字和 json 里的placeholder 的名字 ${likeCount}
一致,所以这个 placeholder 就被赋值了 0。
const card = AdaptiveCards.declare<DataInterface>(rawLearnCard).render(this.likeCountObj);
然后就把卡片加到 activity 里,发送给用户。
await context.sendActivity({ attachments: [CardFactory.adaptiveCard(card)] });
当用户点击的 “I Like This!” 按钮后,onAdaptiveCardInvoke()
函数被触发,可以从代码清楚的看到,如果 verb
是 userlike
,就把like计数器加一,然后通过 context.updateActivity()
来更新这个卡片。
看到这里我想大家已经清楚的明白了前后的逻辑和他们关联的方式。那我们就模仿这个来扩展一下,我们打开 learn.json
,在 “I Like This!” 后增加另一个按钮 “Reset Like Count”
{
"type": "Action.Execute",
"title": "Reset Like Count",
"verb": "resetlike",
"fallback": "Action.Submit"
},
然后在 teamsBot.ts 文件里刚才处理 userlike 的后面再加上一段:
if (invokeValue.action.verb === "userlike") {
...
}
else if (invokeValue.action.verb === "resetlike") {
this.likeCountObj.likeCount == 0;
const card = AdaptiveCards.declare<DataInterface>(rawLearnCard).render(this.likeCountObj);
await context.updateActivity({
type: "message",
id: context.activity.replyToId,
attachments: [CardFactory.adaptiveCard(card)],
});
return { statusCode: 200, type: undefined, value: undefined };
}
运行程序后,就能看到多了一个按钮,点击 “Reset Like Count” 按钮后,就能够重置 like 计数器。
所以 teams bot 并不是一个非常难的东西,通过我们对代码一步步的解析,然后做一些简单修改,希望各位读者大致明白了 bot 运行的机理。