Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Note
В этой статье описываются особенности, используемые в агентах или потоках агентов, питаемых стандартным жгутом.
Холст агента определяет, как агент выглядит для пользователей. Вы можете настроить холст двумя способами:
Настройте стандартный холст с помощью JavaScript и CSS на вашем веб-сайте. Используйте этот вариант для простых изменений.
Используйте пользовательский холст на основе холста веб-чата платформы Bot Framework. Этот вариант требует опыта разработки и обеспечивает возможность полной настройки.
Вы также можете комбинировать настроенный холст с настройкой для автоматического начала разговора.
Вы можете изменить имя агента и значок на портале.
После того как вы опубликуете агент, пользователи смогут взаимодействовать с ним через холст веб-чата.
Important
Вы можете установить и использовать пример кода, включенный в эту статью, только для использования с Copilot Studio. Образец кода лицензируется "как есть" и исключается из любых соглашений об уровне обслуживания или служб поддержки. Вы берете на себя все риски, связанные с использованием сведений, приводящихся в данном документе.
Корпорация Майкрософт не предоставляет никаких явных гарантий или условий и отказывается от всех подразумеваемых гарантий, в том числе пригодности для использования, пригодности для конкретной цели и ненарушения прав.
Изменение имени агента и значка
Important
- После обновления значка для агента может пройти до 24 часов, прежде чем новый значок появится везде.
- Если агент подключен к многоканальному взаимодействию для Customer Service, его имя определяется свойством Отображаемое имя в регистрации портала Azure.
- Если ваш агент предназначен для публикации в Teams, ознакомьтесь с требованиями к значкам в документации разработчиков Microsoft Teams.
Перейдите на страницу Обзор для вашего агента.
Выберите Изменить рядом с пунктом Сведения.
Измените имя и значок агента по желанию.
Нажмите Сохранить.
Настройка холста по умолчанию (простая)
Используйте JavaScript и CSS для настройки стандартного холста.
Во-первых, настройте, где вы развертываете свой холст агента.
Скопируйте образец HTML-кода в файл с именем
index.html. Вы также можете использовать Редактор HTML «попробуй это».<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="description" content="Contoso Web Chat Assistant" /> <title>Contoso Sample Web Chat Test</title> <script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script> <script> let webChatInstance = null; let directLineUrl = null; // Replace with your token endpoint const tokenEndpoint = "<YOUR TOKEN ENDPOINT>"; const styleOptions = { "accent": "#0078D4", "autoScrollSnapOnPage": true, "autoScrollSnapOnPageOffset": 0, "avatarBorderRadius": "7%", "avatarSize": 31, "backgroundColor": "#e8e9eb", "botAvatarBackgroundColor": "#ffffff00", "botAvatarImage": "https://powercatexternal.blob.core.windows.net/creatorkit/Assets/ChatbotLogoBlue.png", "botAvatarInitials": "B", "bubbleAttachmentMaxWidth": 480, "bubbleAttachmentMinWidth": 250, "bubbleBackground": "#f0eded", "bubbleBorderColor": "#f5f5f5", "bubbleBorderRadius": 41, "bubbleBorderStyle": "solid", "bubbleBorderWidth": 1, "bubbleFromUserBackground": "#ebefff", "bubbleFromUserBorderColor": "#f5f5f5", "bubbleFromUserBorderRadius": 41, "bubbleFromUserBorderStyle": "solid", "bubbleFromUserBorderWidth": 1, "bubbleFromUserNubOffset": 0, "bubbleFromUserNubSize": 0, "bubbleFromUserTextColor": "#242424", "bubbleImageHeight": 10, "bubbleImageMaxHeight": 240, "bubbleImageMinHeight": 240, "bubbleMessageMaxWidth": 480, "bubbleMessageMinWidth": 120, "bubbleMinHeight": 50, "bubbleNubOffset": 0, "bubbleTextColor": "#242424", "emojiSet": true, "fontSizeSmall": "70%", "hideUploadButton": false, "messageActivityWordBreak": "break-word", "monospaceFont": "Consolas", "paddingRegular": 10, "paddingWide": 10, "primaryFont": null, "sendBoxBackground": "#e8e9eb", "sendBoxBorderTop": "solid 1px #808080", "sendBoxButtonColor": "#0078d4", "sendBoxButtonColorOnHover": "#006cbe", "sendBoxButtonShadeBorderRadius": 40, "sendBoxButtonShadeColorOnHover": "", "sendBoxHeight": 60, "sendBoxPlaceholderColor": "#171616", "sendBoxTextColor": "#2e2d2d", "showAvatarInGroup": "status", "spinnerAnimationHeight": 16, "spinnerAnimationPadding": 12, "spinnerAnimationWidth": 16, "subtleColor": "#000000FF", "suggestedActionBackgroundColor": "#006FC4FF", "suggestedActionBackgroundColorOnHover": "#0078D4", "suggestedActionBorderColor": "", "suggestedActionBorderRadius": 10, "suggestedActionBorderWidth": 1, "suggestedActionLayout": "flow", "suggestedActionTextColor": "#FFFFFFFF", "typingAnimationBackgroundImage": "url('https://wpamelia.com/wp-content/uploads/2018/11/ezgif-2-6d0b072c3d3f.gif')", "typingAnimationDuration": 5000, "typingAnimationHeight": 20, "typingAnimationWidth": 64, "userAvatarBackgroundColor": "#222222", "userAvatarImage": "https://avatars.githubusercontent.com/u/8174072?v=4&size=64", "userAvatarInitials": "U" }; const backgroundImage = ""; document.addEventListener('DOMContentLoaded', () => { const root = document.documentElement; root.style.setProperty('--primary-color', createGradient(styleOptions.accent)); root.style.setProperty('--header-textColor', styleOptions.suggestedActionTextColor); if (backgroundImage) { const webchatElement = document.getElementById('webchat'); webchatElement.style.backgroundImage = `url(${backgroundImage})`; webchatElement.style.backgroundSize = 'cover'; webchatElement.style.backgroundPosition = 'center'; webchatElement.style.backgroundRepeat = 'no-repeat'; const overlay = document.createElement('div'); overlay.className = 'webchat-overlay'; webchatElement.appendChild(overlay); } }); function createGradient(baseColor) { const r = parseInt(baseColor.slice(1, 3), 16); const g = parseInt(baseColor.slice(3, 5), 16); const b = parseInt(baseColor.slice(5, 7), 16); const lighterColor = `#${Math.min(255, r + 30).toString(16).padStart(2, '0')}${Math.min(255, g + 30).toString(16).padStart(2, '0')}${Math.min(255, b + 30).toString(16).padStart(2, '0')}`; const darkerColor = `#${Math.max(0, r - 30).toString(16).padStart(2, '0')}${Math.max(0, g - 30).toString(16).padStart(2, '0')}${Math.max(0, b - 30).toString(16).padStart(2, '0')}`; return `linear-gradient(135deg, ${lighterColor}, ${baseColor}, ${darkerColor})`; } const environmentEndPoint = tokenEndpoint.slice( 0, tokenEndpoint.indexOf("/powervirtualagents") ); const apiVersion = tokenEndpoint .slice(tokenEndpoint.indexOf("api-version")) .split("=")[1]; const regionalChannelSettingsURL = `${environmentEndPoint}/powervirtualagents/regionalchannelsettings?api-version=${apiVersion}`; function showChat() { const popup = document.getElementById("chatbot-popup"); const openButton = document.getElementById("open-chat"); popup.classList.add("visible"); openButton.classList.add("hidden"); } function hideChat() { const popup = document.getElementById("chatbot-popup"); const openButton = document.getElementById("open-chat"); popup.classList.remove("visible"); openButton.classList.remove("hidden"); } function createCustomStore() { return window.WebChat.createStore( {}, ({ dispatch }) => (next) => (action) => { if (action.type === "DIRECT_LINE/CONNECT_FULFILLED") { dispatch({ type: "DIRECT_LINE/POST_ACTIVITY", meta: { method: "keyboard" }, payload: { activity: { channelData: { postBack: true }, name: "startConversation", type: "event", }, }, }); } return next(action); } ); } async function restartConversation() { try { if (!directLineUrl) { console.error("DirectLine URL not initialized"); return; } const response = await fetch(tokenEndpoint); const conversationInfo = await response.json(); if (!conversationInfo.token) { throw new Error("Failed to get conversation token"); } const newDirectLine = window.WebChat.createDirectLine({ domain: `${directLineUrl}v3/directline`, token: conversationInfo.token, }); const webchatElement = document.getElementById("webchat"); webChatInstance = window.WebChat.renderWebChat( { directLine: newDirectLine, styleOptions, store: createCustomStore(), }, webchatElement ); } catch (err) { console.error("Failed to restart conversation:", err); } } async function initializeChat() { try { const response = await fetch(regionalChannelSettingsURL); const data = await response.json(); directLineUrl = data.channelUrlsById.directline; if (!directLineUrl) { throw new Error("Failed to get DirectLine URL"); } const conversationResponse = await fetch(tokenEndpoint); const conversationInfo = await conversationResponse.json(); if (!conversationInfo.token) { throw new Error("Failed to get conversation token"); } const directLine = window.WebChat.createDirectLine({ domain: `${directLineUrl}v3/directline`, token: conversationInfo.token, }); webChatInstance = window.WebChat.renderWebChat( { directLine, styleOptions, store: createCustomStore(), }, document.getElementById("webchat") ); } catch (err) { console.error("Failed to initialize chat:", err); } } initializeChat(); </script> <style> :root { --primary-gradient: var(--primary-color); --chat-width: 450px; --chat-height: 520px; --header-height: 56px; --border-radius: 16px; --transition-speed: 0.3s; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } body { min-height: 100vh; background-color: #f3f4f6; } #chatbot-popup { display: none; position: fixed; bottom: 32px; right: 32px; width: var(--chat-width); height: var(--chat-height); background: white; border-radius: var(--border-radius); box-shadow: 0 18px 40px -5px rgba(0, 0, 0, 0.2), 0 15px 20px -5px rgba(0, 0, 0, 0.1); overflow: hidden; opacity: 0; transform-origin: bottom right; transform: scale(0.95); transition: all var(--transition-speed) ease-in-out; z-index: 999; } #chatbot-popup.visible { display: block; opacity: 1; transform: scale(1); } #chatbot-header { background: var(--primary-color); padding: 16px 20px; height: var(--header-height); display: flex; justify-content: space-between; align-items: center; color: var(--header-textColor); } .header-title { display: flex; align-items: center; gap: 12px; font-size: 16px; font-weight: 500; } .header-buttons { display: flex; gap: 12px; align-items: center; } .icon-button { background: none; border: none; color: var(--header-textColor); cursor: pointer; padding: 8px; border-radius: 8px; display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; } .icon-button:hover { color: var(--header-textColor); background: rgba(255, 255, 255, 0.1); } .icon-button:focus { outline: 2px solid rgba(255, 255, 255, 0.5); outline-offset: 2px; } #webchat { height: calc(100% - var(--header-height)); background-color: #f9fafb; position: relative; } .webchat-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.85); pointer-events: none; z-index: 1; } #webchat > div { position: relative; z-index: 2; } #webchat .webchat__basic-transcript__content { white-space: pre-wrap !important; word-break: break-word !important; } #webchat .webchat__bubble__content { padding: 8px 12px !important; } #webchat .webchat__bubble { max-width: 85% !important; margin: 8px !important; } #webchat .webchat__basic-transcript__content ul, #webchat .webchat__basic-transcript__content ol, #webchat .webchat__bubble__content ul, #webchat .webchat__bubble__content ol { padding-left: 24px !important; margin: 8px 0 !important; list-style-position: outside !important; } #webchat .webchat__basic-transcript__content li, #webchat .webchat__bubble__content li { margin: 4px 0 !important; padding-left: 4px !important; } #open-chat { position: fixed; bottom: 32px; right: 32px; width: 64px; height: 64px; border-radius: 50%; background: var(--primary-gradient); border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); transition: all var(--transition-speed) ease-in-out; z-index: 998; } #open-chat.hidden { opacity: 0; transform: scale(0.95) translateY(10px); pointer-events: none; } #open-chat:hover { transform: translateY(-4px); box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); } #open-chat:focus { outline: 3px solid rgba(79, 70, 229, 0.5); outline-offset: 2px; } #open-chat svg { width: 28px; height: 28px; color: white; transition: transform 0.2s ease; } .main-content { max-width: 1200px; margin: 0 auto; padding: 48px 24px; } .main-content h1 { font-size: 36px; color: #111827; text-align: center; } .main-content p { font-size: 18px; color: #4b5563; line-height: 1.6; margin-bottom: 48px; text-align: center; max-width: 800px; margin-left: auto; margin-right: auto; } .content-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 32px; margin-bottom: 32px; } .content-box { background: linear-gradient(135deg, #e6e6e6, #c4c4c4, #9f9f9f); padding: 32px; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); min-height: 300px; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; position: relative; overflow: hidden; } .content-box::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; } .content-box.featured { grid-column: span 2; min-height: 350px; background: linear-gradient(135deg, #e6e6e6, #c4c4c4, #9f9f9f); color: #000000; } .content-box h2 { font-size: 24px; margin-bottom: 16px; position: relative; } .content-box p { font-size: 16px; color: #6b7280; margin-bottom: 0; } .content-box.featured p { color: #000000; } @media (max-width: 768px) { .content-grid { grid-template-columns: 1fr; } .content-box.featured { grid-column: span 1; } .main-content { padding: 24px 16px; } .main-content h1 { font-size: 28px; } #chatbot-popup { width: 100%; height: 100%; bottom: 0; right: 0; border-radius: 0; } } </style> </head> <body> <div class="main-content"> <h1>Header</h1> <p>Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat.</p> <div class="content-grid"> <div class="content-box featured"> <h2>Featured Content</h2> <p>Primary content area with custom styling and gradient background</p> </div> <div class="content-box"> <h2>Section One</h2> <p>Content box with minimal design</p> </div> <div class="content-box"> <h2>Section Two</h2> <p>Another content section with consistent styling</p> </div> </div> </div> <div id="chatbot-popup" role="complementary" aria-label="Chat Assistant"> <div id="chatbot-header"> <div class="header-title"> <svg class="chat-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" > <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" ></path> </svg> <span>Contoso Assistant</span> </div> <div class="header-buttons"> <button class="icon-button" id="restart-button" onclick="restartConversation()" aria-label="Restart Conversation" > <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" > <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" ></path> <path d="M3 3v5h5"></path> </svg> </button> <button class="icon-button" id="close-button" onclick="hideChat()" aria-label="Close Chat" > <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" > <line x1="18" y1="6" x2="6" y2="18"></line> <line x1="6" y1="6" x2="18" y2="18"></line> </svg> </button> </div> </div> <div id="webchat" role="main"></div> </div> <button id="open-chat" onclick="showChat()" aria-label="Open Chat Assistant" > <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" > <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" ></path> </svg> </button> </body> </html>В
index.html, заменить:const tokenEndpoint = "<YOUR TOKEN ENDPOINT>";конечной точкой токена.
Откройте
index.htmlв современном браузере (например, Microsoft Edge).Выполните тестирование агента.
Если агент не отвечает:
- Убедитесь, что агент опубликован.
- Проверьте значение конечной точки токена.
- Убедитесь, что значение конечной точки токена находится после
=и заключено в двойные кавычки".
Получение конечной точки токена для вашего агента
Чтобы настроить свой холст, будь то холст по умолчанию или пользовательский холст, к которому вы подключаетесь, вам нужна конечная точка токена для вашего агента.
В пункте Параметры выберите Каналы.
Выберите электронную почту.
Рядом с пунктом Конечная точка токена выберите Копировать.
Настройка значка агента, цвета фона и имени
Используйте объект styleOptions для настройки заранее определенных стилей.
Для получения дополнительной информации о том, что вы можете настроить, и ссылок на файл defaultStyleOptions.js см. раздел Настройка веб-чата.
Изменение значка агента
Обновите файл
index.htmlсо следующим примером кода:const styleOptions = { "accent": "#00809d", "botAvatarBackgroundColor": "#FFFFFF", "botAvatarImage": "https://learn.microsoft.com/azure/bot-service/v4sdk/media/logo_bot.svg", "botAvatarInitials": "BT", "userAvatarImage": "https://avatars.githubusercontent.com/u/661465", "userAvatarInitials": "U" };Замените оба изображения аватара изображениями вашей компании. Если у вас нет URL изображения, используйте строку изображения, закодированную в Base64.
Изменение цвета фона
В
index.htmlдобавьте элементbackgroundColorв определениеstyleOptions:const styleOptions = { "backgroundColor": "lightgray", // ... };Измените
backgroundColorна любой цвет, который вы хотите. Используйте стандартные цветовые имена CSS, значения RGB или HEX.
Изменение имени агента
Обновите текст заголовка
<h1>в файлеindex.htmlна следующий код:<body> <div id="banner"> <h1><img src="contoso-agent.png"> Contoso agent name</h1> </div> <!-- ... -->Измените текст на любое нужное вам название агента. Вы также можете вставить изображение, но вам может понадобиться стилизовать его, чтобы оно помещалось в раздел заголовка.
Настройка и размещение холста чата (дополнительно)
Вы можете подключить свой агент Copilot Studio к пользовательскому холсту, который размещается как отдельное веб-приложение. Этот вариант лучше всего работает, если вам нужно встроить настроенный iFrame на несколько веб-страниц.
Note
Размещение пользовательского холста требует разработки программного обеспечения. Это руководство предназначено для опытных ИТ-специалистов, таких как ИТ-администраторы или разработчики, которые хорошо разбираются в инструментах разработчика, утилитах и интегрированных средах разработки (IDE).
Начните с одного из этих образцов, специально созданных для работы с Copilot Studio:
Полный пакет — это пользовательский холст, способный отображать весь богатый контент из Copilot Studio. Рассмотрим пример.
Расположение и отправка файла — это пользовательский холст, способный получить местоположение пользователя и отправить его агенту Copilot Studio. Рассмотрим пример.
Или попробуйте другие примеры холста веб-чата из Bot Framework.
Как и в случае холста по умолчанию, вы можете использовать styleSetOptions, чтобы настроить пользовательский холст. Все настраиваемые свойства перечислены в defaultStyleOptions.js. Дополнительные сведения о возможностях настройки см. в разделе Настройка веб-чата.
Поддержка настройки соединения в пользовательском холсте
Когда агенту, работающему на стандартном жгуте, требуется пользовательское соединение, чат-холст получает адаптивную карту, требуемую для подключения. Ваш индивидуальный холст должен управлять действием Action.OpenUrlDialog карты. Без этой обработки выбор Connect не открывает окно фокусированного соединения.
Откройте окно соединения
- Зарегистрируйтесь
Action.OpenUrlDialogв рендерере Adaptive Cards и прочитайте егоurlсвойства. Принимайте только абсолютhttp://илиhttps://URL. - Определите, насколько доверен источник назначения, прежде чем открыть его. Доверяйте только источникам, которые вы контролируете или которые ваша команда безопасности проверила и внесла в список разрешений.
- Откройте URL напрямую из выбранного пользователем с
window.open(url, "_blank", "popup")помощью . Открытие окна через действие пользователя снижает вероятность того, что браузер его заблокирует. - Для доверенного назначения в аргументе
window.open, опускайтеnoopenerиnoreferrerпоэтому окно соединения может вернуть результат вwindow.opener.windowFeaturesДля любого другого направления используйтеnoopener,noreferrerи не принимайте ответное сообщение. - Сохраняйте возвращённую
Windowссылку и идентификатор активности карты, требуемой для подключения. Если всплывающее окно заблокировано или пользователь закрывает его без корректного результата, оставьте Continue или другое действие восстановления. Не воспринимайте закрытие окна как успешную установку соединения.
Adaptive Cards JavaScript SDK по умолчанию не реализуетAction.OpenUrlDialog. Регистрируйте действие через SerializationContext.actionRegistry, или обрабатывайте его напрямую в вашем рендерере.
Action.OpenUrl Резервный вариант может открыть пункт назначения в клиентах, которые не поддерживают диалоговое действие, но резервный вариант не может вернуть всплывающий результат.
Important
Окно подключения с доступом window.opener может перемещаться или как-то влиять на страницу чата. Проверьте пункт назначения и его перенаправления вместе с вашей командой по веб-безопасности. Не позволяйте доверенному адресу перенаправлять на ненадёжный сайт, сохраняя при этом доступ к открывающему устройству.
Если встроить Bot Framework Веб-чат, его Action.OpenUrlDialog обработка открывает окно подключения. Окна одного происхождения по умолчанию доверяются. Для проверенного пункта styleOptions.callURLActionTrustedOrigin назначения, установленного на разрешённый пункт отправления. Разделяйте несколько происхождений запятыми. Вы также можете установить callURLActionPopupWindowHeight и callURLActionPopupWindowWidth. Не добавляйте происхождение, которое вы не просматривали.
Продолжить после успешной установки соединения (предварительный просмотр)
[Этот раздел содержит предварительную версию документации и может быть изменен.]
Important
Эта статья содержит документацию по предварительной версии Microsoft Copilot Studio и может быть изменена.
Предварительные версии функций не предназначены для использования в рабочей среде и могут иметь ограниченные функциональные возможности. Они доступны перед официальным выпуском, чтобы вы могли досрочно получить доступ и предоставить отзывы.
Если вы создаете агент, готовый для рабочей среды, см. Обзор Microsoft Copilot Studio.
Доверенное окно соединения может отправить результат завершения на страницу чата с .window.opener.postMessage Используйте точное происхождение страницы чата как целевой источник, а не *.
В чате:
Если
window.openсообщение вернутоnull, не принимайте сообщение при такой попытке. В противном случае принимайте сообщение только тогда, когдаevent.sourceоно совпадает с сохраненным всплывающим окном иevent.originсоответствует ожидаемому источнику.Проверьте, что данные сообщения имеют
type: "postback"значение в форме, ожидаемой вашим агентом или временем выполнения.Следующий пример отправляет агенту сообщение с текстом «hello-world». В интерфейсе чата это не видно.
{ "type": "postback", "value": { hello: "World!" } }Следующий пример отправляет агенту сообщение с JSON
{ hello: "World!" }.{ "type": "postback", "value": { hello: "World!" } }Отправьте принятое значение через механизм обратной связи Bot Framework. Используйте сохранённый идентификатор активности как
replyToId; не принимайте ID активности ответа из всплывающего окна.Принимайте максимум один результат для каждого всплывающего окна. Удалите слушатель событий и очистите его таймер после принятия результата, отклонения искажённого сообщения из доверенного всплывающего окна, обнаружения закрытия всплывающего окна или достижения временного лимита. Веб-чат имеет пятиминутный лимит.
Координируйте с агентом или runtime, чтобы сопоставить постбэк с исходным взаимодействием, требуемым соединениям, и возобновить этот ход ровно один раз.
Лучшее усилие — это браузерные сообщения. Блокировщики всплывающих окон, навигация, политика кросс-ориджинов или закрытое окно могут препятствовать автоматическому продолжению. Оставьте Continue или другой путь восстановления доступным и не воспринимайте пропущенное сообщение как успех.
Развертывание настроенного холста
Чтобы разместить свой пользовательский холст, разверните все файлы в веб-приложении.