جمع المعلومات من مستخدمي Google Chat ومعالجتها

يوضّح هذا الدليل كيفية جمع تطبيقات Google Chat للمعلومات من المستخدمين ومعالجتها من خلال إنشاء حقول إدخال في النماذج ضمن الواجهات المستندة إلى البطاقات.

مربّع حوار يتضمّن مجموعة متنوعة من التطبيقات المصغّرة المختلفة
الشكل 1: نموذج تطبيق Chat يفتح مربّع حوار لجمع معلومات الاتصال

تطلب تطبيقات Chat معلومات من المستخدمين لتنفيذ إجراءات داخل Chat أو خارجه، بما في ذلك بالطرق التالية:

  • اضبط الإعدادات. على سبيل المثال، للسماح للمستخدمين بتخصيص إعدادات الإشعارات أو ضبط تطبيق Chat وإضافته إلى مساحة واحدة أو أكثر.
  • إنشاء معلومات أو تعديلها في تطبيقات Google Workspace الأخرى على سبيل المثال، يمكنك السماح للمستخدمين بإنشاء حدث في "تقويم Google".
  • السماح للمستخدمين بالوصول إلى الموارد وتعديلها في تطبيقات أو خدمات ويب أخرى على سبيل المثال، يمكن أن يساعد تطبيق Chat المستخدمين في تعديل حالة طلب الدعم مباشرةً من مساحة Chat.

المتطلبات الأساسية

HTTP

تطبيق Google Chat يتلقّى تفاعلات المستخدمين ويستجيب لها لإنشاء إضافة، أكمِل دليل البدء السريع لبروتوكول HTTP.

برمجة التطبيقات

تطبيق Google Chat يتلقّى تفاعلات المستخدمين ويستجيب لها لإنشاء إضافة، أكمِل البدء السريع في "برمجة تطبيقات Google".

إنشاء نماذج باستخدام البطاقات

لجمع المعلومات، تصمّم تطبيقات Chat النماذج وحقول الإدخال، وتضمّنها في البطاقات. لعرض البطاقات للمستخدمين، يمكن لتطبيقات Chat استخدام واجهات Chat التالية:

  • الرسائل التي تحتوي على بطاقة واحدة أو أكثر
  • الصفحات الرئيسية، وهي بطاقة تظهر من علامة التبويب الصفحة الرئيسية في الرسائل المباشرة مع تطبيق Chat.
  • مربّعات الحوار، وهي بطاقات يتم فتحها في نافذة جديدة من الرسائل والصفحات الرئيسية

يمكن لتطبيقات Chat إنشاء البطاقات باستخدام التطبيقات المصغّرة التالية:

  • تطبيقات مصغّرة لإدخال النماذج تطلب معلومات من المستخدمين يمكنك اختياريًا إضافة التحقّق من الصحة إلى تطبيقات مصغّرة لإدخال النماذج، لضمان إدخال المستخدمين للمعلومات وتنسيقها بشكل صحيح. يمكن لتطبيقات Chat استخدام التطبيقات المصغّرة التالية لإدخال النماذج:

  • تطبيق مصغّر لزر ليتمكّن المستخدمون من إرسال القيم التي أدخلوها في البطاقة بعد أن ينقر المستخدم على الزر، يمكن لتطبيق Chat بعد ذلك معالجة المعلومات التي يتلقّاها.

في المثال التالي، تجمع البطاقة معلومات الاتصال باستخدام إدخال نصي وأداة اختيار التاريخ والوقت وإدخال الاختيار:

للاطّلاع على المزيد من الأمثلة على التطبيقات المصغّرة التفاعلية التي يمكنك استخدامها لجمع المعلومات، يُرجى مراجعة تصميم بطاقة أو مربّع حوار تفاعلي.

إضافة قائمة منسدلة

لتخصيص عناصر الاختيار أو السماح للمستخدمين باختيار عنصر واحد من مصدر بيانات ديناميكي، يمكن لتطبيقات Chat استخدام القوائم المنسدلة، وهي نوع من تطبيقات SelectionInput المصغّرة. على سبيل المثال، تعرض البطاقة التالية قائمة منسدلة يمكن للمستخدمين من خلالها الاختيار ديناميكيًا من قائمة جهات الاتصال:

