收集和处理 Google Chat 用户的信息

本指南介绍了 Google Chat 应用如何通过在基于卡片的界面中构建表单输入来收集和处理用户信息。

一个包含各种不同 widget 的对话框。
图 1:一个示例 Chat 应用,用于打开对话框以收集联系信息。

聊天应用会通过以下方式请求用户提供信息,以便在 Chat 内或 Chat 外执行操作:

  • 配置设置。例如,允许用户自定义通知设置,或配置 Chat 应用并将其添加到一个或多个聊天室。
  • 在其他 Google Workspace 应用中创建或更新信息。例如,允许用户创建 Google 日历活动。
  • 允许用户访问和更新其他应用或 Web 服务中的资源。例如,Chat 应用可以帮助用户直接在聊天室中更新支持请求的状态。

前提条件

Node.js

一种 Google Chat 应用,可接收并响应互动事件。如需使用 HTTP 服务创建互动式 Chat 应用,请完成此快速入门

Python

一种 Google Chat 应用,可接收并响应互动事件。如需使用 HTTP 服务创建互动式 Chat 应用,请完成此快速入门

Java

一种 Google Chat 应用,可接收并响应互动事件。如需使用 HTTP 服务创建互动式 Chat 应用,请完成此快速入门

Apps 脚本

一种 Google Chat 应用,可接收并响应互动事件。如需在 Apps 脚本中创建交互式 Chat 应用,请完成此快速入门

使用卡片构建表单

为了收集信息,Chat 应用会设计表单及其输入,并将其构建到卡片中。如需向用户显示卡片,Chat 应用可以使用以下 Chat 接口:

  • 包含一张或多张卡片的消息
  • 首页:通过与 Chat 应用的私信中的首页标签页显示的卡片。
  • 对话框:从消息和主页在新窗口中打开的卡片。

聊天应用可以使用以下 widget 构建卡片:

  • 用于向用户请求信息的表单输入 widget。您可以选择向表单输入 widget 添加验证,以确保用户正确输入和格式化信息。聊天应用可以使用以下表单输入 widget:

    • 用于自由格式或建议文本的文本输入 (textInput)。
    • 选择输入源 (selectionInput) 是可选择的界面元素,例如复选框、单选按钮和下拉菜单。选择输入 widget 还可以从静态或动态数据源填充项。例如,用户可以从自己所属的 Chat 聊天室列表中进行选择。
    • 用于日期和时间条目的日期时间选择器 (dateTimePicker)。
  • 一个按钮 widget,以便用户可以提交他们在卡片中输入的值。用户点击该按钮后,Chat 应用即可处理其收到的信息

在以下示例中,卡片使用文本输入、日期时间选择器和选择输入来收集联系信息:

如需查看使用此联系表单的聊天应用示例,请参阅以下代码:

Node.js

node/contact-form-app/index.js
/**
 * The section of the contact card that contains the form input widgets. Used in a dialog and card message.
 * To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
 */
const CONTACT_FORM_WIDGETS = [
  {
    "textInput": {
      "name": "contactName",
      "label": "First and last name",
      "type": "SINGLE_LINE"
    }
  },
  {
    "dateTimePicker": {
      "name": "contactBirthdate",
      "label": "Birthdate",
      "type": "DATE_ONLY"
    }
  },
  {
    "selectionInput": {
      "name": "contactType",
      "label": "Contact type",
      "type": "RADIO_BUTTON",
      "items": [
        {
          "text": "Work",
          "value": "Work",
          "selected": false
        },
        {
          "text": "Personal",
          "value": "Personal",
          "selected": false
        }
      ]
    }
  }
];

Python

