feat(api, domain, core): StatWorkloadTemplate - дополнительная фильтрация по РГ и ЗО.
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
using PARR.Domain.Enums.Workload;
|
||||
|
||||
namespace PARR.API.Contracts.V1.Requests.Queries
|
||||
{
|
||||
public record StatWorkloadTemplateReqportQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// Тип дополнительно фильтра для работы (ЗО, РГ)
|
||||
/// </summary>
|
||||
public WorkloadJobSubfliterType? JobSubfilterType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Значение дополнительного фильтра для работы
|
||||
/// </summary>
|
||||
public string? JobSubfilterValue { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,8 @@ namespace PARR.API.Contracts.V1.Responses.Statistics
|
||||
{
|
||||
public required string Title { get; init; }
|
||||
|
||||
public Guid? ObjId { get; init; }
|
||||
|
||||
public required WorkloadSummaryResponse Summary { get; init; }
|
||||
|
||||
public required List<WorkloadDailyItemResponse> DailyMetrics { get; init; }
|
||||
|
||||
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PARR.API.Contracts.V1;
|
||||
using PARR.API.Contracts.V1.Requests.BaseRequests;
|
||||
using PARR.API.Contracts.V1.Requests.Queries;
|
||||
using PARR.API.Contracts.V1.Responses.Base;
|
||||
using PARR.API.Contracts.V1.Responses.Statistics;
|
||||
using PARR.API.Controllers.V1.Base;
|
||||
@@ -45,7 +46,14 @@ namespace PARR.API.Controllers.V1.Statistics
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
[HttpGet(ApiRoutes.StatWorkloadTemplate.GetWorkloadTemplateReport)]
|
||||
public async Task<IActionResult> GetWorkloadTemplateReport([FromRoute] WorkloadTemplateReportType reportType, [FromRoute] string filter, [FromRoute] WorkloadTemplateReportState state, [FromRoute] DateOnly date, [FromQuery] TimeZoneOffsetClient offset)
|
||||
public async Task<IActionResult> GetWorkloadTemplateReport(
|
||||
[FromRoute] WorkloadTemplateReportType reportType,
|
||||
[FromRoute] string filter,
|
||||
[FromRoute] WorkloadTemplateReportState state,
|
||||
[FromRoute] DateOnly date,
|
||||
[FromQuery] TimeZoneOffsetClient offset,
|
||||
[FromQuery] StatWorkloadTemplateReqportQuery query
|
||||
)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(filter))
|
||||
{
|
||||
@@ -53,7 +61,13 @@ namespace PARR.API.Controllers.V1.Statistics
|
||||
throw new ArgumentException(nameof(filter), "Не передано значение фильтра.");
|
||||
}
|
||||
|
||||
var report = await workloadService.GetTemplateReportAsync(reportType, filter, state, date, offset.TimeZoneOffset);
|
||||
if (query.JobSubfilterType.HasValue && string.IsNullOrWhiteSpace(query.JobSubfilterValue))
|
||||
{
|
||||
logger.LogWarning("Не передано значение дополнительного фильтра для работы");
|
||||
throw new ArgumentException(nameof(filter), "Не передано значение дополнительного фильтра для работы.");
|
||||
}
|
||||
|
||||
var report = await workloadService.GetTemplateReportAsync(reportType, filter, state, date, offset.TimeZoneOffset, query.JobSubfilterType, query.JobSubfilterValue);
|
||||
|
||||
var response = mapper.Map<List<StatWorkloadTemplateReportResponse>>(report);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using PARR.Core.Services.TaskServices.Helpers;
|
||||
using PARR.Core.Services.Workload.Interfaces;
|
||||
using PARR.Core.Services.Workload.Models;
|
||||
using PARR.Domain.DTOs.Workload;
|
||||
using PARR.Domain.Entities;
|
||||
using PARR.Domain.Enums;
|
||||
using PARR.Domain.Enums.Workload;
|
||||
|
||||
@@ -55,7 +56,6 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
throw new ArgumentNullException(nameof(filterParam), $"Для отчета типа {reportType.ToString()} параметр является обязательным.");
|
||||
}
|
||||
|
||||
|
||||
// Если есть отчет в КЭШ, вернуть
|
||||
var cacheReport = await workloadCacheService.GetWorkloadReportAsync(reportType, dateStart, durationDays, offset, filterParam);
|
||||
if (cacheReport != null)
|
||||
@@ -87,7 +87,7 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
case WorkloadReportType.ResponseAreaAll:
|
||||
displayName = "По зонам ответственности";
|
||||
foreach (var group in templates.GroupBy(t => t.ResponseArea, StringComparer.OrdinalIgnoreCase))
|
||||
statistics.Add(BuildStatisticItem(group.Key, group, reportDays, offset));
|
||||
statistics.Add(BuildStatisticItem(group.Key, null, group, reportDays, offset));
|
||||
break;
|
||||
case WorkloadReportType.ResponseAreaWorkGroups:
|
||||
displayName = "По зоне ответственности";
|
||||
@@ -95,13 +95,13 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
var filteredRA = templates.Where(t => string.Equals(t.ResponseArea, filterParam, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
// Группируем работы по РГ
|
||||
foreach (var group in filteredRA.GroupBy(t => t.WorkGroup, StringComparer.OrdinalIgnoreCase))
|
||||
statistics.Add(BuildStatisticItem(group.Key, group, reportDays, offset));
|
||||
statistics.Add(BuildStatisticItem(group.Key, null, group, reportDays, offset));
|
||||
//statistics.Add(BuildStatisticItem(filterParam!, filteredRA, reportDays, offset));
|
||||
break;
|
||||
case WorkloadReportType.WorkGroupAll:
|
||||
displayName = "По рабочим группам";
|
||||
foreach (var group in templates.GroupBy(t => t.WorkGroup))
|
||||
statistics.Add(BuildStatisticItem(group.Key, group, reportDays, offset));
|
||||
statistics.Add(BuildStatisticItem(group.Key, null, group, reportDays, offset));
|
||||
break;
|
||||
case WorkloadReportType.WorkGroupJob:
|
||||
displayName = "По рабочей группе";
|
||||
@@ -118,7 +118,7 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
foreach (var group in filteredWG.GroupBy(t => t.JobId))
|
||||
{
|
||||
var jobName = jobs.GetValueOrDefault(group.Key) ?? "Работа";
|
||||
statistics.Add(BuildStatisticItem(jobName, group, reportDays, offset));
|
||||
statistics.Add(BuildStatisticItem(jobName, group.Key, group, reportDays, offset));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -175,7 +175,15 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<WorkloadTemplateReport>> GetTemplateReportAsync(WorkloadTemplateReportType reportType, string filter, WorkloadTemplateReportState state, DateOnly date, TimeSpan offset)
|
||||
public async Task<List<WorkloadTemplateReport>> GetTemplateReportAsync(
|
||||
WorkloadTemplateReportType reportType,
|
||||
string filter,
|
||||
WorkloadTemplateReportState state,
|
||||
DateOnly date,
|
||||
TimeSpan offset,
|
||||
WorkloadJobSubfliterType? jobSubfilterType,
|
||||
string? jobSubfilterValue
|
||||
)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(filter))
|
||||
{
|
||||
@@ -218,19 +226,16 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
break;
|
||||
}
|
||||
|
||||
// Если тип - работы
|
||||
// Если тип - работы, получим из бд сразу нужные работы
|
||||
if (reportType == WorkloadTemplateReportType.Job)
|
||||
{
|
||||
if (!Guid.TryParse(trimmedFilter, out Guid jobId))
|
||||
throw new ArgumentException("Значение фильтра не является Guid");
|
||||
|
||||
return await query.Where(t => t.JobId == jobId)
|
||||
.OrderBy(t => t.Name)
|
||||
.Select(t => new WorkloadTemplateReport(t.Id, t.Name, t.NextRun, t.IsActiveTemplate, t.IsActiveSchedule))
|
||||
.ToListAsync();
|
||||
query = query.Where(t => t.JobId == jobId);
|
||||
}
|
||||
|
||||
// Тип "не работы", загружаем шаблоны
|
||||
// Загружаем шаблоны
|
||||
var dbTemplates = await query.OrderBy(t => t.Name)
|
||||
.Select(t => new WorkloadTemplateReport(t.Id, t.Name, t.NextRun, t.IsActiveTemplate, t.IsActiveSchedule))
|
||||
.ToListAsync();
|
||||
@@ -238,6 +243,13 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
if (dbTemplates.Count == 0)
|
||||
return new List<WorkloadTemplateReport>();
|
||||
|
||||
// Если тип - работы, и нет дополнительных фильтров по ЗО или РГ, не полезем в кэш, вернем сразу
|
||||
if (reportType == WorkloadTemplateReportType.Job && (!jobSubfilterType.HasValue || string.IsNullOrWhiteSpace(jobSubfilterValue)))
|
||||
{
|
||||
// Тут кэш не нужен, вернем сразу из бд (нет фильтров по РГ и ЗО, нужен список всех работ на дату)
|
||||
return FilterWorkloadJobTemplateReport(dbTemplates, null);
|
||||
}
|
||||
|
||||
// Получаем из кэша шаблоны (если их в кэше нет, догружаем в кэш)
|
||||
var cacheData = await workloadCacheService.GetTemplateReportDataByIdsAsync(dbTemplates.Select(t => t.TemplateId).ToHashSet());
|
||||
|
||||
@@ -250,6 +262,30 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
// Фильтр по типу
|
||||
switch (reportType)
|
||||
{
|
||||
case WorkloadTemplateReportType.Job:
|
||||
// Смотрим есть ли дополнительные фильтры
|
||||
if (jobSubfilterType.HasValue && !string.IsNullOrWhiteSpace(jobSubfilterValue))
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
return FilterWorkloadJobTemplateReport(dbTemplates, cacheTemplatesJobs);
|
||||
}
|
||||
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();
|
||||
@@ -266,6 +302,16 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
}
|
||||
|
||||
|
||||
private List<WorkloadTemplateReport> FilterWorkloadJobTemplateReport(List<WorkloadTemplateReport> dbTemplates, HashSet<Guid>? filteredCacheTemplates)
|
||||
{
|
||||
if (filteredCacheTemplates == null)
|
||||
return dbTemplates;
|
||||
|
||||
// Отсекаем шаблоны которых нет в кэше
|
||||
return dbTemplates.Where(t => filteredCacheTemplates.Contains(t.TemplateId)).ToList();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Получить список дней для отчета, с отметкой выходной/рабочий
|
||||
/// </summary>
|
||||
@@ -347,12 +393,12 @@ namespace PARR.Core.Services.Workload.Implementations
|
||||
/// <param name="reportDays"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
private WorkloadStatisticItem BuildStatisticItem(string title, IEnumerable<TemplateReportData> groupTemplates, List<WorkloadDayItem> reportDays, TimeSpan offset)
|
||||
private WorkloadStatisticItem BuildStatisticItem(string title, Guid? objId, IEnumerable<TemplateReportData> groupTemplates, List<WorkloadDayItem> reportDays, TimeSpan offset)
|
||||
{
|
||||
var dailyMetrics = GetDailyMetrics(groupTemplates.ToList(), reportDays, offset);
|
||||
var summary = GetSummary(dailyMetrics, reportDays.Count);
|
||||
|
||||
return new WorkloadStatisticItem { DailyMetrics = dailyMetrics, Summary = summary, Title = title };
|
||||
return new WorkloadStatisticItem { DailyMetrics = dailyMetrics, Summary = summary, Title = title, ObjId = objId };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,10 @@ 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>
|
||||
/// <returns></returns>
|
||||
Task<List<WorkloadTemplateReport>> GetTemplateReportAsync(WorkloadTemplateReportType reportType, string filter, WorkloadTemplateReportState state, DateOnly date, TimeSpan offset);
|
||||
Task<List<WorkloadTemplateReport>> GetTemplateReportAsync(WorkloadTemplateReportType reportType, string filter, WorkloadTemplateReportState state, DateOnly date, TimeSpan offset, WorkloadJobSubfliterType? jobSubfilterType, string? jobSubfilterValue);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,12 @@ namespace PARR.Domain.DTOs.Workload
|
||||
{
|
||||
public required string Title { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// ИД строки, если есть.
|
||||
/// Например JobId
|
||||
/// </summary>
|
||||
public Guid? ObjId { get; init; }
|
||||
|
||||
public required WorkloadSummary Summary { get; init; }
|
||||
|
||||
public required List<WorkloadDailyItem> DailyMetrics { get; init; }
|
||||
|
||||
22
PARR.Domain/Enums/Workload/WorkloadJobSubfliterType.cs
Normal file
22
PARR.Domain/Enums/Workload/WorkloadJobSubfliterType.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace PARR.Domain.Enums.Workload
|
||||
{
|
||||
/// <summary>
|
||||
/// Дополнительный фильтр для работ.
|
||||
/// Отчет Workload, шаблоны
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum WorkloadJobSubfliterType
|
||||
{
|
||||
/// <summary>
|
||||
/// ЗО
|
||||
/// </summary>
|
||||
ResponseArea = 0,
|
||||
|
||||
/// <summary>
|
||||
/// РГ
|
||||
/// </summary>
|
||||
WorkGroup=1
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user