يمكنك تعبئة العناصر لقائمة منسدلة من مصادر البيانات التالية:

تعبئة العناصر من مصدر بيانات Google Workspace

لتعبئة العناصر من مصادر بيانات Google Workspace، مثل مستخدمي Google Workspace، حدِّد الحقل platformDataSource ضمن عنصر DataSourceConfig. على عكس أنواع الإدخال الأخرى، يمكنك حذف عناصر SelectionItem لأنّ عناصر الاختيار هذه يتم الحصول عليها ديناميكيًا من Google Workspace.

يعرض الرمز التالي قائمة منسدلة لمستخدمي Google Workspace:

JSON

{
  "sections": [
    {
      "header": "Section Header",
      "widgets": [
        {
          "selectionInput": {
            "name": "contacts",
            "type": "DROPDOWN",
            "label": "Select contact from organization",
            "dataSourceConfigs": [
              {
                "platformDataSource": {
                  "commonDataSource": "USER"
                },
                "minCharactersTrigger": 1
              }
            ]
          }
        }
      ]
    }
  ]
}

تعبئة العناصر من مصدر بيانات خارجي

يمكن للقوائم المنسدلة أيضًا تعبئة العناصر من مصدر بيانات خارجي أو تابع لجهة خارجية. لاستخدام مصدر بيانات خارجي، عليك تحديد الحقل remoteDataSource ضمن عنصر DataSourceConfig يحتوي على الدالة التي ترسل طلبات بحث وتعرض عناصر من مصدر البيانات.

لتقليل الطلبات إلى مصدر بيانات خارجي، يمكنك تضمين العناصر المقترَحة التي تظهر في القائمة المنسدلة قبل أن يكتب المستخدمون في القائمة. لتعبئة العناصر المقترَحة من مصدر بيانات خارجي، حدِّد عناصر SelectionItem ثابتة.

يعرض الرمز التالي قائمة منسدلة تطلب العناصر وتعبئتها من مصدر بيانات خارجي:

JSON

{
  "sections": [
    {
      "header": "Section Header",
      "widgets": [
        {
          "selectionInput": {
            "name": "crm_leads",
            "type": "DROPDOWN",
            "label": "Select CRM Lead",
            "dataSourceConfigs": [
              {
                "remoteDataSource": {
                  "function": "getCrmLeads"
                },
                "minCharactersTrigger": 2
              }
            ],
            "items": [
              {
                "text": "Suggested Lead 1",
                "value": "lead-1"
              }
            ]
          }
        }
      ]
    }
  ]
}

للحصول على مثال كامل يوضّح كيفية عرض العناصر المقترَحة، يُرجى الاطّلاع على قسم اقتراح عناصر الاختيار.

إضافة قائمة متعددة الاختيارات

لتخصيص عناصر الاختيار أو السماح للمستخدمين باختيار عناصر من مصدر بيانات ديناميكي، يمكن لتطبيقات Chat استخدام قوائم الاختيار المتعدد، وهي نوع من تطبيقات SelectionInput المصغّرة. على سبيل المثال، تعرض البطاقة التالية قائمة متعددة الاختيارات حيث يمكن للمستخدمين الاختيار ديناميكيًا من قائمة جهات الاتصال:

يمكنك تعبئة عناصر لقائمة متعددة الاختيارات من مصادر البيانات التالية:

  • بيانات Google Workspace، والتي تشمل المستخدمين أو مساحات Chat التي يكون المستخدم عضوًا فيها لا تملأ القائمة سوى العناصر من مؤسسة 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"
    }
  }
}

يوضّح الرمز التالي قائمة متعددة الاختيارات لمساحات Chat. لتعبئة المساحات، يحدّد إدخال الاختيار الحقل 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 ثابتة.

تعرض عينة التعليمات البرمجية التالية قائمة متعددة الاختيارات تستعلم عن العناصر وتعبئتها من مصدر بيانات خارجي:

Node.js

node/chat/selection-input/index.js
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")]
}

استبدِل FUNCTION_URL بنقطة نهاية HTTP التي ترسل طلبات البحث إلى مصدر البيانات الخارجي.

Python

python/chat/selection-input/main.py
'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': [get_suggested_contact("3")]
}

استبدِل FUNCTION_URL بنقطة نهاية HTTP التي ترسل طلبات البحث إلى مصدر البيانات الخارجي.

