В этом руководстве описывается, как приложения Google Chat могут собирать и обрабатывать информацию от пользователей, создавая формы ввода в интерфейсах на основе карточек.


Приложения чата запрашивают у пользователей информацию для выполнения действий в чате или за его пределами, в том числе следующими способами:
- Настройте параметры. Например, чтобы разрешить пользователям настраивать параметры уведомлений или настроить и добавить приложение Chat в одно или несколько чат-пространств.
 - Создавайте или обновляйте информацию в других приложениях Google Workspace. Например, разрешите пользователям создавать события в Google Календаре.
 - Предоставьте пользователям доступ к ресурсам в других приложениях или веб-сервисах и возможность их обновления. Например, приложение чата может помочь пользователям обновлять статус обращения в службу поддержки непосредственно из чата.
 
Предпосылки
HTTP
Надстройка для Google Workspace, расширяющая возможности Google Chat. Чтобы создать её, выполните краткое руководство по HTTP .
Скрипт приложений
Надстройка для Google Workspace, расширяющая возможности Google Chat. Чтобы создать её, выполните краткое руководство по Apps Script .
Создавайте формы с использованием карточек
Для сбора информации чат-приложения разрабатывают формы и их поля ввода, а также встраивают их в карточки. Для отображения карточек пользователям чат-приложения могут использовать следующие чат-интерфейсы:
- Сообщения чата, содержащие одну или несколько карточек.
 - Диалоги — карточки, которые открываются в новом окне из сообщений и домашних страниц.
 