python/contact-form-app/main.py
# The section of the contact card that contains the form input widgets. Used in a dialog and card message.
# To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
CONTACT_FORM_WIDGETS = [
  {
    "textInput": {
      "name": "contactName",
      "label": "First and last name",
      "type": "SINGLE_LINE"
    }
  },
  {
    "dateTimePicker": {
      "name": "contactBirthdate",
      "label": "Birthdate",
      "type": "DATE_ONLY"
    }
  },
  {
    "selectionInput": {
      "name": "contactType",
      "label": "Contact type",
      "type": "RADIO_BUTTON",
      "items": [
        {
          "text": "Work",
          "value": "Work",
          "selected": False
        },
        {
          "text": "Personal",
          "value": "Personal",
          "selected": False
        }
      ]
    }
  }
]

Java

java/contact-form-app/src/main/java/com/google/chat/contact/App.java
// The section of the contact card that contains the form input widgets. Used in a dialog and card message.
// To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
final static private List<GoogleAppsCardV1Widget> CONTACT_FORM_WIDGETS = List.of(
  new GoogleAppsCardV1Widget().setTextInput(new GoogleAppsCardV1TextInput()
    .setName("contactName")
    .setLabel("First and last name")
    .setType("SINGLE_LINE")),
  new GoogleAppsCardV1Widget().setDateTimePicker(new GoogleAppsCardV1DateTimePicker()
    .setName("contactBirthdate")
    .setLabel("Birthdate")
    .setType("DATE_ONLY")),
  new GoogleAppsCardV1Widget().setSelectionInput(new GoogleAppsCardV1SelectionInput()
    .setName("contactType")
    .setLabel("Contact type")
    .setType("RADIO_BUTTON")
    .setItems(List.of(
      new GoogleAppsCardV1SelectionItem()
        .setText("Work")
        .setValue("Work")
        .setSelected(false),
      new GoogleAppsCardV1SelectionItem()
        .setText("Personal")
        .setValue("Personal")
        .setSelected(false)))));

Apps 脚本

apps-script/contact-form-app/contactForm.gs
/**
 * The section of the contact card that contains the form input widgets. Used in a dialog and card message.
 * To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
 */
const CONTACT_FORM_WIDGETS = [
  {
    "textInput": {
      "name": "contactName",
      "label": "First and last name",
      "type": "SINGLE_LINE"
    }
  },
  {
    "dateTimePicker": {
      "name": "contactBirthdate",
      "label": "Birthdate",
      "type": "DATE_ONLY"
    }
  },
  {
    "selectionInput": {
      "name": "contactType",
      "label": "Contact type",
      "type": "RADIO_BUTTON",
      "items": [
        {
          "text": "Work",
          "value": "Work",
          "selected": false
        },
        {
          "text": "Personal",
          "value": "Personal",
          "selected": false
        }
      ]
    }
  }
];

如需查看可用于收集信息的互动式 widget 的更多示例,请参阅设计互动式卡片或对话框

从互动 widget 接收数据

每当用户点击按钮时,聊天应用都会收到一个互动事件,具体取决于按钮的位置:

  • 如果按钮位于消息或对话框中,Chat 应用会收到包含互动信息的 CARD_CLICKED 互动事件CARD_CLICKED 互动事件的载荷包含一个 common.formInputs 对象,其中包含用户输入的任何值。

    您可以从对象 common.formInputs.WIDGET_NAME 中检索值,其中 WIDGET_NAME 是您为 widget 指定的 name 字段。这些值以 widget 的特定数据类型(表示为 Inputs 对象)返回。

    以下内容显示了 CARD_CLICKED 互动事件的一部分,其中用户为每个 widget 输入了值:

    HTTP

    {
      "type": "CARD_CLICKED",
      "common": { "formInputs": {
        "contactName": { "stringInputs": {
          "value": ["Kai 0"]
        }},
        "contactBirthdate": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }},
        "contactType": { "stringInputs": {
          "value": ["Personal"]
        }}
      }}
    }
    

    Apps 脚本

    {
      "type": "CARD_CLICKED",
      "common": { "formInputs": {
        "contactName": { "": { "stringInputs": {
          "value": ["Kai 0"]
        }}},
        "contactBirthdate": { "": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }}},
          "contactType": { "": { "stringInputs": {
          "value": ["Personal"]
        }}}
      }}
    }
    
  • 如果按钮位于首页上,Chat 扩展应用会收到 SUBMIT_FORM 互动事件。 互动事件的载荷包含一个 commonEventObject.formInputs 对象,其中包含用户输入的任何值。

    您可以从对象 commonEventObject.formInputs.WIDGET_NAME 中检索值,其中 WIDGET_NAME 是您为 widget 指定的 name 字段。这些值以 widget 的特定数据类型(表示为 Inputs 对象)返回。

    以下内容显示了 SUBMIT_FORM 互动事件的一部分,其中用户为每个 widget 输入了值:

    HTTP

    {
      "type": "SUBMIT_FORM",
      "commonEventObject": { "formInputs": {
        "contactName": { "stringInputs": {
          "value": ["Kai 0"]
        }},
        "contactBirthdate": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }},
        "contactType": { "stringInputs": {
          "value": ["Personal"]
        }}
      }}
    }
    

    Apps 脚本

    {
      "type": "SUBMIT_FORM",
      "commonEventObject": { "formInputs": {
        "contactName": { "": { "stringInputs": {
          "value": ["Kai 0"]
        }}},
        "contactBirthdate": { "": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }}},
          "contactType": { "": { "stringInputs": {
          "value": ["Personal"]
        }}}
      }}
    }
    