جافا

java/chat/selection-input/src/main/java/com/google/chat/selectionInput/App.java
.setSelectionInput(new GoogleAppsCardV1SelectionInput()
  .setName("contacts")
  .setType("MULTI_SELECT")
  .setLabel("Selected contacts")
  .setMultiSelectMaxSelectedItems(3)
  .setMultiSelectMinQueryLength(1)
  .setExternalDataSource(new GoogleAppsCardV1Action().setFunction(FUNCTION_URL))
  // Suggested items loaded by default.
  // The list is static here but it could be dynamic.
  .setItems(List.of(getSuggestedContact("3")))))))))));

استبدِل FUNCTION_URL بنقطة نهاية HTTP التي ترسل طلبات البحث إلى مصدر البيانات الخارجي.

برمجة التطبيقات

يرسل هذا المثال رسالة بطاقة من خلال عرض ملف JSON للبطاقة. يمكنك أيضًا استخدام خدمة بطاقات "برمجة تطبيقات Google".

apps-script/chat/selection-input/selection-input.gs
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")]
}

للحصول على مثال كامل يوضّح كيفية عرض العناصر المقترَحة، يُرجى الاطّلاع على قسم اقتراح عناصر الاختيار.

تلقّي البيانات من التطبيقات المصغّرة التفاعلية

عندما ينقر المستخدمون على زر، يتم تشغيل إجراء تطبيق Chat الخاص به مع معلومات عن التفاعل. في commonEventObject لحمولة الحدث، يحتوي العنصر formInputs على أي قيم يُدخلها المستخدم.

يمكنك استرداد القيم من الكائن event.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 في البطاقة دالة تطلب مصدر البيانات الخارجي. بالنسبة إلى القوائم المتعددة الاختيارات، يمكنك تحديد الحقل externalDataSource. بالنسبة إلى القوائم المنسدلة، يمكنك تحديد الحقل remoteDataSource ضمن عنصر DataSourceConfig.

يمكنك أيضًا ضبط عدد الأحرف التي يكتبها المستخدم قبل أن تعرض القائمة الاقتراحات. بالنسبة إلى القوائم المتعددة الاختيارات، اضبط الحقل multiSelectMinQueryLength. بالنسبة إلى القوائم المنسدلة، اضبط حقل min_characters_trigger ضمن DataSourceConfig.

لعرض العناصر المقترَحة، يجب أن تنفّذ الدالة ما يلي:

  1. معالجة كائن حدث، يتلقّاه تطبيق Chat عندما يكتب المستخدمون في القائمة.
  2. من كائن الحدث، احصل على القيمة التي يكتبها المستخدم، والتي يتم تمثيلها في الحقل event.commonEventObject.parameters["autocomplete_widget_query"].
  3. يمكنك الاستعلام عن مصدر البيانات باستخدام قيمة إدخال المستخدم للحصول على SelectionItems واحد أو أكثر لاقتراحه على المستخدم.
  4. يمكنك عرض السلع المقترَحة من خلال عرض الإجراء RenderActions مع عنصر modifyCard.

يوضّح نموذج الرمز البرمجي التالي كيفية اقتراح تطبيق Chat للعناصر ديناميكيًا في قائمة الاختيار المتعدّد على بطاقة. عندما يكتب المستخدم في القائمة، تستعلم الدالة أو نقطة النهاية المقدَّمة في حقل externalDataSource الخاص بعنصر واجهة المستخدم عن مصدر بيانات خارجي، وتقترح عناصر يمكن للمستخدم اختيارها.

Node.js

node/chat/selection-input/index.js
/**
 * Web app 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
 */
app.post('/', async (req, res) => {
  // Stores the Google Chat event
  const chatEvent = req.body.chat;

  // Handle user interaction with multiselect.
  if(chatEvent.widgetUpdatedPayload) {
    return res.json(queryContacts(req.body));
  }

  // Replies with a card that contains the multiselect menu.
  return res.json({ 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 التي ترسل طلبات البحث إلى مصدر البيانات الخارجي.

Python

python/chat/selection-input/main.py
@app.route('/', methods=['POST'])
def post() -> Mapping[str, Any]:
  """Handle requests from Google Chat

  Returns:
      Mapping[str, Any]: The response
  """
  # Stores the Google Chat event
  chatEvent = request.get_json().get('chat')

  # Handle user interaction with multiselect.
  if chatEvent.get('widgetUpdatedPayload') is not None:
    return json.jsonify(query_contacts(request.get_json()))

  # Replies with a card that contains the multiselect menu.
  return json.jsonify({ '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': [get_suggested_contact("3")]
        }
      }]}]}
    }]}
  }}}})


