Перейти к основному контенту

Контакт Центр. Дополнения

https://pm.metarex.ru/issues/8192

здесь описаны новые изменения по КЦ, их нужно будет не публиковать отдельной страницей документации, а внести в имеющуюся страницу по контакт центру, а отдельную - это уже можно будет сформулировать новость по релизу

ps: документацию нужно будет существенно корректировать, нужно будет все переформулировать и перестроить структуру документа, данный же документ необходим для тестирования и понимания нового функционала.


image.png

contact-center-improverments-1.png


1.  Информационная панель.

Здесь выводятся все основные данные по лиду.

Email и телефон выводятся на основе атрибутов лида sys_email и sys_phone

Аватар и имя лида кликабельны, при нажатии открывается страница админ панели с сообщениями по лиду, на которой можно отредактировать лид.


2. Кликабельная шапка лида.

Открывает / Скрывает информационную панель по лиду

На PC: По умолчанию информационная панель по лиду автоматически открывается при смене лида. Но если ее закрыть, то при открытии другого лида она также останется свернутой. Т.е. состояние панели запоминается (как в Telegram)

На мобильном устройстве панель открывается на весь экран, при открытии страницы с сообщениями лида панель всегда свернута. Для открытия всегда нужно нажимать на шапку лида.


3. Фильтр лидов по имени (как в Telegram, но пока без поиска по содержимому самих сообщений).

Ищется только совпадение указанного текста в имени (ID в поиске не участвует)

При поиске по имени (как и при поиске по любому другому параметру) активная панель автоматически переключается на "Поиск", а панель "Все" скрывается.

После очистки всех параметров поиска, панель "Все" будет возвращена, а панель "Поиск" скрыта.

ps: при нажатии на написать письмо можно сделать выбор шаблона и отправку письмо по SMTP, но это не имеет смысла, тк обратное письмо мы не получим, тут лучше рассмотреть вариант интеграции с Хэлп Деском. Можно даже рассмотреть вариант, чтобы открытая страница Лида имела несколько вкладок, например: Сообщения, Письма (отобржать IFRAME стороннего хэлп дэска), Заявки (отображать IFRAME сторонней CRM или наши Тикеты), Звонки (отображать IFRAME стороннего колл центра).


4. Расширенный поиск лидов.

При нажатии на кнопку подписанную как "4" на первом скрине откроется форма, на которой можно указать дополнительные параметры поиска и отредактировать текущий фильтр.

image.png

Эту же форму можно открыть нажав на область с выводом текущих, примененных фильтров для поиска лидов, т.е. на любую область с подписью "Результаты поиска", за исключением нажатия на крестики. Эти крестики необходимы для сброса всех параметров (крестиком в правой части) поиск или сброса поиска по конкретному параметру (крестиком слева от названия параметра)


image.png


 Возвращаемся к форме расширенного поиска

image.png

Поиск по ID - можно искать точным соответствием (по умолчанию) или вхождением указанного числа в ID (если представить ID лида в виде строки). Для регулирования точного совпадения / вхождения - отдельная галка 

Поиск по имени - вхождение указанного текста в имени Лидов

Поиск по тэгам - поиск лидов по вхождению указанных сроки (через запятую) в имена тэго (т.е. не точное соответсвие имени тэга, а вхождение указанных строк в имена тэгов). Здесь можно указывать несколько тэгов. 

Условие соединения тэгов указывается в отдельном поле ниже.

Доступно 2 варианта 

- или (по умолчанию)

это значит что будет выполнен поиск лидов у которых есть любой из указанных тэгов

- и

это значит что будет выполнен поиск лидов у которых есть все указанные тэги

Кнопки формы - Сбросить (идентична крестику сброса фильтра в  блоке с заголовком "Результаты поиска")


Т.е. пока есть 3 критерия поиска по ID, по Имени, по Тэгам. Эти три группы в будущем можно будет визуально выделить рамкой на форме, чтобы было понятно что галка - точное совпадение относистя к ID, а выподающий список к поиску по тэгам.

В дальнейшем сюда могут быть добавлены другие необходимые фильтры и параметры, например:


Фильтр по

Бот, Канал, Мессенджер
Галка - Передан Оператору
Галка - Отключена реакция бота (is_mute)
Дата создания
Последняя активность
Последнее входящее сообщение
По дате последнего сообщения оператора

Сортировать по Дате создания / Последней активности / Дате посл вх сообщения / Дате посл сообщ оператора

можно добавить все поля которые есть на странице лидов


