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

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

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

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

Решение: 

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

Это снижение стоимости владения

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

Это быстрое внесение изменений

по ходу эксплуатации программы. Как создается функционал на платформе

Это простой удобный интерфейс

адаптация под мобильные устройства. Про юзабилити платформы

Нужна бесплатная консультация?
Получить оценку проекта
Создайте концепцию проекта на основе нашего шаблона и получите оценку проекта в виде КП.
Демо-сайт решений
Базисные решения, которые можно гибко адаптировать под себя: менять внешний вид, бизнес-логику и даже структуру базы данных.