Node.js Microsoft团队机器人自适应卡转盘删除卡

Node.js Microsoft团队机器人自适应卡转盘删除卡,node.js,typescript,botframework,microsoft-teams,adaptive-cards,Node.js,Typescript,Botframework,Microsoft Teams,Adaptive Cards,我正在使用带有nodejs的微软团队机器人。我正在渲染自适应卡的旋转木马,每张卡上都有操作。我的要求是删除单击该操作的单个卡片。可能吗 当前代码如下所示。我已尝试删除Active,但这会删除整个旋转木马 const { TurnContext, TeamsActivityHandler, CardFactory, AttachmentLayoutTypes, ActionTypes } = require('botbuilder'); class Tea

我正在使用带有nodejs的微软团队机器人。我正在渲染自适应卡的旋转木马,每张卡上都有操作。我的要求是删除单击该操作的单个卡片。可能吗

当前代码如下所示。我已尝试删除Active,但这会删除整个旋转木马

const {
    TurnContext,
    TeamsActivityHandler,
    CardFactory,
    AttachmentLayoutTypes,
    ActionTypes
} = require('botbuilder');

class TeamsConversationBot extends TeamsActivityHandler {
    constructor() {
        super();
        this.onMessage(async (context:any, next:any) => {
            TurnContext.removeRecipientMention(context.activity);
            console.log("context activigty at the begin is:" + JSON.stringify(context.activity))
            let msg = context.activity.text
            let action = context.activity.value

            if(msg.startsWith('lead')){
                msg = 'lead'
            }

            if(action !== undefined){
                console.log("user did some action on a card")
                msg = action.action
            }

            switch (msg) {
                case 'lead':
                        await this.lead(context)
                        break;
                case 'qualify_lead':
                        await this.qualifyLead(context)
                        break;
            }
            await next();
        });
    }


    /**
     * 
     * @param context this method does a lead qualification
     */
    async qualifyLead(context:any){
        console.log("in qualifyLead:" + JSON.stringify(context.activity))
        //await context.deleteActivity(context.activity.replyToId)

        const leadId = context.activity.value.objectId
        console.log("Lead to qualify is:" + leadId)


        await context.sendActivity('Lead is qualified')
    }


/**
    * Search contact by name
    * @param context
    * @param keyword 
*/ 
async lead(context:any){
    console.log("Start of lead with context:" + JSON.stringify(context))
    const cardArr = []
    let items = [
        {"Name": 'x', "LeadId": "1"},
        {"Name": 'a', "LeadId": "2"},
        {"Name": 'b', "LeadId": "3"},
        {"Name": 'c', "LeadId": "4"},
        {"Name": 'd', "LeadId": "5"}
    ]

     for(const item of items){
        const header =  {
            "type": "TextBlock",
            "size": "Medium",
            "weight": "Bolder",
            "text": item.Name
        }



    const actions = [
        {
            "type": "Action.Submit",
            "title": "Qualify",
            "data": { "action" : "qualify_lead", "objectId" : item.LeadId }
        }
       ]


   const acard = CardFactory.adaptiveCard(
    {
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "type": "AdaptiveCard",
        "version": "1.0",
        "body": [
            header,
            ''
            ],
           "actions": actions
         }
     )

    cardArr.push(acard)
    console.log("payload is::::" + JSON.stringify(acard))
        }

    const reply = {
        "attachments" : cardArr,
        "attachmentLayout" : AttachmentLayoutTypes.Carousel
    }

    await context.sendActivity(reply);
}

}

module.exports.TeamsConversationBot = TeamsConversationBot;
与之一样,答案将类似于。我可以看到您正在尝试使用TypeScript,但您的代码与JavaScript的差异非常小,所以我将用JavaScript编写我的答案

首先,您需要一种保存[carousel]状态的方法,以便更新[carousel]的活动

您需要一种一致的方式来生成[carousel],以便在最初发送[carousel]和更新[carousel]时使用

这与您的代码类似,但有一些重要的区别。首先,我过滤items数组以允许更少的项目,这就是最终从旋转木马中删除卡片的方式。其次,我在每个动作的数据中都包含一个“批处理ID”,这是您的机器人在收到动作的有效负载时知道要更新哪个活动的方式。此外,这与您的问题无关,但我在任何地方都使用字符串常量而不是字符串文本,我希望不止一次使用该字符串,这是我为避免与打字错误相关的错误等而遵循的实践

使用此功能,您可以按如下方式发送[转盘]