Чат-приложения могут создавать карточки с использованием следующих виджетов:
Виджеты ввода форм, запрашивающие информацию у пользователей. При желании вы можете добавить проверку в виджеты ввода форм, чтобы гарантировать, что пользователи правильно вводят и форматируют информацию. Приложения чата могут использовать следующие виджеты ввода форм:
-  Текстовые поля ( 
textInput) для ввода текста в свободной форме или предлагаемого текста. Элементы ввода выбора (
selectionInput) — это выбираемые элементы пользовательского интерфейса, такие как флажки, переключатели и раскрывающиеся меню. Виджеты ввода выбора также могут заполнять и предлагать элементы из данных Google Workspace (например, из чат-группы) или динамического источника данных. Подробнее см. в следующем разделе Добавление меню множественного выбора .Выбор даты и времени (
dateTimePicker) для ввода даты и времени.
-  Текстовые поля ( 
 Виджет кнопки , позволяющий пользователям отправлять значения, введённые ими в карточку. После нажатия кнопки приложение чата обрабатывает полученную информацию .
В следующем примере карточка собирает контактную информацию с помощью текстового ввода, выбора даты и времени и выбора:
Дополнительные примеры интерактивных виджетов, которые можно использовать для сбора информации, см. в разделе Создание интерактивной карточки или диалога в документации API Google Chat.
Добавить меню множественного выбора
 Чтобы настроить элементы выбора или предоставить пользователям возможность выбирать элементы из динамического источника данных, приложения Chat могут использовать меню с множественным выбором, которые представляют собой виджет SelectionInput . Например, на следующей карточке показано меню с множественным выбором, в котором пользователи могут динамически выбирать элементы из списка контактов: 
Вы можете заполнить пункты меню множественного выбора из следующих источников данных:
- Данные Google Workspace , включая пользователей или чат-группы, участником которых является пользователь. Меню заполняет только элементы из той же организации Google Workspace.
 - Внешние источники данных , такие как реляционная база данных. Например, вы можете использовать меню с множественным выбором, чтобы помочь пользователю выбрать из списка потенциальных клиентов в системе управления взаимоотношениями с клиентами (CRM).
 
Заполнение элементов из источника данных Google Workspace
 Чтобы использовать источники данных Google Workspace, укажите поле platformDataSource в виджете SelectionInput . В отличие от других типов полей выбора, объекты SelectionItem не используются, поскольку эти элементы выбора динамически извлекаются из Google Workspace.
 Следующий код демонстрирует меню с несколькими пользователями Google Workspace. Для заполнения списка пользователей входной параметр выбора устанавливает commonDataSource в USER : 
JSON
{
  "selectionInput": {
    "name": "contacts",
    "type": "MULTI_SELECT",
    "label": "Selected contacts",
    "multiSelectMaxSelectedItems": 5,
    "multiSelectMinQueryLength": 1,
    "platformDataSource": {
      "commonDataSource": "USER"
    }
  }
}
 Следующий код демонстрирует меню с множественным выбором чат-пространств. Для заполнения пространств в поле выбора указывается поле hostAppDataSource . Меню с множественным выбором также устанавливает defaultToCurrentSpace в true , что делает текущее пространство выбором по умолчанию в меню: 
JSON
{
  "selectionInput": {
    "name": "spaces",
    "type": "MULTI_SELECT",
    "label": "Selected contacts",
    "multiSelectMaxSelectedItems": 3,
    "multiSelectMinQueryLength": 1,
    "platformDataSource": {
      "hostAppDataSource": {
        "chatDataSource": {
          "spaceDataSource": {
            "defaultToCurrentSpace": true
          }
        }
      }
    }
  }
}
Заполнение элементов из внешнего источника данных
 Меню с множественным выбором также могут заполнять элементы из стороннего или внешнего источника данных. Чтобы использовать внешний источник данных, укажите поле externalDataSource в виджете SelectionInput , содержащем функцию, которая запрашивает и возвращает элементы из источника данных.
 Чтобы сократить количество запросов к внешнему источнику данных, можно включить предлагаемые элементы, которые будут отображаться в меню с множественным выбором до того, как пользователь введёт данные. Например, можно заполнить список недавно найденных контактов. Для заполнения предлагаемых элементов из внешнего источника данных укажите статические объекты SelectionItem .
В следующем коде показано меню с множественным выбором, которое запрашивает и заполняет элементы из внешнего источника данных:
JSON
{
  "selectionInput": {
    "name": "contacts",
    "type": "MULTI_SELECT",
    "label": "Selected contacts",
    "multiSelectMaxSelectedItems": 3,
    "multiSelectMinQueryLength": 1,
    "externalDataSource": { "function": "FUNCTION" },
    // Suggested items loaded by default.
    // The list is static here but it could be dynamic.
    "items": [FUNCTION]
  }
}
 Замените FUNCTION на URL-адрес HTTP или имя функции Apps Script, которая запрашивает внешнюю базу данных. Полный пример, демонстрирующий, как возвращать предлагаемые элементы, см. в разделе «Предложение элементов с множественным выбором» .
Получайте данные из интерактивных виджетов
 При каждом нажатии кнопки активируется действие приложения Chat с информацией о взаимодействии. В объекте commonEventObject полезной нагрузки события объект formInputs содержит все значения, введённые пользователем.
 Значения можно получить из объекта commonEventObject.formInputs. WIDGET_NAME , где WIDGET_NAME — это поле name , указанное для виджета. Значения возвращаются в виде определённого типа данных для виджета.
Ниже показана часть объекта события, где пользователь ввел значения для каждого виджета:
{
  "commonEventObject": { "formInputs": {
    "contactName": { "stringInputs": {
      "value": ["Kai 0"]
    }},
    "contactBirthdate": { "dateInput": {
      "msSinceEpoch": 1000425600000
    }},
    "contactType": { "stringInputs": {
      "value": ["Personal"]
    }}
  }}
}
Для получения данных ваше приложение Chat обрабатывает объект события, чтобы получить значения, вводимые пользователями в виджеты. В следующей таблице показано, как получить значение для виджета ввода формы. Для каждого виджета в таблице указан тип данных, который принимает виджет, место хранения значения в объекте события и пример значения.
| Виджет ввода формы | Тип входных данных | Входное значение из объекта события | Пример значения | 
|---|---|---|---|
 textInput |  stringInputs |  event.commonEventObject.formInputs.contactName.stringInputs.value[0] |  Kai O | 
 selectionInput |  stringInputs |  Чтобы получить первое или единственное значение, event.commonEventObject.formInputs.contactType.stringInputs.value[0] |  Personal | 
 dateTimePicker , который принимает только даты. |  dateInput |  event.commonEventObject.formInputs.contactBirthdate.dateInput.msSinceEpoch . |  1000425600000 | 
После того как приложение Chat получит данные, оно может выполнить любое из следующих действий:
- Для карточек, содержащих меню с множественным выбором, заполняйте или предлагайте пункты на основе того, что пользователь вводит в меню.
 - Перенесите данные на другую карту, чтобы пользователь мог просмотреть свою информацию или перейти к следующему разделу формы.
 - Ответьте пользователю , чтобы подтвердить, что пользователь успешно заполнил форму.
 
Предложить множественный выбор элементов
 Если карточка содержит меню с множественным выбором, которое заполняет элементы из внешнего источника данных , приложение Chat может возвращать предлагаемые элементы на основе того, что пользователь вводит в меню. Например, если пользователь начинает вводить Atl для меню, в котором представлены города США, приложение Chat может автоматически предложить Atlanta до того, как пользователь закончит вводить данные. Приложение Chat может предложить до 100 элементов.
 Для предложения и динамического заполнения пунктов в меню с множественным выбором виджет SelectionInput на карточке должен указывать функцию, которая запрашивает внешний источник данных . Для возврата предлагаемых пунктов функция должна выполнять следующие действия:
- Обрабатывайте объект события , который приложение чата получает, когда пользователи вводят текст в меню.
 -  Из объекта события получите значение, которое вводит пользователь, представленное в поле 
event.commonEventObject.parameters["autocomplete_widget_query"]. -  Запросите источник данных, используя введенное пользователем значение, чтобы получить один или несколько 
SelectionItemsдля предложения пользователю. -  Возвращайте предложенные элементы, возвращая действие 
RenderActionsс объектомmodifyCard. 
 В следующем примере кода показано, как приложение Chat динамически предлагает пункты в меню с множественным выбором на карточке. Когда пользователь вводит данные в меню, функция или конечная точка, указанная в поле externalDataSource виджета, запрашивает внешний источник данных и предлагает пункты, которые пользователь может выбрать. 
Node.js
/**
 * Google Cloud Function that responds to events sent from a
 * Google Chat space.
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.selectionInput = function selectionInput(req, res) {
  if (req.method === 'GET' || !req.body.chat) {
    return res.send('Hello! This function is meant to be used ' +
        'in a Google Chat Space.');
  }
  // Stores the Google Chat event
  const chatEvent = req.body.chat;
  // Handle user interaction with multiselect.
  if(chatEvent.widgetUpdatedPayload) {
    return res.send(queryContacts(req.body));
  }
  // Replies with a card that contains the multiselect menu.
  return res.send({ hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    cardsV2: [{
      cardId: "contactSelector",
      card: { sections:[{ widgets: [{
        selectionInput: {
          name: "contacts",
          type: "MULTI_SELECT",
          label: "Selected contacts",
          multiSelectMaxSelectedItems: 3,
          multiSelectMinQueryLength: 1,
          externalDataSource: { function: "FUNCTION_URL" },
          // Suggested items loaded by default.
          // The list is static here but it could be dynamic.
          items: [getSuggestedContact("3")]
        }
      }]}]}
    }]
  }}}}});
};
/**
* Get contact suggestions based on text typed by users.
*
* @param {Object} event the event object that contains the user's query
* @return {Object} suggestions
*/
function queryContacts(event) {
  const query = event.commonEventObject.parameters["autocomplete_widget_query"];
  return { action: { modifyOperations: [{ updateWidget: { selectionInputWidgetSuggestions: { suggestions: [
    // The list is static here but it could be dynamic.
    getSuggestedContact("1"), getSuggestedContact("2"), getSuggestedContact("3"), getSuggestedContact("4"), getSuggestedContact("5")
  // Only return items based on the query from the user.
  ].filter(e => !query || e.text.includes(query)) }}}]}};
}
/**
 * Generate a suggested contact given an ID.
 *
 * @param {String} id The ID of the contact to return.
 * @return {Object} The contact formatted as a selection item in the menu.
 */
function getSuggestedContact(id) {
  return {
    value: id,
    startIconUri: "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    text: "Contact " + id
  };
}
 Замените FUNCTION_URL на конечную точку HTTP, которая запрашивает внешний источник данных.
Скрипт приложений
/**
* Responds to a Message trigger in Google Chat.
*
* @param {Object} event the event object from Google Chat
* @return {Object} Response from the Chat app.
*/
function onMessage(event) {
  // Replies with a card that contains the multiselect menu.
  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    cardsV2: [{
      cardId: "contactSelector",
      card: { sections:[{ widgets: [{
        selectionInput: {
          name: "contacts",
          type: "MULTI_SELECT",
          label: "Selected contacts",
          multiSelectMaxSelectedItems: 3,
          multiSelectMinQueryLength: 1,
          externalDataSource: { function: "queryContacts" },
          // Suggested items loaded by default.
          // The list is static here but it could be dynamic.
          items: [getSuggestedContact("3")]
        }
      }]}]}
    }]
  }}}}};
}
/**
* Get contact suggestions based on text typed by users.
*
* @param {Object} event the event object that contains the user's query
* @return {Object} suggestions
*/
function queryContacts(event) {
  const query = event.commonEventObject.parameters["autocomplete_widget_query"];
  return { action: { modifyOperations: [{ updateWidget: { selectionInputWidgetSuggestions: { suggestions: [
    // The list is static here but it could be dynamic.
    getSuggestedContact("1"), getSuggestedContact("2"), getSuggestedContact("3"), getSuggestedContact("4"), getSuggestedContact("5")
  // Only return items based on the query from the user.
  ].filter(e => !query || e.text.includes(query)) }}}]}};
}
/**
* Generate a suggested contact given an ID.
*
* @param {String} id The ID of the contact to return.
* @return {Object} The contact formatted as a selection item in the menu.
*/
function getSuggestedContact(id) {
  return {
    value: id,
    startIconUri: "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    text: "Contact " + id
  };
}
Перенос данных на другую карту
После того, как пользователь отправит информацию с карты, вам может потребоваться вернуть дополнительные карты, чтобы выполнить любое из следующих действий:
- Помогите пользователям заполнять более длинные формы, создав отдельные разделы.
 - Позвольте пользователям предварительно просмотреть и подтвердить информацию из исходной карточки, чтобы они могли проверить свои ответы перед отправкой.
 - Динамически заполняйте оставшиеся разделы формы. Например, чтобы предложить пользователям записаться на приём, приложение Chat может отображать начальную карточку с запросом причины приёма, а затем заполнять другую карточку с доступным временем в зависимости от типа приёма.
 
 Чтобы перенести входные данные из исходной карты, можно создать виджет button с actionParameters , содержащими name виджета и значение, вводимое пользователем, как показано в следующем примере: 
