Адаптивная карусель карточек с ботами Microsoft Teams удаляет карточку

Я использую бота Microsoft team с 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;

person Moblize IT    schedule 19.12.2019    source источник
comment
Никогда не пробовал, но я думаю, вам нужно будет удалить значение щелчка из массива cardArr с помощью cardArr.filter или чего-то подобного. Вам также придется регенерировать карусель.   -  person billoverton    schedule 19.12.2019
comment
хм звучит так, как будто мне нужно будет вернуть всю полезную нагрузку карты, сделай то, что мне нужно, и отправь ее обратно с одной картой меньше   -  person Moblize IT    schedule 19.12.2019
comment
Я считаю, что могу помочь, но не могли бы вы исправить свой образец кода, пожалуйста? await next(); дублируется в вашем onMessage обработчике, у вас есть лишние или отсутствующие закрывающие скобки в некоторых местах, тело вашей карты имеет нуль, поскольку один из его элементов, а действия содержатся в теле и т. Д. Как мы можем исправить ваш код, если мы этого не сделаем знаете, есть ли эти проблемы в вашем реальном коде или это просто артефакты от копирования и вставки вашего кода? Убедитесь, что вы отформатировали код в редакторе, чтобы его было легко читать. (Так как в этой теме участвует несколько человек, вам нужно @ упомянуть меня, чтобы я увидел ваш ответ.)   -  person Kyle Delaney    schedule 19.12.2019
comment
@KyleDelaney, я повторно добавил код, исправив проблемы и упростив, насколько мог. пожалуйста, порекомендуйте   -  person Moblize IT    schedule 20.12.2019
comment
@MoblizeIT, вместо SendActivity () вы можете использовать UpdateActivity () с обновленной полезной нагрузкой карты.   -  person Subhasish    schedule 20.12.2019
comment
@ Subhasish-MSFT у вас есть пример по этому поводу? Я вижу, что updateActivity может помочь мне обновить передаваемые значения. но не визуальные элементы. например, в этом случае, если я хочу удалить одну карту из 10, я не понимаю, как   -  person Moblize IT    schedule 20.12.2019
comment
@MoblizeIT - Почему в теле вашей адаптивной карты пустая строка? Строки - это не элементы карты. Также ваш код все еще не отформатирован. Вы используете Visual Studio Code? stackoverflow.com/questions/29973357/   -  person Kyle Delaney    schedule 20.12.2019
comment
да, я использую код Visual Studio   -  person Moblize IT    schedule 21.12.2019
comment
@MoblizeIT - в VS Code вы можете использовать alt + shift + F для автоматического форматирования документа.   -  person Kyle Delaney    schedule 23.12.2019
comment
@MoblizeIT - Ты собираешься принять мой ответ?   -  person Kyle Delaney    schedule 27.12.2019


Ответы (1)


Как и в случае с этим другим ответом, ответ будет похож на этот. Я вижу, вы пытаетесь использовать TypeScript, но ваш код очень мало отличается от JavaScript, поэтому я просто напишу свой ответ на JavaScript.

Во-первых, вам понадобится способ сохранения состояния для вашей [карусели], чтобы вы могли обновить активность [карусели].

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
    };
}

Это похоже на ваш код, но есть некоторые важные отличия. Во-первых, я фильтрую массив items, чтобы учесть меньше элементов, поэтому вы в конечном итоге удалите карточки из своей карусели. Во-вторых, я включаю «идентификатор пакета» в данные каждого действия, с помощью которого ваш бот узнает, какое действие нужно обновить, когда он получит полезную нагрузку действия. Кроме того, это не имеет отношения к вашему вопросу, но я использую строковые константы вместо строковых литералов почти везде, где я ожидаю использовать эту строку более одного раза, и это практика, которой я следую, чтобы избежать ошибок, связанных с опечатками и т. Д.

Используя эту функцию, вы можете изначально отправить [карусель] следующим образом

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
    };
}