def query_contacts(event: dict) -> dict:
  """Get contact suggestions based on text typed by users.

  Args:
      event (Mapping[str, Any]): The event object that contains the user's query

  Returns:
      Mapping[str, Any]: The response with contact suggestions.
  """
  query = event.get("commonEventObject").get("parameters").get("autocomplete_widget_query")
  return { 'action': { 'modifyOperations': [{ 'updateWidget': { 'selectionInputWidgetSuggestions': { 'suggestions': list(
    filter(lambda e: query is None or query in e["text"], [
      # The list is static here but it could be dynamic.
      get_suggested_contact("1"), get_suggested_contact("2"), get_suggested_contact("3"), get_suggested_contact("4"), get_suggested_contact("5")
    # Only return items based on the query from the user
    ])
  )}}}]}}


def get_suggested_contact(id: str) -> dict:
  """Generate a suggested contact given an ID.

  Args:
      id (str): The ID of the contact to return.

  Returns:
      Mapping[str, Any]: The contact formatted as a selection item in the menu.
  """
  return {
    'value': id,
    'startIconUri': "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    'text': "Contact " + id
  }

استبدِل FUNCTION_URL بنقطة نهاية HTTP التي ترسل طلبات البحث إلى مصدر البيانات الخارجي.

جافا

java/chat/selection-input/src/main/java/com/google/chat/selectionInput/App.java
@SpringBootApplication
@RestController
// Web app that responds to events sent from a Google Chat space.
public class App {
  private static final String FUNCTION_URL = "your-function-url";

  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }

  /**
   * Handle requests from Google Chat
   * 
   * @param event the event object sent by Google Chat
   * @return The response to be sent back to Google Chat
   */
  @PostMapping("/")
  @ResponseBody
  public GenericJson onEvent(@RequestBody JsonNode event) throws Exception {
    // Stores the Google Chat event
    JsonNode chatEvent = event.at("/chat");

    // Handle user interaction with multiselect.
    if (!chatEvent.at("/widgetUpdatedPayload").isEmpty()) {
      return queryContacts(event);
    }

    // Replies with a card that contains the multiselect menu.
    Message message = new Message().setCardsV2(List.of(new CardWithId()
      .setCardId("contactSelector")
      .setCard(new GoogleAppsCardV1Card()
        .setSections(List.of(new GoogleAppsCardV1Section().setWidgets(List.of(new GoogleAppsCardV1Widget()
          .setSelectionInput(new GoogleAppsCardV1SelectionInput()
            .setName("contacts")
            .setType("MULTI_SELECT")
            .setLabel("Selected contacts")
            .setMultiSelectMaxSelectedItems(3)
            .setMultiSelectMinQueryLength(1)
            .setExternalDataSource(new GoogleAppsCardV1Action().setFunction(FUNCTION_URL))
            // Suggested items loaded by default.
            // The list is static here but it could be dynamic.
            .setItems(List.of(getSuggestedContact("3")))))))))));

    return new GenericJson() {{
      put("hostAppDataAction", new GenericJson() {{
        put("chatDataAction", new GenericJson() {{
          put("createMessageAction", new GenericJson() {{
            put("message", message);
          }});
        }});
      }});
    }};
  }

  /**
   * Get contact suggestions based on text typed by users.
   *
   * @param event the event object that contains the user's query.
   * @return The response with contact suggestions.
   */
  GenericJson queryContacts(JsonNode event) throws Exception {
    String query = event.at("/commonEventObject/parameters/autocomplete_widget_query").asText();
    List<GoogleAppsCardV1SelectionItem> suggestions = List.of(
      // 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
    ).stream().filter(e -> query == null || e.getText().indexOf(query) > -1).toList();

    return new GenericJson() {{
      put("action", new GenericJson() {{
        put("modifyOperations", List.of(new GenericJson() {{
          put("updateWidget", new GenericJson() {{
            put("selectionInputWidgetSuggestions", new GenericJson() {{
              put("suggestions", suggestions);
            }});
          }});
        }}));
      }});
    }};
  }

  /**
   * Generate a suggested contact given an ID.
   * 
   * @param id The ID of the contact to return.
   * @return The contact formatted as a selection item in the menu.
   */
  GoogleAppsCardV1SelectionItem getSuggestedContact(String id) {
    return new GoogleAppsCardV1SelectionItem()
      .setValue(id)
      .setStartIconUri("https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png")
      .setText("Contact " + id);
  }
}