Node.js
{
  "buttonList": { "buttons": [{
    "text": "Submit",
    "onClick": { "action": {
      "function": "FUNCTION_URL", // Must be an `https` endpoint.
      "parameters": [
        {
          "key": "WIDGET_NAME",
          "value": "USER_INPUT_VALUE"
        },
        // Can specify multiple parameters
      ]
    }}
  }]}
}
Скрипт приложений
{
  "buttonList": { "buttons": [{
    "text": "Submit",
    "onClick": { "action": {
      "function": "submitForm",
      "parameters": [
        {
          "key": "WIDGET_NAME",
          "value": "USER_INPUT_VALUE"
        },
        // Can specify multiple parameters
      ]
    }}
  }]}
}
 Где WIDGET_NAME — name виджета, а USER_INPUT_VALUE — вводимые пользователем данные. Например, для текстового поля, которое собирает имя человека, имя виджета — contactName , а пример значения — Kai O
Когда пользователь нажимает кнопку, ваше приложение чата получает объект события, из которого вы можете получить данные .
Ответить на отправку формы
Получив данные из сообщения или диалога с картой, приложение Chat отвечает подтверждением получения или возвращает ошибку.
В следующем примере приложение чата отправляет текстовое сообщение, чтобы подтвердить, что оно успешно получило форму, отправленную из сообщения карты.
Node.js
/**
 * Google Cloud Function that handles all Google Workspace Add On events for
 * the contact manager app.
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.contactManager = function contactManager(req, res) {
  const chatEvent = req.body.chat;
  const chatMessage = chatEvent.messagePayload.message;
  // Handle message payloads in the event object
  if(chatEvent.messagePayload) {
    return res.send(handleMessage(chatMessage, chatEvent.user));
  // Handle button clicks on the card
  } else if(chatEvent.buttonClickedPayload) {
    switch(req.body.commonEventObject.parameters.actionName) {
        case "openDialog":
            return res.send(openDialog());
        case "openNextCard":
            return res.send(openNextCard(req.body));
        case "submitForm":
            return res.send(submitForm(req.body));
    }
  }
};
/**
 * Submits information from a dialog or card message.
 *
 * @param {Object} event the interactive event with form inputs.
 * @return {Object} a message response that posts a private message.
 */
