Как отслеживать историю действий пользователя или историю событий по объекту системы

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

Это может быть заказ в системе, действия определенного лица, или события связанные с активностью лиц определенного отдела. 

Как организовать сбор данных и их вывод для анализа? 

Решение: 

1. Все данные храним в таблицах логов по определенным объектам со ссылками на пользователя, связанные объекты (например, заказ). Таких таблиц может быть много. Суть в том, чтобы сохранить факт действия в структурированном виде с нужными связями по данным. 

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

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

Таблицы логов заполняются в SaveItem формы, при смене статусов сущности (as-entities), операциях таблицы, поиск или любых других местах в коде.

2. Создаем таблицу, на входе будет код сущности и ее itemID. Это может быть человек в системе, заказ в системе или что-то еще. 

Таблица имеет всегда единую структуру: 

  • id  - идентификатор события (если используется универсальная структура, то это что-то вроде human_ivanov, order_123)
  • created - дата, время события и сколько времени прошло с этого момента 
  • type - тип это иконка с указанием цвета. Иконка задает тип события - для человека это может быть Занесение времени в таймлог, Смена статуса задачи, Вход-Выход, Создание задачи  т.д.
  • username - это пользователь, с которым связано данное действие. Например, для заказа это может быть тот, кто создал заказ, кто подтвердил заказ и т.д.

3. В рамках самой процедуры построения заказа на входе мы имеем временную таблицу со единой структурой, которая затем выводится по стандартной обработке. 

CREATE TABLE #actionLog ( id nvarchar(64) primary key,
    username nvarchar(128), title nvarchar(256), text nvarchar(max),
    created datetime, typeCode nvarchar(64), itemID int, color nvarchar(20),
    icon nvarchar(32), iconColor nvarchar(20) )
  • id - идентификатор действия
  • username - cвязанное действие
  • title, text - описание события
  • created - когда было событие
  • typeCode - код типа события (например newTicket)
  • itemID - ID связанной сущности (например ticketID)
  • color - маркет цвета у названия (например #f00)
  • icon - иконка Font Awesome (например fa fa-bars)
  • iconColor - цвет иконки (#f00)

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

4. Сниппет таблицы: 

<a href="#" class="as-table-modal" data-code="actionLog" data-itemid="human_5017" data-big="1" title="Лог по пользователю" data-title="Лог по пользователю">
   <i class="fa fa-clock"></i>
</a>

human_5017 - говорит нам о том, что это будет лог по человеку с ID=5017, данный параметр должен быть обработан в самой процедуре, а также проверены права пользователя на возможность просмотра этих данных. 

Полный вариант процедуры: 

CREATE PROCEDURE [dbo].[crud_actionLog_getItems]
	@filters CRUDFilterParameter READONLY,
	@sort sql_variant,
	@direction nvarchar(8),
	@page int,
	@pageSize int,
	@username nvarchar(32)
AS
BEGIN
	declare @minDate datetime = dateadd(day, -7, getdate())
    declare @us nvarchar(128) = '', @type nvarchar(20), @itemID int

    -- filters...
	declare @filterTitle nvarchar(128)
	select @filterTitle = Value from @filters where [Key] = 'title'

    declare @filterDate nvarchar(128),@createdFrom date = NULL, @createdTo date = NULL
	select @filterDate = Value from @filters where [Key] = 'created'
	select @createdFrom = min(try_convert(date,value,104)) from split(@filterDate, '-')
	select @createdTo = max(try_convert(date,value,104)) from split(@filterDate, '-')


    declare @filterItemID nvarchar(128)
	select @filterItemID = Value from @filters where [Key] = 'itemID'

    set @type = dbo.str_splitPart(@filterItemID, '_',1)
    set @itemID = try_cast(dbo.str_splitPart(@filterItemID, '_',2) as int)

    IF OBJECT_ID('tempdb..#actionLog') IS NOT NULL begin
   		DROP TABLE #actionLog
	end
	CREATE TABLE #actionLog ( id nvarchar(64) primary key, username nvarchar(128), title nvarchar(256), text nvarchar(max),
                             created datetime, typeCode nvarchar(64), itemID int, color nvarchar(20),
                             icon nvarchar(32), iconColor nvarchar(20) )


    -- извлекаем данные для таблицы
    if(@type='human') begin
    	select @us  = username from hr_humans where id = @itemID
    	-- createTicket
        insert into #actionLog
        select top 100 'createTicket_' + cast(id as nvarchar) id,
        	createdBy username,
        	'Создал задачу #' + cast(id as nvarchar) +  ' ' + name +
            	' (' + (select top 1 name from tt_projects where id = t.projectID)+ ')' title,
            name text,
            createdDate created, 'createTicket' typeCode, id itemID, '' color, 'fas fa-ticket-alt' icon, '' iconColor
        from tt_tickets t
        where createdDate > @minDate and createdBy = @us
		order by id desc

    end

	-- SELECT 1 - выходной результат
    select * from (
        select top 1000
      		created hide_created,
            isnull([id], '') [id],
            isnull([username], '') [username],

            isnull([title], '') [title],
            iif(len(color)>0, color, '') marker_title,
            isnull([text], '') [desc_title],
            isnull(convert(nvarchar(10),[created], 104), '') + ''+convert(nvarchar(5), [created], 108) +'' [created],
            dbo.as_timeDelay(datediff(minute, created, getdate())) + ' назад' desc_created,
             iif(len(icon)>0, '0, ' style="color: '+iconColor+'" ', '' )+'>', '')  [type]
        from #actionLog
        where (@filterTitle is null or @filterTitle ='' or title like '%'+@filterTitle+'%'  or [text] like '%'+@filterTitle+'%')
            --and (@createdFrom is null or @createdTo is null  or (created  between @createdFrom and @createdTo))
        order by  created desc
    )t1
	order by  hide_created desc
	OFFSET @PageSize * (@Page - 1) ROWS
	FETCH NEXT @PageSize ROWS ONLY;

	-- SELECT 2
	select count(*) from #actionLog

	-- SELECT 3
    select 1 Compact, '12px' FontSize, 'light' theme, 1 HideTitleCount

	/*Select  '' Title,
		'' ToolbarAdditional,
		'' GroupOperationsToolbar,
		'' EmptyText,
		'' FastCreateLinkText, '' FastCreateDialogHeader, '' FastCreateDialogPlaceholder,
		0 FastCreateSearch, 0 FastCreateTextarea,
		 0 HideTitleCount,
		 0 DisableCellTitle,
		 '10px' FontSize,
		 '{filterCode}' FilterMakeup,
		 1 InstantFilter,
		   */

	-- 4 SELECT Footer data or kanban/gantt data

	drop table #actionLog
END

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

Falcon Space - функциональная веб-платформа разработки на узком стеке MS SQL/Bootstrap. Вводная по Falcon Space
Насколько полезной была статья?

Google поиск по нашей документации

Выгода от использования Falcon Space

В 2-3 раза экономнее и быстрее, чем заказная разработка
Более гибкая, чем коробочные решения и облачные сервисы
Используйте готовые решения и изменяйте под свои потребности
Нужна бесплатная консультация?
Планируете делать веб-проект?
Сайт использует Cookie. Правила конфиденциальности OK