استبدِل FUNCTION_URL بنقطة نهاية HTTP التي ترسل طلبات البحث إلى مصدر البيانات الخارجي.

برمجة التطبيقات

يرسل هذا المثال رسالة بطاقة من خلال عرض ملف JSON للبطاقة. يمكنك أيضًا استخدام خدمة بطاقات "برمجة تطبيقات Google".

apps-script/chat/selection-input/selection-input.gs
/**
* 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

node/chat/contact-form-app/index.js
{ buttonList: { buttons: [{
  text: "SUBMIT",
  onClick: { action: {
    function: FUNCTION_URL,
    parameters: [
      { key: "actionName", value: "submitDialog" },
      // Pass input values as parameters for last dialog step (submission)
      { key: "contactName", value: name },
      { key: "contactBirthdate", value: birthdate },
      { key: "contactType", value: type }
    ]
  }}
}]}}

استبدِل FUNCTION_URL بنقطة نهاية HTTP التي تعالج النقرات على الأزرار.

Python

python/chat/contact-form-app/main.py
{ 'buttonList': { 'buttons': [{
  'text': "SUBMIT",
  'onClick': { 'action': {
    'function': FUNCTION_URL,
    'parameters': [
      { 'key': "actionName", 'value': "submitDialog" },
      # Pass input values as parameters for last dialog step (submission)
      { 'key': "contactName", 'value': name },
      { 'key': "contactBirthdate", 'value': birthdate },
      { 'key': "contactType", 'value': type }
    ]
  }}
}]}}

استبدِل FUNCTION_URL بنقطة نهاية HTTP التي تعالج النقرات على الأزرار.

جافا

java/chat/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(FUNCTION_URL)
      .setParameters(List.of(
        new GoogleAppsCardV1ActionParameter().setKey("actionName").setValue("submitDialog"),
        // Pass input values as parameters for last dialog step (submission)
        new GoogleAppsCardV1ActionParameter().setKey("contactName").setValue(name),
        new GoogleAppsCardV1ActionParameter().setKey("contactBirthdate").setValue(birthdate),
        new GoogleAppsCardV1ActionParameter().setKey("contactType").setValue(type))))))))))));

استبدِل FUNCTION_URL بنقطة نهاية HTTP التي تعالج النقرات على الأزرار.

برمجة التطبيقات

يرسل هذا المثال رسالة بطاقة من خلال عرض ملف JSON للبطاقة. يمكنك أيضًا استخدام خدمة بطاقات "برمجة تطبيقات Google".

apps-script/chat/contact-form-app/Code.gs
{ buttonList: { buttons: [{
  text: "SUBMIT",
  onClick: { action: {
    function: "submitDialog",
    // Pass input values as parameters for last dialog step (submission)
    parameters: [
      { key: "contactName", value: name },
      { key: "contactBirthdate", value: birthdate },
      { key: "contactType", value: type }
    ]
  }}
}]}}

عندما ينقر المستخدم على الزر، يتلقّى تطبيق Chat كائن حدث يمكنك من خلاله تلقّي البيانات.

الردّ على نموذج تم إرساله

بعد تلقّي البيانات من رسالة بطاقة أو مربّع حوار، يستجيب تطبيق Chat إما من خلال تأكيد الاستلام أو عرض رسالة خطأ.

في المثال التالي، يرسل تطبيق Chat رسالة نصية لتأكيد تلقّيه نموذجًا تم إرساله من رسالة بطاقة بنجاح.

Node.js

node/chat/contact-form-app/index.js
return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
  text: "✅ " + event.commonEventObject.parameters["contactName"] + " has been added to your contacts."
}}}}};

Python

python/chat/contact-form-app/main.py
return { 'hostAppDataAction': { 'chatDataAction': { 'createMessageAction': { 'message': {
  'text': "✅ " + event.get('commonEventObject').get('parameters')["contactName"] + " has been added to your contacts."
}}}}}

جافا

java/chat/contact-form-app/src/main/java/com/google/chat/contact/App.java
return new GenericJson() {{
  put("hostAppDataAction", new GenericJson() {{
    put("chatDataAction", new GenericJson() {{
      put("createMessageAction", new GenericJson() {{
        put("message", new Message()
          .setText( "✅ " + event.at("/commonEventObject/parameters/contactName").asText() +
                    " has been added to your contacts."));
      }});
    }});
  }});
}};

برمجة التطبيقات

يرسل هذا المثال رسالة بطاقة من خلال عرض ملف JSON للبطاقة. يمكنك أيضًا استخدام خدمة بطاقات "برمجة تطبيقات Google".

apps-script/chat/contact-form-app/Code.gs
return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
  text: "✅ " + event.commonEventObject.parameters["contactName"] + " has been added to your contacts."
}}}}};

لمعالجة مربّع حوار وإغلاقه، عليك عرض عنصر RenderActions يحدّد ما إذا كنت تريد إرسال رسالة تأكيد أو تعديل الرسالة أو البطاقة الأصلية أو إغلاق مربّع الحوار فقط. للاطّلاع على الخطوات، يُرجى مراجعة مقالة إغلاق مربّع حوار.

تحديد المشاكل وحلّها

يقدّم هذا القسم خطوات تحديد المشاكل وحلّها لرموز أخطاء معيّنة وسلوكيات وقت التشغيل عند التفاعل مع مربّعات الحوار في Chat.

تفاعلات مربّعات الحوار تعرض رسالة "حدث خطأ غير محدَّد أثناء استدعاء الإضافة"

عند التفاعل مع مربّع حوار، إذا ظهرت لك سجلّات أخطاء تتضمّن الرسالة "حدث خطأ غير محدّد أثناء استدعاء الإضافة" والرمز 13، يشير ذلك عادةً إلى خطأ داخلي أو أنّ نقطة نهاية HTTP لتطبيق Chat تعذّر عليها معالجة الطلب أو عرض ردّ صالح.

لتحديد المشاكل وحلّها:

  • تحقَّق من سجلّات نقطة نهاية HTTP بحثًا عن أي استثناءات أو أعطال لم تتم معالجتها.
  • تأكَّد من أنّ نقطة النهاية تستجيب للطلبات في غضون 30 ثانية. إذا استغرقت نقطة النهاية أكثر من 30 ثانية للتشغيل، لن يتمكن Chat من معالجة الاستجابة ويفشل التفاعل. لمعرفة التفاصيل، يُرجى الاطّلاع على الحدود القصوى للمعدّل وأفضل الممارسات.
  • تأكَّد من أنّ نقطة النهاية تعرض ردًا صالحًا. بالنسبة إلى عمليات إرسال مربّعات الحوار، يجب أن تعرض نقطة النهاية عنصر RenderActions بتنسيق JSON الصحيح. إذا كان الردّ غير صحيح أو لا يحتوي على الحقول المطلوبة، قد يتعذّر التفاعل مع مربّع الحوار.

عندما يعرض تطبيق Google Chat أو بطاقة خطأً، تعرض واجهة Chat رسالة "حدث خطأ". أو "تتعذّر معالجة طلبك". في بعض الأحيان، لا تعرض واجهة مستخدم Chat أي رسالة خطأ، ولكن ينتج عن تطبيق Chat أو البطاقة نتيجة غير متوقعة، على سبيل المثال، قد لا تظهر رسالة بطاقة.

على الرغم من أنّ رسالة الخطأ قد لا تظهر في واجهة مستخدم Chat، تتوفّر رسائل خطأ وصفية وبيانات السجلّ لمساعدتك في إصلاح الأخطاء عند تفعيل تسجيل الأخطاء لتطبيقات Chat. للحصول على مساعدة في عرض الأخطاء وتصحيحها وإصلاحها، يُرجى الاطّلاع على مقالة تحديد أخطاء Google Chat وحلّها.

تطبيقات Chat التي ليست إضافات: قراءة بيانات النماذج التي يُدخلها المستخدمون في البطاقات

تنطبق المستندات التالية على تطبيقات Chat التي ليست إضافات Google Workspace. لنقل تطبيق Chat ليس إضافة، يُرجى الاطّلاع على المقالة تحويل تطبيق Google Chat إلى إضافة Google Workspace.

إنشاء نماذج باستخدام البطاقات

للاطّلاع على مثال لتطبيق 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/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-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
        }
      ]
    }
  }
];

تلقّي البيانات من التطبيقات المصغّرة التفاعلية

عندما ينقر المستخدمون على زر، تتلقّى تطبيقات Chat التي ليست إضافات حدث تفاعل يعتمد على موقع الزر:

  • إذا كان الزر في رسالة أو مربّع حوار، تتلقّى تطبيقات Chat التي ليست إضافات حدث تفاعل CARD_CLICKED يحتوي على معلومات عن التفاعل. تحتوي حمولة أحداث التفاعل CARD_CLICKED على عنصر common.formInputs (event.common.formInputs) مع أي قيم يُدخلها المستخدم.

    يمكنك استرداد القيم من الكائن common.formInputs.WIDGET_NAME، حيث WIDGET_NAME هو حقل name الذي حددته للأداة. يتم عرض القيم كنوع بيانات محدّد للأداة (يتم تمثيله كعنصر Inputs).

    يوضح ما يلي جزءًا من حدث تفاعل CARD_CLICKED حيث أدخل المستخدم قيمًا لكل عنصر واجهة مستخدم:

    HTTP

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

    برمجة التطبيقات

    {
      "type": "CARD_CLICKED",
      "common": { "formInputs": {
        "contactName": { "": { "stringInputs": {
          "value": ["Kai 0"]
        }}},
        "contactBirthdate": { "": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }}},
          "contactType": { "": { "stringInputs": {
          "value": ["Personal"]
        }}}
      }}
    }
    
  • إذا كان الزر في صفحة رئيسية، ستتلقّى تطبيقات Chat التي ليست إضافات حدث تفاعل SUBMIT_FORM. تحتوي حمولة حدث التفاعل على عنصر commonEventObject.formInputs (event.commonEventObject.formInputs) مع أي قيم يُدخلها المستخدم.

    يمكنك استرداد القيم من الكائن commonEventObject.formInputs.WIDGET_NAME، حيث WIDGET_NAME هو حقل name الذي حددته للأداة. يتم عرض القيم كنوع بيانات محدّد للأداة (يتم تمثيله كعنصر Inputs).

    يوضح ما يلي جزءًا من حدث تفاعل SUBMIT_FORM حيث أدخل المستخدم قيمًا لكل عنصر واجهة مستخدم:

    HTTP

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

    برمجة التطبيقات

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

لتلقّي البيانات، يعالج تطبيق Chat الذي لا يُعدّ إضافة حدث التفاعل للحصول على القيم التي يُدخلها المستخدمون في التطبيقات المصغّرة. يوضّح الجدول التالي كيفية الحصول على قيمة عنصر واجهة مستخدم معيّن لإدخال البيانات في النموذج. بالنسبة إلى كل تطبيق مصغّر، يعرض الجدول نوع البيانات الذي يقبله التطبيق المصغّر، ومكان تخزين القيمة في حدث التفاعل، ومثال على القيمة.

التطبيق المصغَّر لإدخال النموذج نوع بيانات الإدخال قيمة الإدخال من حدث التفاعل مثال على القيمة
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

نقل البيانات إلى بطاقة أخرى

لنقل البيانات التي تم إدخالها من البطاقة الأولية في تطبيق Chat ليس إضافة، يمكنك إنشاء تطبيق مصغّر button باستخدام actionParameters يحتوي على name للتطبيق المصغّر والقيمة التي يُدخلها المستخدم، كما هو موضّح في المثال التالي:

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

لمعالجة مربّع حوار وإغلاقه في تطبيق Chat ليس إضافة، يمكنك عرض عنصر ActionResponse يحدّد ما إذا كنت تريد إرسال رسالة تأكيد أو تعديل الرسالة أو البطاقة الأصلية أو إغلاق مربّع الحوار فقط. للاطّلاع على الخطوات، يُرجى مراجعة مقالة إغلاق مربّع حوار.