В стандартном GLPI нет журнала прочтений: история заявки хранит то, что изменилось, но никогда — кто просто открыл и прочитал. В сопровождении клиентских инсталляций GLPI это выливается в классический тупик «специалист даже не посмотрел заявку» против «нет, я читал» — и без объективных данных это слово одного против слова другого. Бесплатный модуль Ticket Tracker закрывает этот пробел, регистрируя каждый просмотр заявки. В этом руководстве показано, как он записывает данные, как настроить его, не раздувая счётчики, и три SQL-запроса, которые сразу отвечают на вопрос «кто что прочитал».
Почему GLPI не знает, кто прочитал заявку
Встроенная история (glpi_logs) фиксирует только изменения: создание, смену статуса, новый комментарий, смену специалиста. Открытие формы и чтение не меняют ни одного поля, поэтому никакой строки не появляется. В ядре GLPI нет события «просмотр». Ticket Tracker решает это, подключаясь к моменту отрисовки формы заявки (хук postShowItem у Ticket): каждый раз, когда аутентифицированный сеанс отображает заявку, модуль записывает просмотр. Без ручных действий и без новых полей в форме.
Два уровня записи: сводка и журнал
Модуль пишет в две таблицы с разным назначением. Сводная отвечает на вопрос «сколько раз и когда»; журнальная — «каждое обращение по отдельности»:
-- Summary per (ticket, user): one row, updated on each access.
CREATE TABLE `glpi_plugin_nextool_tickettracker_views` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`tickets_id` int unsigned NOT NULL,
`users_id` int unsigned NOT NULL,
`view_count` int unsigned NOT NULL DEFAULT 1,
`first_view` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_view` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_ticket_user` (`tickets_id`, `users_id`)
);
-- Detailed log: one row per individual access.
CREATE TABLE `glpi_plugin_nextool_tickettracker_viewlog` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`tickets_id` int unsigned NOT NULL,
`users_id` int unsigned NOT NULL,
`view_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
Ключ UNIQUE (tickets_id, users_id) — сердце сводной таблицы: у каждой пары заявка/пользователь ровно одна строка. Запись выполняется через INSERT ... ON DUPLICATE KEY UPDATE view_count = view_count + 1 — атомарный upsert: два одновременных обращения одного пользователя не создают дублирующую строку и не теряют счёт. Вкладка «Просмотры» в заявке читает сводку (таблица со всеми просмотревшими, счётчиком, первым и последним прочтением) и предлагает раскрывающийся список, который подтягивает из журнала каждое отдельное обращение с датой и временем.
Включение и чек-лист настройки
Модуль бесплатный и включается в каталоге NexTool. После активации настройки находятся в Модули > Ticket Tracker, вкладка Функциональность:
- Модуль активен — тот же переключатель, что на странице Модулей. Если выключен, ничего не отслеживается.
- Отслеживание активно (tracking_enabled) — включает запись просмотров. Может быть включено при скрытой вкладке, если вы хотите собирать данные, не показывая их.
- Показывать вкладку в заявке (show_tab_on_ticket) — показывает или скрывает вкладку «Просмотры» в форме заявки.
- Минимальный интервал (с) (min_interval_seconds, по умолчанию 60) — окно debounce: обращения одного пользователя к одной заявке в пределах этого интервала считаются одним.
- Игнорируемые (вкладка Дополнительные права) — пользователи, профили или группы, чьи просмотры не отслеживаются. Если всё пусто — учитываются все обращения.
Ошибка настройки, которая раздувает (или обнуляет) счётчики
Частая ошибка — обнулить минимальный интервал в расчёте на то, что «чем детальнее, тем лучше». Хук срабатывает при каждой отрисовке формы — в том числе при перезагрузках, возврате назад и повторном открытии вкладки. При min_interval_seconds = 0 специалист, который держит заявку открытой и трижды нажимает F5, превращается в «три прочтения», и view_count теряет смысл «сколько раз он действительно возвращался к вопросу». Значение по умолчанию 60 секунд существует именно для того, чтобы схлопнуть серию перезагрузок в одно прочтение. Используйте 0 только для разовой диагностики и затем вернитесь к значению по умолчанию.
Вторая ошибка тоньше, и мы столкнулись с ней у клиента: до версии модуля 1.2.0 запись зависела от права видеть вкладку «Просмотры» — то есть учитывались только административные профили. Инициатор и наблюдатели открывали заявку, и ничего не фиксировалось, поэтому база недоучитывала как раз тех, кто важнее всего в споре об SLA. Мы отвязали запись от права видеть вкладку: сейчас учитывается любой аутентифицированный сеанс, отрисовавший заявку, — инициатор, наблюдатель или специалист — независимо от профиля. Если у вас более ранняя версия, обновитесь, прежде чем доверять цифрам.
Матрица решений: интервал и игнорируемые по сценариям
Правильная настройка зависит от того, что вы хотите доказать. Матрица, которую мы используем при проектировании:
| Сценарий эксплуатации | Отслеживание | Минимальный интервал (с) | Кого добавить в «игнорируемые» |
|---|---|---|---|
| Аудит прочтений / SLA (по умолчанию) | Включено | 60 | Никого |
| Инсталляция с автообновлением или настенной панелью | Включено | 180–300 | Интеграционные учётные записи / роботы |
| Контроль, который не должен раздувать счётчик | Включено | 60 | Профиль руководителей / аудиторов |
| Разовая диагностика (считать каждое обращение) | Включено | 0 (временно) | Никого |
Три SQL-запроса, которые отвечают сразу
Вкладка решает вопрос по отдельной заявке; для картины по всей инсталляции идите прямо в базу. Открытые назначенные заявки, которые ответственный специалист ещё не открывал (type = 2 в glpi_tickets_users — назначенный специалист):
-- Open assigned tickets the responsible technician has NEVER viewed.
SELECT t.id AS ticket, t.name AS title, u.name AS technician, t.date AS opened_at
FROM glpi_tickets t
JOIN glpi_tickets_users tu ON tu.tickets_id = t.id AND tu.type = 2
JOIN glpi_users u ON u.id = tu.users_id
LEFT JOIN glpi_plugin_nextool_tickettracker_views v
ON v.tickets_id = t.id AND v.users_id = tu.users_id
WHERE t.is_deleted = 0
AND t.status IN (1, 2, 3, 4) -- new, assigned, planned, pending
AND v.id IS NULL -- no read logged by the technician
ORDER BY t.date ASC;
Задержка прочтения — сколько минут заявка была открыта до первого прочтения назначенным специалистом. Эта метрика предшествует первому ответу и часто объясняет нарушенный SLA:
-- Minutes between opening and the 1st read by the assigned technician.
SELECT t.id AS ticket,
TIMESTAMPDIFF(MINUTE, t.date, v.first_view) AS minutes_to_first_read
FROM glpi_tickets t
JOIN glpi_tickets_users tu ON tu.tickets_id = t.id AND tu.type = 2
JOIN glpi_plugin_nextool_tickettracker_views v
ON v.tickets_id = t.id AND v.users_id = tu.users_id
WHERE t.is_deleted = 0
ORDER BY minutes_to_first_read DESC;
Самые активные просматривающие конкретной заявки, из сводки, — чтобы понять, кто действительно следит за ней (замените 12345 на ID заявки):
-- Who opened ticket 12345 the most, from most recurrent to least.
SELECT u.name AS username, v.view_count, v.first_view, v.last_view
FROM glpi_plugin_nextool_tickettracker_views v
JOIN glpi_users u ON u.id = v.users_id
WHERE v.tickets_id = 12345
ORDER BY v.view_count DESC;
Прочтение — не ответ: что доказывает счётчик
Данные мощные, но у них есть честное ограничение: они доказывают, что форма была отрисована для этого пользователя, а не что человек внимательно прочитал или что-то сделал. Высокий view_count без комментариев — жёлтый сигнал: кто-то открывает и закрывает, не решая. Заявка с нулём просмотров у ответственного при идущем SLA — красный сигнал: никто даже не посмотрел. В сопровождении реальная ценность не в слежке за специалистами, а в закрытии доказательного пробела: когда клиент спрашивает «почему эта заявка простояла три дня?», ответ перестаёт быть мнением и получает отметку даты и времени.
Нужна реальная прозрачность работы службы поддержки в вашем GLPI, с правильными модулями, включёнными и настроенными под ваш процесс? Узнайте о сопровождении GLPI от NexTool.
Проверено командой NexTool Solutions.