feat(api,core,infrastructure): Workload - дополнительная фильтрация по свяанным ЗО и РГ. RedisCacheService - при формирование hash key, дополнительная фильтрация на null, empty.
This commit is contained in:
@@ -415,9 +415,9 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="filterParam">Наименование ЗО или РГ или null</param>
|
||||
/// <returns></returns>
|
||||
public async Task<WorkloadReport?> GetWorkloadReportAsync(WorkloadReportType reportType, DateOnly dateStart, int durationDays, TimeSpan offset, string? filterParam)
|
||||
public async Task<WorkloadReport?> GetWorkloadReportAsync(WorkloadReportType reportType, DateOnly dateStart, int durationDays, TimeSpan offset, string? responseArea, string? workGroup)
|
||||
{
|
||||
var key = GetReportCacheKey(reportType, dateStart, durationDays, offset, filterParam);
|
||||
var key = GetReportCacheKey(reportType, dateStart, durationDays, offset, responseArea, workGroup);
|
||||
|
||||
return await redisCacheService.GetCachedDataAsync<WorkloadReport>(key, true);
|
||||
}
|
||||
@@ -433,9 +433,9 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="filterParam">Наименование ЗО или РГ или null</param>
|
||||
/// <returns></returns>
|
||||
public async Task SetWorkloadReport(WorkloadReport report, WorkloadReportType reportType, DateOnly dateStart, int durationDays, TimeSpan offset, string? filterParam)
|
||||
public async Task SetWorkloadReport(WorkloadReport report, WorkloadReportType reportType, DateOnly dateStart, int durationDays, TimeSpan offset, string? responseArea, string? workGroup)
|
||||
{
|
||||
var key = GetReportCacheKey(reportType, dateStart, durationDays, offset, filterParam);
|
||||
var key = GetReportCacheKey(reportType, dateStart, durationDays, offset, responseArea, workGroup);
|
||||
await redisCacheService.SetCachedDataAsync(key, report, cacheWorkloadTtl, true);
|
||||
}
|
||||
|
||||
@@ -462,10 +462,10 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="filterParam"></param>
|
||||
/// <returns></returns>
|
||||
private string GetReportCacheKey(WorkloadReportType reportType, DateOnly dateStart, int durationDays, TimeSpan offset, string? filterParam = null)
|
||||
private string GetReportCacheKey(WorkloadReportType reportType, DateOnly dateStart, int durationDays, TimeSpan offset, string? responseArea, string? workGroup)
|
||||
{
|
||||
// формируе ключ, вида: основа + дата начала + продолжительность + смещение
|
||||
// Если есть параметр (filterParam), добавляется параметр в виде Hash
|
||||
// Если есть параметр (responseArea, workGroup), добавляется параметр в виде Hash
|
||||
|
||||
var keyList = new List<string>();
|
||||
|
||||
@@ -493,10 +493,10 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
|
||||
var keyStr = string.Empty;
|
||||
|
||||
if (filterParam == null)
|
||||
if (responseArea == null && workGroup == null)
|
||||
keyStr = redisCacheService.GetKey(keyList.ToArray());
|
||||
else
|
||||
keyStr = redisCacheService.GetKey(keyList.ToArray(), new string[] { filterParam });
|
||||
keyStr = redisCacheService.GetKey(keyList.ToArray(), new string[] { responseArea ?? string.Empty, workGroup ?? string.Empty });
|
||||
|
||||
logger.LogDebug("Сформирован ключ для кэш '{Key}'", keyStr);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using PARR.Core.Services.NextRunServices;
|
||||
using PARR.Core.Services.TaskServices.Helpers;
|
||||
using PARR.Core.Services.Workload.Interfaces;
|
||||
using PARR.Core.Services.Workload.Models;
|
||||
using PARR.Domain.Cache.Models;
|
||||
using PARR.Domain.DTOs.Workload;
|
||||
using PARR.Domain.Entities;
|
||||
using PARR.Domain.Enums;
|
||||
@@ -45,19 +46,25 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
}
|
||||
|
||||
|
||||
public async Task<WorkloadReport?> GetWorkloadReportAsync(WorkloadReportType reportType, DateOnly dateStart, int durationDays, TimeSpan offset, string? filterParam)
|
||||
public async Task<WorkloadReport?> GetWorkloadReportAsync(WorkloadReportType reportType, DateOnly dateStart, int durationDays, TimeSpan offset, string? responseArea, string? workGroup)
|
||||
{
|
||||
logger.LogDebug("Начинаю формировать отчет о загруженности по параметрам: reportType '{ReportType}', dateStart {DateStart}, durationDays {DurationDays}, offset {Offset}",
|
||||
reportType.ToString(), dateStart, durationDays, offset);
|
||||
|
||||
if ((reportType == WorkloadReportType.WorkGroupJob || reportType == WorkloadReportType.ResponseAreaWorkGroups) && string.IsNullOrEmpty(filterParam))
|
||||
if (reportType == WorkloadReportType.WorkGroupJob && string.IsNullOrEmpty(workGroup))
|
||||
{
|
||||
logger.LogError("Для типа отчета {ReportType} не передан параметр.", reportType.ToString());
|
||||
throw new ArgumentNullException(nameof(filterParam), $"Для отчета типа {reportType.ToString()} параметр является обязательным.");
|
||||
throw new ArgumentNullException(nameof(workGroup), $"Для отчета типа {reportType.ToString()} параметр является обязательным.");
|
||||
}
|
||||
|
||||
if (reportType == WorkloadReportType.ResponseAreaWorkGroups && string.IsNullOrEmpty(responseArea))
|
||||
{
|
||||
logger.LogError("Для типа отчета {ReportType} не передан параметр.", reportType.ToString());
|
||||
throw new ArgumentNullException(nameof(responseArea), $"Для отчета типа {reportType.ToString()} параметр является обязательным.");
|
||||
}
|
||||
|
||||
// Если есть отчет в КЭШ, вернуть
|
||||
var cacheReport = await workloadCacheService.GetWorkloadReportAsync(reportType, dateStart, durationDays, offset, filterParam);
|
||||
var cacheReport = await workloadCacheService.GetWorkloadReportAsync(reportType, dateStart, durationDays, offset, responseArea, workGroup);
|
||||
if (cacheReport != null)
|
||||
{
|
||||
logger.LogDebug("Вернул отчет из кэша.");
|
||||
@@ -92,11 +99,10 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
case WorkloadReportType.ResponseAreaWorkGroups:
|
||||
displayName = "По зоне ответственности";
|
||||
// Фильтруем по ЗО
|
||||
var filteredRA = templates.Where(t => string.Equals(t.ResponseArea, filterParam, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var filteredRA = templates.Where(t => string.Equals(t.ResponseArea, responseArea, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
// Группируем работы по РГ
|
||||
foreach (var group in filteredRA.GroupBy(t => t.WorkGroup, StringComparer.OrdinalIgnoreCase))
|
||||
statistics.Add(BuildStatisticItem(group.Key, null, group, reportDays, offset));
|
||||
//statistics.Add(BuildStatisticItem(filterParam!, filteredRA, reportDays, offset));
|
||||
break;
|
||||
case WorkloadReportType.WorkGroupAll:
|
||||
displayName = "По рабочим группам";
|
||||
@@ -106,7 +112,12 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
case WorkloadReportType.WorkGroupJob:
|
||||
displayName = "По рабочей группе";
|
||||
// Фильтруем по РГ
|
||||
var filteredWG = templates.Where(t => string.Equals(t.WorkGroup, filterParam, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var filteredWG = templates.Where(t => string.Equals(t.WorkGroup, workGroup, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
if (!string.IsNullOrWhiteSpace(responseArea))
|
||||
{
|
||||
// Дополнительно фильтруем по ЗО
|
||||
filteredWG = filteredWG.Where(t => string.Equals(t.ResponseArea, responseArea, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
}
|
||||
|
||||
// Получим все JobName из бд
|
||||
var jobIds = filteredWG.Select(t => t.JobId).ToHashSet();
|
||||
@@ -123,11 +134,12 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
var report = new WorkloadReport
|
||||
{
|
||||
Type = reportType,
|
||||
DisplayName = displayName,
|
||||
SubfilterName = filterParam,
|
||||
SubfilterName = string.Join(", ", new[] { responseArea, workGroup }),
|
||||
ReportCacheCreatedAt = DateTimeOffset.UtcNow,
|
||||
TemplateCacheCreatedAt = templates.FirstOrDefault()?.CacheDate ?? DateTimeOffset.MinValue,
|
||||
Days = reportDays,
|
||||
@@ -135,7 +147,7 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
};
|
||||
|
||||
// Сохраним в кэш
|
||||
await workloadCacheService.SetWorkloadReport(report, reportType, dateStart, durationDays, offset, filterParam);
|
||||
await workloadCacheService.SetWorkloadReport(report, reportType, dateStart, durationDays, offset, responseArea, workGroup);
|
||||
logger.LogDebug("Отчет построен и сохранен в кэш");
|
||||
|
||||
return report;
|
||||
@@ -181,8 +193,8 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
WorkloadTemplateReportState state,
|
||||
DateOnly date,
|
||||
TimeSpan offset,
|
||||
WorkloadJobSubfliterType? jobSubfilterType,
|
||||
string? jobSubfilterValue
|
||||
string? responseArea,
|
||||
string? workGroup
|
||||
)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(filter))
|
||||
@@ -243,8 +255,8 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
if (dbTemplates.Count == 0)
|
||||
return new List<WorkloadTemplateReport>();
|
||||
|
||||
// Если тип - работы, и нет дополнительных фильтров по ЗО или РГ, не полезем в кэш, вернем сразу
|
||||
if (reportType == WorkloadTemplateReportType.Job && (!jobSubfilterType.HasValue || string.IsNullOrWhiteSpace(jobSubfilterValue)))
|
||||
// Если тип - работы, и нет дополнительных фильтров по ЗО и РГ, не полезем в кэш, вернем сразу
|
||||
if (reportType == WorkloadTemplateReportType.Job && string.IsNullOrWhiteSpace(responseArea) && string.IsNullOrWhiteSpace(workGroup))
|
||||
{
|
||||
// Тут кэш не нужен, вернем сразу из бд (нет фильтров по РГ и ЗО, нужен список всех работ на дату)
|
||||
return FilterWorkloadJobTemplateReport(dbTemplates, null);
|
||||
@@ -259,41 +271,51 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
if (dbTemplates.Count != cacheData.Count)
|
||||
logger.LogWarning("Количество шаблонов в БД {DbCount} не совпадает с количеством шаблонов полученных из кэша {CacheCount}", dbTemplates.Count, cacheData.Count);
|
||||
|
||||
// Дополнительные фильтры
|
||||
var trimmedResponseArea = responseArea?.Trim();
|
||||
var trimmedWorkGroup = workGroup?.Trim();
|
||||
|
||||
// Фильтр по типу
|
||||
switch (reportType)
|
||||
{
|
||||
case WorkloadTemplateReportType.Job:
|
||||
// Смотрим есть ли дополнительные фильтры
|
||||
if (jobSubfilterType.HasValue && !string.IsNullOrWhiteSpace(jobSubfilterValue))
|
||||
if (!string.IsNullOrEmpty(trimmedResponseArea) || !string.IsNullOrEmpty(trimmedWorkGroup))
|
||||
{
|
||||
var cacheTemplatesJobs = new HashSet<Guid>();
|
||||
// Фильтруем из кэша
|
||||
var trimmedJobSubfilterValue = jobSubfilterValue.Trim();
|
||||
switch (jobSubfilterType)
|
||||
{
|
||||
case WorkloadJobSubfliterType.ResponseArea:
|
||||
cacheTemplatesJobs = cacheData.Where(t => string.Equals(t.Data.ResponseArea, trimmedJobSubfilterValue, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(t => t.Data.TemplateId).ToHashSet();
|
||||
break;
|
||||
case WorkloadJobSubfliterType.WorkGroup:
|
||||
cacheTemplatesJobs = cacheData.Where(t => string.Equals(t.Data.WorkGroup, trimmedJobSubfilterValue, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(t => t.Data.TemplateId).ToHashSet();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("Неверный тип фильтра", nameof(jobSubfilterType));
|
||||
}
|
||||
IEnumerable<TemplateCache> cacheTemplatesJobs = cacheData;
|
||||
|
||||
return FilterWorkloadJobTemplateReport(dbTemplates, cacheTemplatesJobs);
|
||||
// Фильтруем по ЗО если есть
|
||||
if (!string.IsNullOrEmpty(trimmedResponseArea))
|
||||
cacheTemplatesJobs = cacheTemplatesJobs.Where(t => string.Equals(t.Data.ResponseArea, trimmedResponseArea, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// Дополнительный фильтр по РГ, если есть
|
||||
if (!string.IsNullOrEmpty(trimmedWorkGroup))
|
||||
cacheTemplatesJobs = cacheTemplatesJobs.Where(t => string.Equals(t.Data.WorkGroup, trimmedWorkGroup, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var filteredTemplateJobIds = cacheTemplatesJobs.Select(t => t.Data.TemplateId).ToHashSet();
|
||||
|
||||
return FilterWorkloadJobTemplateReport(dbTemplates, filteredTemplateJobIds);
|
||||
}
|
||||
return FilterWorkloadJobTemplateReport(dbTemplates, null);
|
||||
case WorkloadTemplateReportType.WorkGroup:
|
||||
var cacheTemplatesWg = cacheData.Where(t => string.Equals(t.Data.WorkGroup, trimmedFilter, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(t => t.Data.TemplateId).ToHashSet();
|
||||
return dbTemplates.Where(t => cacheTemplatesWg.Contains(t.TemplateId)).ToList();
|
||||
var cacheTemplatesWg = cacheData.Where(t => string.Equals(t.Data.WorkGroup, trimmedFilter, StringComparison.OrdinalIgnoreCase));
|
||||
// Дополнительный фильтр по ЗО, если есть
|
||||
if (!string.IsNullOrEmpty(trimmedResponseArea))
|
||||
cacheTemplatesWg = cacheTemplatesWg.Where(t => string.Equals(t.Data.ResponseArea, trimmedResponseArea, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var filteredTemplateWgIds = cacheTemplatesWg.Select(t => t.Data.TemplateId).ToHashSet();
|
||||
|
||||
return dbTemplates.Where(t => filteredTemplateWgIds.Contains(t.TemplateId)).ToList();
|
||||
case WorkloadTemplateReportType.ResponseArea:
|
||||
var cacheTemplatesRa = cacheData.Where(t => string.Equals(t.Data.ResponseArea, trimmedFilter, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(t => t.Data.TemplateId).ToHashSet();
|
||||
return dbTemplates.Where(t => cacheTemplatesRa.Contains(t.TemplateId)).ToList();
|
||||
var cacheTemplatesRa = cacheData.Where(t => string.Equals(t.Data.ResponseArea, trimmedFilter, StringComparison.OrdinalIgnoreCase));
|
||||
// Дополнительный фильтр по РГ если есть
|
||||
if (!string.IsNullOrEmpty(trimmedWorkGroup))
|
||||
cacheTemplatesRa = cacheTemplatesRa.Where(t => string.Equals(t.Data.WorkGroup, trimmedWorkGroup, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var filteredTemplateRaIds = cacheTemplatesRa.Select(t => t.Data.TemplateId).ToHashSet();
|
||||
|
||||
return dbTemplates.Where(t => filteredTemplateRaIds.Contains(t.TemplateId)).ToList();
|
||||
}
|
||||
|
||||
logger.LogWarning("Не обработанный тип отчета {ReportType}", reportType);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using PARR.Domain.DTOs.Workload;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using PARR.Domain.DTOs.Workload;
|
||||
using PARR.Domain.Enums.Workload;
|
||||
|
||||
namespace PARR.Core.Services.Workload.Interfaces
|
||||
@@ -21,9 +22,10 @@ namespace PARR.Core.Services.Workload.Interfaces
|
||||
/// <param name="dateStart"></param>
|
||||
/// <param name="durationDays"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="filterParam"></param>
|
||||
/// <param name="responseArea"></param>
|
||||
/// <param name="workGroup"></param>
|
||||
/// <returns></returns>
|
||||
Task<WorkloadReport?> GetWorkloadReportAsync(WorkloadReportType reportType, DateOnly dateStart, int durationDays, TimeSpan offset, string? filterParam);
|
||||
Task<WorkloadReport?> GetWorkloadReportAsync(WorkloadReportType reportType, DateOnly dateStart, int durationDays, TimeSpan offset, string? responseArea, string? workGroup);
|
||||
|
||||
/// <summary>
|
||||
/// Получить отчет - список шаблонов на дату согласно фильтрам
|
||||
@@ -33,10 +35,18 @@ namespace PARR.Core.Services.Workload.Interfaces
|
||||
/// <param name="state"></param>
|
||||
/// <param name="date"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="jobSubfilterType">Дополнительный фильтр при отчете по шаблонам, тип</param>
|
||||
/// <param name="jobSubfilterValue">Дополнительный фильтр при отчете по шаблонам, значение</param>
|
||||
/// <param name="responseArea">Дополнительный фильтр при отчете по шаблонам, ЗО</param>
|
||||
/// <param name="workGorup">Дополнительный фильтр при отчете по шаблонам, РГ</param>
|
||||
/// <returns></returns>
|
||||
Task<List<WorkloadTemplateReport>> GetTemplateReportAsync(WorkloadTemplateReportType reportType, string filter, WorkloadTemplateReportState state, DateOnly date, TimeSpan offset, WorkloadJobSubfliterType? jobSubfilterType, string? jobSubfilterValue);
|
||||
Task<List<WorkloadTemplateReport>> GetTemplateReportAsync(
|
||||
WorkloadTemplateReportType reportType,
|
||||
string filter,
|
||||
WorkloadTemplateReportState state,
|
||||
DateOnly date,
|
||||
TimeSpan offset,
|
||||
string? responseArea,
|
||||
string? workGroup
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user