5. Панель результатов поиска

Суть панели описана выше (о подмене панелей "Все" на "Поиск" при выполнении фильтрации). В документации можно не выделять отдельный раздел для нее.

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


6. Цветовая индикация лидов.

Цветовая индикация лидов была переработана, чтобы лиды требующие реакции, не выглядели как светофор.

Подсвечивается теперь только левая часть лида с аватаром, а правая только если лид активен, т.е. когда открыли страницу по лиду.

В основном это сделано, тк на  разноцветных плашках было сложно чтото читать и теперь туда добавлено отображение последнее сообщение лида, прочесть которое было довольно сложно.


7. URL 

Этот пункт в документации не нужен

Теперь в URL отражены параметры текущей, открытой страницы лида и все примененные фильтры расширенного поиска лидов:


- show:

текущий открытий Лид, что позволяет обновлять страницу и возвращаться к текущему лиду (а также решает проблему сброса открытого лида, при изменении размера страницы КЦ на PC)

show, это скрытый фильтр по ID, который при старте мессенджера запускает следующий алгоритм:

  • ждет загрузку текущих вкладок и фильтра
  • ищет лид на вкладках, если есть, кликает на него и открывает сообщения лида
  • если лид не найден на вкладках, то посылает аякс на бэк, ищет лид и добавляет его в начало списка на вкладку Все, кликает на него и открывает сообщения лида

технические детали: здесь было перепробовано множество вариантов, в том числе и использование видимого фильтра по id для текущего открытого лида, но все они конфликтуют по логике, например, открытый лид начинает участвовать как фильтр, необходимо его сбрасывать вручную после обновления страницы (поэтому был добавлен быстрый сброс отдельных параметров примененного фильтра через крестик слева от параметра), либо если есть фильтр по другим параметром и открытая страница лида, то после обновления к фильтру по параметрам добавляется ID лида, что сужает выборку до 1 лида), в общем текущий вариант использования дополнительного параметра show отдельно от видимого фильтра id является самым оптимальным


- id:

для поиска по id.

работает в комбинации с параметров id_eq=0 (для неточного соответствия по ID лида) - про id_eq упоминать в доке не нужно (если все таки будет упоминаться про структуру URL)


- name

имя лида


- tags

тэги перечисленные через запятую


- tags_condition=or/and

условие соединения тэгов



8. Последнее сообщение по лиду

последнее входящее по лиду (текст или нажатая кнопка)

последнее исходящее от оператора

исходящее от бота не выводится, тк не обладает информативностью и будет только мешать

image.png

(PS: последнее сообщение хранится в поле leads.last_message)

9. Индикаторы информирующие об ожидании загрузки

(в документации этот пункт не нужен)

image.png

Анимация отображается при старте КЦ. А также при применении фильтра.

Также были добавлена анимация в подвале при выполнении скроллинга (но она скрыта сейчас), ввиду особенностей скроллинга - почти любе перелистывание списка лидов приводит к этой анимации, тк у нас лиды грузятся не когда достигли конца списка, а начинают грузиться раньше (как в Telegram), чтобы пока ты листаешь вниз, уже была подгружена следующая порция лидов, иначе если грузить только при достижении конца списка, то скроллинг даже 200 лидов занимает очень долгое время.


10. Страница - Настройки КЦ.


image.png

Опции:

10.1. Отправлять сообщение о подключении оператора к диалогу

По умолчанию включена

Это информационное сообщение, отправляемое лиду, о том что Оператор подключился к диалогу, отправляется когда оператор нажимает на кнопку Начать диалог в КЦ. Т.е. это не информирование о переводе на оператора, скрипт перевод на оператора с информацией о том что бот отключен, ожидайте оператора, все равно нужно создавать.
Суть этой опции - жалоба клиента о то что Лиды не понимали с кем общаются и продолжали говорить с оператором, считая что это бот.
Если вывод имени оператора включен, то лиду отправляется сообщение 
Оператор {NAME} подключился к диалогу
Если вывод имени оператора отключен, то
Оператор подключился к диалогу
имя оператора берется из настроек Личного кабинета пользователя (оператора)
10.2. Отправлять сообщение о выходе оператора из диалога
По умолчанию выключена. Не рекомендуется включать если есть бот, тк после отправки этого информационного сообщения будет скрыто меню в виджете, имеет смысл использовать только без бота с скриптами. 
Событие возникает при нажатии оператором на кнопку Выйти из диалогу в КЦ или на выйти и отметить диалог решенным
Примеры отправляемых сообщений:
Если вывод имени оператора включен, то лиду отправляется сообщение 

