Глава 12. Бронирование переговорных и Workflow

К этому моменту Вы уже хорошо знакомы с NocoBase.

В этой главе мы вместе реализуем особый сценарий: модуль управления совещаниями.

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


12.1 Проектирование структуры таблиц

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

12.1.1 Таблица переговорных

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

Пример структуры таблицы
Переговорные (Rooms)
    ID (первичный ключ)
    Название переговорной (name, однострочный текст)
    Расположение (location, многострочный текст)
    Вместимость (capacity, целое число)
    Оснащение (equipment, многострочный текст)

12.1.2 Таблица бронирований

Таблица бронирований хранит информацию о всех записях на совещания: переговорная, участники, временной интервал, тема совещания и описание.

Пример структуры таблицы
Бронирования (Bookings)
    ID (целое число, уникальный первичный ключ)
    Переговорная (room, многие к одному, внешний ключ room_id связан с ID переговорной)
    Пользователи (users, многие ко многим, связь с ID пользователя)
    Время начала (start_time, дата и время)
    Время окончания (end_time, дата и время)
    Заголовок совещания (title, однострочный текст)
    Описание совещания (description, Markdown)
Связь «многие ко многим»

В таблице бронирований используется связь «многие ко многим»: один пользователь может участвовать во многих совещаниях, а в одном совещании может участвовать много пользователей. Здесь нужно правильно настроить связь по внешнему ключу. Для удобства можно назвать промежуточную таблицу booking_users.


12.2 Создание модуля управления совещаниями

После проектирования структуры таблиц можно создать обе таблицы согласно проекту и собрать модуль «Управление совещаниями». Шаги создания и настройки:

12.2.1 Создание блока таблицы

Сначала добавьте на страницу модуль «Управление совещаниями», создайте отдельные блок таблицы переговорных и блок таблицы бронирований (таблица). Затем добавьте блок календаря для таблицы бронирований и установите вид по умолчанию «День».

Связывание блока таблицы переговорных

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

Связывание блоков NocoBase (рекомендуется!)

Помимо ранее использованных блоков фильтра, блок таблицы тоже можно связывать с другими блоками — для фильтрации по клику.

Как показано ниже, в настройках таблицы переговорных свяжите два других блока бронирований (блок таблицы бронирований и блок календаря бронирований).

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


12.3 Проверка занятости переговорной

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

12.3.1 Настройка workflow «Событие до операции»

Для проверки во время бронирования используем особый тип workflow — «Событие до операции»:

  • Событие до операции (коммерческий plugin): выполняет последовательность операций перед созданием, изменением или удалением данных, может в любой момент остановить выполнение и заранее перехватить операцию. Этот подход очень близок к привычному процессу разработки!

12.3.2 Настройка узлов

В workflow проверки занятости нам понадобятся узлы следующих типов:


12.3.3 Привязка к таблице бронирований и настройка триггера

Привяжите workflow к таблице бронирований, выберите режим триггера «Глобальный режим» и установите типы операций — создание и обновление записи.


12.4 Настройка узла вычислений

12.4.1 Создание узла «Преобразование пустого ID в -1»

Сначала создадим узел вычислений, который будет преобразовывать пустой ID в -1. Узел вычислений может преобразовывать переменные нужным нам способом и поддерживает три формы операций:

  • Math.js (см. Math.js)
  • Formula.js (см. Formula.js)
  • Шаблон строк (для конкатенации данных)

Используем Formula.js для проверки числа:

IF(NUMBERVALUE(【Переменная триггера/Параметры/Объект отправленных значений/ID】, '', '.'),【Переменная триггера/Параметры/Объект отправленных значений/ID】, -1)


12.5. Создание узла SQL-операции

Затем создаём узел SQL-операции, выполняющий запрос для поиска свободных переговорных:

12.5.1 SQL-запрос для поиска свободных переговорных

-- Запрос всех переговорных, доступных для бронирования
SELECT r.id, r.name
FROM rooms r
LEFT JOIN bookings b ON r.id = b.room_id
  AND b.id <> {{$jobsMapByNodeKey.3a0lsms6tgg}}  -- исключаем текущее бронирование
  AND b.start_time < '{{$context.params.values.end_time}}' -- время начала меньше конца запрашиваемого интервала
  AND b.end_time > '{{$context.params.values.start_time}}' -- время окончания больше начала запрашиваемого интервала
WHERE b.id IS NULL;

Внимание по SQL: переменные подставляются прямо в SQL, проверяйте их внимательно во избежание SQL-инъекций. Не забывайте про одинарные кавычки в нужных местах.

Переменные:

{{$jobsMapByNodeKey.3a0lsms6tgg}} — результат предыдущего узла, 【Данные узла / Преобразование пустого ID в -1】

{{$context.params.values.end_time}} — 【Переменная триггера/Параметры/Объект отправленных значений/Время окончания】

{{$context.params.values.start_time}} — 【Переменная триггера/Параметры/Объект отправленных значений/Время начала】

12.5.2 Тестирование SQL