您可以更新[carousel]以响应卡的[Qualified]提交操作,如下所示


从未尝试过此操作,但我认为您需要使用cardArr.filter或类似工具从cardArr数组中删除单击的值。你也必须重新生成旋转木马。嗯,听起来我需要将整个卡的有效载荷传递回去,做我需要做的事情,然后用更少的卡将其发送回去。我相信我可以帮助你,但是你能修复你的代码样本吗<代码>等待下一步()在你的
onMessage
处理程序中重复,你在某些地方有额外的或缺少的结束括号,你的卡的主体有空作为其元素之一,“操作”包含在主体中,等等。如果我们不知道这些问题是在您的实际代码中,还是仅仅是复制和粘贴代码的工件,我们如何修复您的代码?确保在编辑器中格式化代码,以便易于阅读。(因为这个帖子上有很多人,所以你需要@提到我,我会看到你的回复。)@KyleDelaney我已经通过修复问题和尽可能简化重新添加了代码。请advise@MoblizeIT-在VS代码中,您可以使用alt+shift+F自动格式化文档,即保存转盘状态的第一行。这个变量是在哪里定义的?它如何能够跨多个交互保存数据?实际上,您正在删除特定的卡,并使用UpdateActCity重新发送剩余的卡(旋转木马)。对吗?@moblizet-第一行不是保存状态,而是创建一个。属性访问器通常在bot的构造函数中创建,如和等示例中所示。要了解bot状态在两个回合之间是如何持久化的,请参阅文档:
updateActivity
不必“删除”或“重新发送”任何内容。顾名思义,它正在更新现有的活动。在您的情况下,它正在修改转盘,使其不包含特定的卡。SDK函数使用。记住接受这个答案。顺便说一句,这是一个很好的例子,说明了为什么模板有帮助。使用Adaptivecards模板将使95%的代码过时,并且更容易发现issues@TimCadenbach-我写了一个答案,涉及到另一个关于更新自适应卡的问题,这仍然是一个相当复杂的过程。你能解释一下你认为模板会过时的代码吗?
this.carouselState = this.conversationState.createProperty('carouselState');
createCarousel(batchId, leads)
{
    const cardArr = [];

    let items = [
        { "Name": 'x', "LeadId": 1 },
        { "Name": 'a', "LeadId": 2 },
        { "Name": 'b', "LeadId": 3 },
        { "Name": 'c', "LeadId": 4 },
        { "Name": 'd', "LeadId": 5 }
    ];

    items = items.filter(item => leads.includes(item.LeadId));

    for (const item of items) {
        const header = {
            "type": "TextBlock",
            "size": "Medium",
            "weight": "Bolder",
            "text": item.Name
        };

        const actions = [
            {
                "type": "Action.Submit",
                "title": "Qualify",
                "data": { [KEYACTION]: ACTIONQUALIFYLEAD, [KEYOBJECTID]: item.LeadId, [KEYBATCHID]: batchId }
            }
        ];

        const acard = CardFactory.adaptiveCard(
            {
                "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                "type": "AdaptiveCard",
                "version": "1.0",
                "body": [
                    header
                ],
                "actions": actions
            }
        );

        cardArr.push(acard);
    }

    return {
        "type": "message",
        "attachments": cardArr,
        "attachmentLayout": AttachmentLayoutTypes.Carousel
    };
}
async testCarousel(turnContext) {
    const batchId = Date.now();
    const leads = [1, 2, 3, 4, 5];
    const reply = this.createCarousel(batchId, leads);
    const response = await turnContext.sendActivity(reply);
    const dict = await this.carouselState.get(turnContext, {});

    dict[batchId] = {
        [KEYACTIVITYID]: response.id,
        [KEYLEADS]: leads
    };
}
async handleSubmitAction(turnContext) {
    const value = turnContext.activity.value;

    switch (value[KEYACTION]) {
        case ACTIONQUALIFYLEAD:
            const dict = await this.carouselState.get(turnContext, {});
            const batchId = value[KEYBATCHID];
            const info = dict[batchId];
            if (info) {
                const leads = info[KEYLEADS];
                const objectId = value[KEYOBJECTID];
                var index = leads.indexOf(objectId);
                if (index !== -1) leads.splice(index, 1);
                const update = this.createCarousel(batchId, leads);
                update.id = info[KEYACTIVITYID];
                if (update.attachments.length) {
                    await turnContext.updateActivity(update);
                } else {
                    await turnContext.deleteActivity(update.id);
                }
            }
            break;
    }
}