Оператор {NAME} вышел из диалога


Если вывод имени оператора отключен, то
Оператор вышел из диалога


10.3. Отображать информацию об операторе в начале сообщения

По умолчанию включена
Клеить или нет к каждому исходящему сообщению оператора его имя. Чтобы было понятно кто пишет сообщение бот или оператора.

Если отображение имени оператора включено, то в сообщении лиду выводится
{NAME}: Здраствуйте, чем могу помочь?
если отображение имени отключено, то
Оператор: текст сообщения

имя оператора подгружается из настроек Личного кабинета пользователя (оператора), поэтому необходимо установить имена операторов компактными, без лишних символов, и без никнейма в скобках


10.4. Отображать имя оператора в информационных сообщениях


По умолчанию включена

Опция отображать или нет имя оператора: 

- при подключении оператора к диалогу

-в сообщениях от оператора

-при выходе оператора из диалога


Технические детали (не для докуменатции):

Опции по бизнесу хранятся в новой таблице business_attributes (была такая ранее не использовалась, текущая таблица новая, старая за основу не бралась, также удалена неиспользуемая таблица business_entites на которую ранее ссылалась business_attributes, такая таблица избыточна). Это keyvalue таблицы, primary key по ID, в отличии от user_attributes, user_attributes в дальнейшем будет переработан, тк как оказалось работать с составным PK в Laravel только доп. проблемы, он не заточен на это, плюс проще кэшировать сущности и оперировать с ними по ID.

Все опции по бизнесу кэшируются в Redis для такого чтобы не было проблем нагрузки при работе операторов с КЦ.

Очищаются опции, при сохранении формы Настройки КЦ, а также просто при открытии страницы Настройки КЦ, чтобы данные на форме всегда были актуальны. При работе же оператора с КЦ, эти опиции грузятся из кэша.


11. Отчеты 


11.1. ОТЧЁТ ПО ДИАЛОГАМ ПЕРЕВЕДЕННЫМ НА ОПЕРАТОРОВ

image.png

по всем диалогам лидов, которые переводились на оператора, отчет с пагинацией

доступен экспорт отчета в csv, при экспорте выгружаются все данные, без пагинации


этот отчет идет вторым в списке, но для понимания логики расчетом имеет смысл рассмотреть его первым, тк другой отчет строится на основе него (а этот является второстепенным, который получился при решении задачи по статистике, также возможно для клиентов которые хотят сами анализировать KPI по операторам имеет смысл использовать именно этот отчет, чтобы загружать его в свою систему аналитики и строить отчеты)


Логика построения отчета

- отбираются все диалоги, которые были переведены на оператора (т.е. событие запроса оператора в бота лидом)

- на каждое событие перевода находим первый ответ оператора (причем смотрим чтобы дата ответа оператора была >= даты перевода на оператора)

берем первый ответ оператора, а не нажатие кнопку Начать диалог, тк в таком случае отчет будет некорректен если включено авто распределение диалогов по операторам. Минусы подхода: KPI по первому ответу может сподвигнуть операторов писать короткие первые сообщения, при необходимости можно вывести в отчет - первое сообщение оператора, если это будет критично

- считаем разницу по времени между переводом на оператора и первым сообщением от оператора - это и есть время отклика (далее если получить суммарное время всех заявок оператора и разделить на количество диалогов, то получим среднее время отклика по оператору)