Цель — найти все переговорные, не конфликтующие с заданным интервалом времени.

Можно нажать кнопку «Test run» внизу, изменить значения переменных и отладить SQL.


12.6 Парсинг JSON

12.6.1 Настройка узла парсинга JSON

После теста на предыдущем шаге результат имеет такой вид. Для его обработки нужно включить plugin JSON query node:

[
  {
    "id": 2,
    "name": "Переговорная 2"
  },
  {
    "id": 1,
    "name": "Переговорная 1"
  }
]

Доступны три способа разбора JSON: JMESPath JSON Path Plus JSONata

Здесь выбираем любой, например [JMESPath]. Нам нужен список названий доступных переговорных, поэтому пишем:

[].name

Привязка свойств выполняется для списков объектов, в данном случае она необязательна.

12.7 Условное ветвление

Настройте узел условного ветвления, чтобы определить, входит ли текущая переговорная в список доступных. В зависимости от результата (да или нет) сконфигурируем разные сообщения-ответы.

В качестве условия выберем «базовое» вычисление:

【Данные узла / Список доступных переговорных】 содержит 【Переменная триггера / Параметры / Объект отправленных значений / Переговорная / Название】

12.7.1 Да: настройка сообщения об успехе

Здесь нужно включить plugin Workflow: Response message:

【Переменная триггера/Параметры/Объект отправленных значений/Переговорная/Название】 свободна, бронирование выполнено успешно!

12.7.2 Нет: настройка сообщения об ошибке

Целевая переговорная недоступна, список доступных переговорных: 【Данные узла/Список доступных переговорных】

Внимание: при отрицательном результате обязательно добавьте узел «Завершить процесс», чтобы вручную остановить выполнение.

202411170606321731794792.png


12.8 Проверка работы и пошаговая отладка

Перейдём к финальному тестированию системы управления совещаниями. Цель — убедиться, что workflow корректно обнаруживает конфликты бронирования и блокирует их.

12.8.1 Бронирование с конфликтным интервалом

Сначала попробуем добавить бронирование, время которого пересекается с уже существующими. Посмотрим, заблокирует ли система операцию и покажет ли ошибку.

  • Установим конфликтный временной интервал

Попробуем добавить новое бронирование в «Переговорную 1» на интервал

2024-11-14 00:00:00 — 2024-11-14 23:00:00

Этот интервал охватывает весь день — мы намеренно создаём конфликт с уже существующими бронированиями.

  • Существующие бронирования

В «Переговорной 1» уже есть два интервала:

  1. 2024-11-14 09:00:00 — 2024-11-14 12:00:00
  2. 2024-11-14 14:00:00 — 2024-11-14 16:30:00

Оба пересекаются с интервалом

(2024-11-14 00:00:00 — 2024-11-14 23:00:00).

Поэтому система должна обнаружить конфликт и заблокировать бронирование.

  • Отправка бронирования и проверка реакции

Нажимаем кнопку Отправить — система выполняет workflow проверки:

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


12.8.2 Бронирование без конфликтов

Теперь протестируем сценарий без конфликтов.

Убедимся, что когда времена не пересекаются, бронирование переговорной выполняется успешно.

  • Выбираем непересекающийся интервал

Например,

2024-11-10 16:00:00 — 2024-11-10 17:00:00.

Этот интервал не пересекается ни с одним существующим бронированием и удовлетворяет условиям.

  • Отправляем бронирование

Нажимаем кнопку Отправить — система снова выполняет логику проверки workflow:

Проверим вместе: отправка успешна! Появляется сообщение «Бронирование выполнено». Это подтверждает, что без конфликтов функция тоже работает правильно.

12.8.3 Изменение времени существующего бронирования

Помимо создания новых бронирований Вы можете протестировать изменение времени уже существующих.

Например, измените время существующего совещания на другой непересекающийся интервал и снова отправьте.

Этот шаг оставляем Вам.


12.9 Доработка дашборда и панель личного расписания

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

12.9.1 Корректировка раскладки дашборда

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

Для дополнительного удобства можно создать каждому пользователю собственную панель совещаний. Конкретные шаги:

  1. Создать блок «Личное расписание»: добавьте на дашборд новый блок календаря или списка для отображения личных совещаний пользователя.
  2. Установить значение участника по умолчанию: задайте значение по умолчанию равным текущему пользователю, чтобы при открытии дашборда он сразу видел свои совещания.

Это улучшает опыт работы с модулем управления совещаниями.

После выполнения этих настроек дашборд становится нагляднее и удобнее, а функциональность — заметно богаче!

С помощью описанных шагов мы успешно реализовали и оптимизировали основные функции модуля управления совещаниями! Надеемся, что в процессе работы Вы постепенно освоите ключевые возможности NocoBase и почувствуете удовольствие от модульного построения систем.


Продолжайте исследовать и проявляйте творческий подход! Если столкнётесь с трудностями, всегда обращайтесь к официальной документации NocoBase или к сообществу NocoBase для обсуждения.