function submitForm(event) {
  const chatUser = event.chat.user;
  const contactName = event.commonEventObject.parameters["contactName"];
  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    privateMessageViewer: chatUser,
    text: "✅ " + contactName + " has been added to your contacts."
  }}}}};
}
Скрипт приложений
/**
 * Sends private text message that confirms submission.
 *
 * @param {Object} event the interactive event with form inputs.
 * @return {Object} a message response that posts a private message.
 */
function submitForm(event) {
  const chatUser = event.chat.user;
  const contactName = event.commonEventObject.parameters["contactName"];
  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    privateMessageViewer: chatUser,
    text: "✅ " + contactName + " has been added to your contacts."
  }}}}};
}
 Для обработки и закрытия диалогового окна необходимо вернуть объект RenderActions , который определяет, хотите ли вы отправить сообщение с подтверждением, обновить исходное сообщение или карточку или просто закрыть диалоговое окно. Инструкции см. в разделе «Закрытие диалогового окна» .
Устранение неполадок
Когда приложение или карточка Google Chat возвращает ошибку, в интерфейсе Chat отображается сообщение «Что-то пошло не так» или «Не удалось обработать ваш запрос». Иногда в интерфейсе Chat не отображается сообщение об ошибке, но приложение или карточка Chat выдаёт неожиданный результат; например, сообщение может не появиться.
Хотя сообщение об ошибке может не отображаться в пользовательском интерфейсе чата, при включенном ведении журнала ошибок для приложений чата доступны описательные сообщения об ошибках и данные журнала, которые помогут вам исправить ошибки. Сведения о просмотре, отладке и исправлении ошибок см. в статье «Устранение неполадок и исправление ошибок Google Chat» .