Техническое описание логики работы (вырезано из комментариев к коду, не для документации):

     * 1. Из таблицы botlogs получаем все события перевода на оператора за указанный период
     *  Из botlos записи получаем время создания записи - это время идентично открытию диалона
     * operator_id должен быть NULL указан в данном событии,
     *   иначе это событие приема диалога из КЦ оператором, а не перевод на оператора ботом
     *
     * bot_id IN (...) AND is_event=1 AND bot_event_type_id=60 AND operator_id IS NULL
     *
     * 2. По dialog_id в botlogs ищем первый ответ от оператора.
     * Причем запрос делаем не по каждому диалогу, а с помощью IN dialog_id (список id из п1)
     * Фильтруем события у которых дата < даты перевода на оператора
     *
     * Для статистики по отправке первого сообщения лиду оператором КЦ по данному диалогу:
     * sql для поиска EVENT_TYPE_ON_OPERATOR_MESSAGE = 3:
     * is_event=0 AND bot_event_type_id=3  // AND operator_id IS NOT NULL
     * order by id asc LIMIT 1
     *
     * Если нужна статистика по нажатию на Начать диалог оператором КЦ
     * sql для поиска EVENT_TYPE_ON_OPERATOR_JOINED = 230:
     * is_event=1 AND bot_event_type_id=230 // AND operator_id IS NOT NULL
     * order by id asc LIMIT 1
     * Но такой запрос не выполняется, по причине, что сюда попадают события автоназначения заявки оператору
     * Или события когда оператор подключился к диалогу без перевода на оператора
     *
     * -----
     *
     * Также в csv можно выгрузить сами диалоги
     * Или предоставлять их по апи, доп запросом
     *
     * -----
     *
     * Что можно посчитать дополнительно, помимо выгрузки по каждому диалогу:
     *
     * Статистика по каждому оператору:
     * - Среднее время отклика на диалог
     * - Среднее время общения с оператором
     * - Среднее количество вх/исх сообщений на диалог
     * - Всего диалогов
     * - Диалогов в день
     *
     * TODO: Для отчета можно сделать Флаг:
     *   С какой точки считать начала отлкика на диалог оператором:
     *     -  с момента написания первого сообщения оператором
     *     - с момента нажатия кнопки - Начать общение (подходит для кейсов без автоназначения заявок)
     *    В csv же можно выгружать обе даты
        /*
        SELECT
            --DISTINCT "dialog_id"
          id, dialog_id, bot_id, lead_id, bot_event_type_id, operator_id, created_at
        FROM
            botlogs
        WHERE
          bot_id IN (32,114,763,764,798,812,1031,1039,1040,1042,1043,1045,1046,1047,1067,1068,1069) AND
          is_event=1 AND
          bot_event_type_id=60 AND
          operator_id IS NULL
        ORDER BY
            id ASC
        LIMIT 100
        */

        // 1. Из таблицы botlogs получаем все события перевода на оператора за указанный период
        //    Из botlos записи получаем время создания записи - это время идентично открытию диалона
        // Далее оставляем только первое событие по каждому диалогу из этой выборки
        $botlogsQuery = Botlog
            ::select([
                'botlogs.id',
                'botlogs.dialog_id',
                'botlogs.bot_id',
                'bots.name AS bot_name',
                'botlogs.lead_id',
                'leads.name AS lead_name',
                'botlogs.bot_event_type_id',
                'botlogs.operator_id',
                'botlogs.created_at',
                'dialogs.created_at as dialog_opened_at',
                'dialogs.state_id as current_dialog_state_id',
                'dialogs.updated_at as dialog_closed_at'
            ])
            ->whereIn('botlogs.bot_id', $botsIn)
            ->where('botlogs.is_event', 1)
            ->where('botlogs.bot_event_type_id', BotEventTypeModel::EVENT_TYPE_ON_LEAD_FORWARDED_TO_OPERATOR)
            ->whereNull('botlogs.operator_id')
            ->leftJoin('dialogs', 'dialogs.id', '=', 'botlogs.dialog_id')
            ->leftJoin('bots', 'bots.id', '=', 'botlogs.bot_id')
            ->leftJoin('leads', 'leads.id', '=', 'botlogs.lead_id')
            //::select(['botlogs.dialog_id'])
            //->distinct()
            //->orderBy('botlogs.dialog_id')
            ->orderBy('botlogs.bot_id')
            ->orderBy('botlogs.dialog_id')
            ->orderBy('botlogs.lead_id')
            ->orderBy('botlogs.id')

            //->limit(100) // !!!
        ;
// Данные о всех сообщениях от оператора по каждому из диалогов
$sql = '
    SELECT
        botlogs2.*, users.name AS operator_name
    FROM (
        SELECT
          -- RANK() OVER (PARTITION BY "dialog_id" ORDER BY id ASC) n, 
          id, bot_id, lead_id, operator_id, is_event, 
          dialog_id, bot_event_type_id, 
          operator_outgoing_text, 
          created_at 
        FROM
            botlogs as botlogs1
        WHERE
            bot_id IN (' . implode(',', $botsIn) . ') AND
            dialog_id in (' . implode(',', $dialogIds) . ') AND
            is_event = 0 AND  
            bot_event_type_id = ' . BotEventTypeModel::EVENT_TYPE_ON_OPERATOR_MESSAGE . '
        ORDER BY id ASC
    ) AS botlogs2
    LEFT JOIN users AS users ON users.id = botlogs2.operator_id
    -- WHERE
    --    n = 1
    ORDER BY id ASC
    
    далее
    
