Очень удобно иметь некий отчет, в котором есть все действия в хронологическом порядке, связанные с определенным объектом или субъектом.
Это может быть заказ в системе, действия определенного лица, или события связанные с активностью лиц определенного отдела.
Как организовать сбор данных и их вывод для анализа?
Решение:
1. Все данные храним в таблицах логов по определенным объектам со ссылками на пользователя, связанные объекты (например, заказ). Таких таблиц может быть много. Суть в том, чтобы сохранить факт действия в структурированном виде с нужными связями по данным.
Не нужно пытаться сохранять (с дублированием) в лог конкретного человека. Это негибко, сложно менять и приводит к избытку информации - данные по сути приходится дублировать для разных типов логов.
Обычно таблица подобного журнала будет иметь следующие поля - дата, кто создал, статус, примечание.
Таблицы логов заполняются в SaveItem формы, при смене статусов сущности (as-entities), операциях таблицы, поиск или любых других местах в коде.
2. Создаем таблицу, на входе будет код сущности и ее itemID. Это может быть человек в системе, заказ в системе или что-то еще.
Таблица имеет всегда единую структуру:
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) )
Таким образом, основная задача заключается в наполнении этой временной таблицы данными из разных таблиц логов, которая затем и выводится пользователю.
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
Таким образом, можно собирать данные из разных разрозненных таблиц логов и выводить их в формате единой истории по определенному объекту системы.