如需接收数据,您的 Chat 应用会处理互动事件,以获取用户在 widget 中输入的值。下表显示了如何获取给定表单输入 widget 的值。对于每个 widget,下表都会显示 widget 接受的数据类型、值在互动事件中的存储位置以及示例值。

表单输入微件 输入数据类型 来自互动事件的输入值 示例值
textInput stringInputs event.common.formInputs.contactName.stringInputs.value[0] Kai O
selectionInput stringInputs 如需获取第一个值或唯一值,请使用 event.common.formInputs.contactType.stringInputs.value[0] Personal
dateTimePicker,仅接受日期。 dateInput event.common.formInputs.contactBirthdate.dateInput.msSinceEpoch 1000425600000

将数据转移到另一张卡

用户提交卡片中的信息后,您可能需要返回其他卡片以执行以下任一操作:

  • 通过创建不同的部分,帮助用户完成较长的表单。
  • 让用户预览并确认初始卡片中的信息,以便他们在提交之前检查自己的回答。
  • 动态填充表单的其余部分。例如,为了提示用户创建预约,聊天应用可以显示一个初始卡片,请求用户提供预约原因,然后填充另一个卡片,其中根据预约类型提供可预约的时间。

如需转移初始卡片中的输入数据,您可以构建包含 widget 的 name 和用户输入的值的 actionParameters 来构建 button widget,如以下示例所示:

Node.js

node/contact-form-app/index.js
buttonList: { buttons: [{
  text: "Submit",
  onClick: { action: {
    function: "submitForm",
    parameters: [{
      key: "contactName", value: name }, {
      key: "contactBirthdate", value: birthdate }, {
      key: "contactType", value: type
    }]
  }}
}]}

Python

python/contact-form-app/main.py
'buttonList': { 'buttons': [{
  'text': "Submit",
  'onClick': { 'action': {
    'function': "submitForm",
    'parameters': [{
      'key': "contactName", 'value': name }, {
      'key': "contactBirthdate", 'value': birthdate }, {
      'key': "contactType", 'value': type
    }]
  }}
}]}

Java

java/contact-form-app/src/main/java/com/google/chat/contact/App.java
new GoogleAppsCardV1Widget().setButtonList(new GoogleAppsCardV1ButtonList().setButtons(List.of(new GoogleAppsCardV1Button()
  .setText("Submit")
  .setOnClick(new GoogleAppsCardV1OnClick().setAction(new GoogleAppsCardV1Action()
    .setFunction("submitForm")
    .setParameters(List.of(
      new GoogleAppsCardV1ActionParameter().setKey("contactName").setValue(name),
      new GoogleAppsCardV1ActionParameter().setKey("contactBirthdate").setValue(birthdate),
      new GoogleAppsCardV1ActionParameter().setKey("contactType").setValue(type))))))))));