Пропускаем событие если такой диалог уже есть в списке.
В отчет пападает только событие первого ответа оператора    
    
исключаем события, дата которых раньше чем дата перевода на оператора
для случаев, когда есть ответы операторов, еще до события перевода
например когда лид сам вернул в бота, не дождавшись оператора и затем опять запросил поддержку оператора




11.2.  ОТЧЁТ ПО АКТИВНОСТИ ОПЕРАТОРОВ

image.png


по всем операторам участвующим в диалогах, отчет без пагинации

в дальнейшем можно вывести всех зарегистрированных операторов бизнеса + по тем кто принимал заявки (на случай если удалили роль у оператора)

доступен экспорт отчета в csv


Отчет строится на основе - отчёта по диалогам переведенным на операторов

Из первого отчета получаем суммарные данные по каждому оператору. Затем суммарное время отклика по оператору делим на количество таких диалогов по оператору, получаем среднее время отклика.


Технические детали (не для документации):

Для формирования отчета необходима информация о всех диалогах за период расчета,  отчет делится на итерации, и на каждой итерации первый отчет проходит 50 диалогов и сразу накапливают суммарную информацию по диалогам оператора, после итерации данные о диалогах удаляются из памяти, остаются только по операторам. Т.е. в теории алгоритм должен нормально обрабатывать большое количество диалогов.

(а при отображении же первого отчета отображается только одна из страницы итерации в 50 диалогов)


12. Слетание сессии

Было запрошено в задаче. Причина почему вылетает сессия не понятна, эксперементировал даже с уменьшением ограничения времени жизни сессии до 1 минуты, но не могу повторить. Причем КЦ выполняет кучу аяксом каждые неск. секунд, каждый из которых продлевает время жизни сессии, в таком случае получается что у оператора мог вылететь интернет на очень долгое время, после чего произошел логаут, тк не было обращений к сайту (что тоже нереалистично). Также возможно при авторизации на сайте не установили галку Запомнить меня (но тестировал также и без этой галки, слетов сессии не наблюдал).

image.png


Решено косвенно - выводом информационного сообщения.

Для тестирования нужно открыть КЦ и страницу с сайтом, на второй странице сделать logout

image.png


13. Звуковые уведомления

Звук, проигрываемый при старте КЦ

https://stage.metabot.dev/media/welcome.mp3

заменен на mp3 в котором заглушена звуковая дорожка

https://stage.metabot.dev/media/empty.mp3

Проигрывание звука необходимо для того чтобы на старте КЦ понять разрешены ли звук уведомления в браузере или нет и вывести инф. окно. 

В документации это отражать не нужно, но нужно убрать из доки пункт, если там сказано о стартовом звуковом уведомлении, тк теперь его не слышно.


14. Убран зеленый кружочек, чтобы не возникало мыслей, что клиент онлайн

image.png 

image.png

15. Добавлена подсветка ссылок в сообщениях

Ссылки теперь подсвечиваются и кликабельные.

image.png

PS: Подстветка выполняется на фронте, при добавлении сообщения в чат, сообщение прогоняется через регулярки и для всех ссылок добавляется html тэг <a href ....   

PS: Другим ключевым моментом необходимым для полноценной работы с КЦ остается добавление поддержки изображений.

Todo (это на будущее): 

кц отображение картинок и ссылок
+ emoji
+ ссылок на прикрепленные файлы, документы, картинки и т.д. (хотя бы для telegram и widget)

также отправка оператором, ссылок, файлов, изображений и emoji

!!! todo
в инфо панели выводить ссылку на sys_current_ticket_id

!!! Автовысота поля отправляемого текста (поле для ввода текста оператором)


16. Поддержка Enter и Escape в Popup

Enter и Esc работают на 2х Popup

1. Стартовое окно где выводится уведомлялка о Выключенном звуке
2. Форма Расш. поиска - Enter - применить фильтр. Esc - отмена (скрыть попап)


17. Смена бота / бизнеса при просмотре переписки по лиду

Добавлена поддержка возможности быстрой смены бота при просмотре переписки по лиду, чтобы можно быстро находить бизнес и бот по лиду. А также передавать ссылки на лид, напримерр при описании бага на платоформе, без указания к какому бизнесу и боту он относится.

image.png


18. Имена каналов в списке лидов и в шапке лида

В списке лидов слева и в шапке лида выводится имя канала и мессендежр, если это не нативный канал, т.е. только для 'jivo','webim','umnico','bitrix'