И вы можете обновить [карусель] в ответ на действие [qualify] отправки карты, как это

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;
    }
}
person Kyle Delaney    schedule 20.12.2019
comment
самая первая строка, которая сохраняет состояние карусели. где эта переменная определена? как он может хранить данные о нескольких взаимодействиях? Также по сути вы удаляете конкретную карту и повторно отправляете оставшиеся карты (карусель) с помощью updateActvity. Верный ? - person Moblize IT; 21.12.2019
comment
@MoblizeIT - первая строка не сохраняет состояние, она создает средство доступа к свойству состояния. Аксессоры свойств обычно создаются в конструкторе бота, что можно увидеть в таких примерах, как this и this. - person Kyle Delaney; 23.12.2019
comment
Чтобы понять, как состояние бота сохраняется между ходами, обратитесь к документации: docs.microsoft.com/en-us/azure/bot-service/. updateActivity не обязательно ничего удалять или повторно отправлять. Как следует из названия, он обновляет существующее действие. В вашем случае это изменение карусели, чтобы не включать конкретную карту. Функция SDK использует этот вызов REST API. Не забудьте принять этот ответ. - person Kyle Delaney; 23.12.2019
comment
Это, кстати, отличный пример того, почему шаблоны помогают. Использование шаблонов Adaptivecards сделает 95% вашего кода устаревшим и значительно упростит выявление проблем. - person Tim Cadenbach; 07.01.2020
comment
@TimCadenbach - Я написал ответ с использованием шаблонов на другой вопрос об обновлении адаптивных карт, и это все еще довольно сложный процесс. Можете ли вы объяснить, какой код вы считаете устаревшим с помощью шаблонов? - person Kyle Delaney; 07.01.2020
comment
вся функция CreateCarusel может быть выполнена с помощью шаблонов. По крайней мере, цикл for. В общем, с шаблонами вам не нужно создавать json самостоятельно. Это в значительной степени привязка к json. - person Tim Cadenbach; 07.01.2020
comment
@TimCadenbach - Что ж, если у вас есть решение для создания шаблонов, которое устранит 95% моего кода, я бы с удовольствием его увидел. Не стесняйтесь редактировать ответ. - person Kyle Delaney; 07.01.2020
comment
95% было немного выше: P однако взгляните на это: jsfiddle.net/vmgd2sup Это вернет именно то, что делает ваша функция create, однако он не использует никакого цикла, не создает никаких ненужных объектов, которые в любом случае только сериализуются и должны быть проще в использовании и обслуживании. Все, что вам нужно сделать, чтобы удалить карту, это отредактировать ваш массив с меньшим количеством элементов, и он будет производить меньше карт. Это дает дополнительное преимущество: если вы когда-нибудь захотите сменить карту, вам не нужно менять какой-либо код, просто обновите карту. Если вы храните карту отдельно, вам даже не нужно ничего перекомпилировать ... - person Tim Cadenbach; 08.01.2020
comment
Просто нужно добавить, что во многих случаях создание шаблонов намного лучше, чем обычное создание карточек ... кто-нибудь действительно должен прекратить предлагать создавать карточки вручную. Карты, созданные в вашем коде, не могут быть изменены без новой версии, должны поддерживаться вашим кодом и т. Д. И т. Д. С шаблоном ваши карты могут храниться где угодно. :) - person Tim Cadenbach; 08.01.2020
comment
@TimCadenbach - код, с которым вы связались, не будет создавать карусель из 5 карточек, он создаст одну карточку с 5 текстовыми блоками и 5 кнопками. - person Kyle Delaney; 08.01.2020
comment
Не могу легко опубликовать это здесь, но если вы запустите jsfiddle и посмотрите на вывод консоли, вы увидите сообщение с 5 вложениями, каждое из которых представляет собой отдельную карту. - person Tim Cadenbach; 11.01.2020
comment
Вы должны понять, как работает шаблон, чтобы увидеть это. Параметр $ data в начале карточки по существу повторяет полную карточку для каждого элемента в массиве. Точнее, $ data повторяет все на том же уровне иерархии, на котором находится. В корне он повторяет полную карту, внутри кнопки он повторяет только кнопку и т. Д. И т. Д. - person Tim Cadenbach; 11.01.2020
comment
@TimCadenbach - О, это неплохо, но мне нужно сделать одно исправление. Ваш Activity.attachments должен быть массивом объектов Attachment, а не массивом объектов карты. Я полагаю, что Array.map здесь поможет. - person Kyle Delaney; 11.01.2020
comment
@TimCadenbach - На самом деле map не нужен. Я просто переместил $ data на уровень выше, как вы сказали, и смог сгенерировать массив из Attachment объектов, просто используя template.expand. - person Kyle Delaney; 11.01.2020
comment
Ага, рад, что это сработало. Почувствуйте, ребята из карт не очень хороши, чтобы объяснить, насколько это мощно :) - person Tim Cadenbach; 11.01.2020
comment
извините за то, что на это ушла целая вечность. когда я жду context.updateActivity (myCardCarousal), он выдает ошибку, отсутствующую await context.updateActivity (), пожалуйста, посоветуйте - person Moblize IT; 04.02.2020
comment
@MoblizeIT - Если вы примете этот ответ и зададите новый вопрос, который объясняет вашу новую проблему, я смогу вам помочь. - person Kyle Delaney; 04.02.2020
comment
@KyleDelaney опубликовал stackoverflow.com/questions/60063335/ - person Moblize IT; 04.02.2020