Apps 脚本

apps-script/contact-form-app/main.gs
buttonList: { buttons: [{
  text: "Submit",
  onClick: { action: {
    function: "submitForm",
    parameters: [{
      key: "contactName", value: name }, {
      key: "contactBirthdate", value: birthdate }, {
      key: "contactType", value: type
    }]
  }}
}]}

当用户点击该按钮时,您的 Chat 应用会收到 CARD_CLICKED 互动事件,您可以从中接收数据

回复表单提交

在收到来自卡片消息或对话框的数据后,Chat 应用会通过确认收到数据或返回错误来做出响应。

在以下示例中,聊天应用发送了一条文本消息,以确认其已成功收到从对话框或卡片消息提交的表单。

Node.js

node/contact-form-app/index.js
const contactName = event.common.parameters["contactName"];
// Checks to make sure the user entered a contact name.
// If no name value detected, returns an error message.
const errorMessage = "Don't forget to name your new contact!";
if (!contactName && event.dialogEventType === "SUBMIT_DIALOG") {
  return { actionResponse: {
    type: "DIALOG",
    dialogAction: { actionStatus: {
      statusCode: "INVALID_ARGUMENT",
      userFacingMessage: errorMessage
    }}
  }};
}

Python

python/contact-form-app/main.py
contact_name = event.get('common').get('parameters')["contactName"]
# Checks to make sure the user entered a contact name.
# If no name value detected, returns an error message.
error_message = "Don't forget to name your new contact!"
if contact_name == "" and "SUBMIT_DIALOG" == event.get('dialogEventType'):
  return { 'actionResponse': {
    'type': "DIALOG",
    'dialogAction': { 'actionStatus': {
      'statusCode': "INVALID_ARGUMENT",
      'userFacingMessage': error_message
    }}
  }}

Java

java/contact-form-app/src/main/java/com/google/chat/contact/App.java
String contactName = event.at("/common/parameters/contactName").asText();
// Checks to make sure the user entered a contact name.
// If no name value detected, returns an error message.
String errorMessage = "Don't forget to name your new contact!";
if (contactName.isEmpty() && event.at("/dialogEventType") != null && "SUBMIT_DIALOG".equals(event.at("/dialogEventType").asText())) {
  return new Message().setActionResponse(new ActionResponse()
    .setType("DIALOG")
    .setDialogAction(new DialogAction().setActionStatus(new ActionStatus()
      .setStatusCode("INVALID_ARGUMENT")
      .setUserFacingMessage(errorMessage))));
}

Apps 脚本

apps-script/contact-form-app/main.gs
const contactName = event.common.parameters["contactName"];
// Checks to make sure the user entered a contact name.
// If no name value detected, returns an error message.
const errorMessage = "Don't forget to name your new contact!";
if (!contactName && event.dialogEventType === "SUBMIT_DIALOG") {
  return { actionResponse: {
    type: "DIALOG",
    dialogAction: { actionStatus: {
      statusCode: "INVALID_ARGUMENT",
      userFacingMessage: errorMessage
    }}
  }};
}

若要处理并关闭对话框,您需要返回一个 ActionResponse 对象,该对象用于指定您是否要发送确认消息、更新原始消息或卡片,或者只是关闭对话框。如需了解相关步骤,请参阅关闭对话框

问题排查

当 Google Chat 应用或卡片返回错误时,Chat 界面会显示一条消息,提示“出了点问题”。 或“无法处理您的请求”。有时,Chat 界面不会显示任何错误消息,但 Chat 应用或卡片会产生意外结果;例如,卡片消息可能不会显示。

虽然聊天界面中可能不会显示错误消息,但当为聊天应用启用错误日志记录功能后,系统会提供描述性错误消息和日志数据,帮助您修复错误。如需有关查看、调试和修复错误的帮助,请参阅排查和修复 Google Chat 错误