feat(api,core,domain): Статистика по роботам, кол-во работающих роботов в час
This commit is contained in:
@@ -23,5 +23,10 @@
|
|||||||
/// Ошибок
|
/// Ошибок
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Errors { get; set; }
|
public int Errors { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Среднее кол-во роботов работающих в течении часа
|
||||||
|
/// </summary>
|
||||||
|
public double AvgRobots { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ using PARR.API.Contracts.V1.Responses.Base;
|
|||||||
using PARR.API.Contracts.V1.Responses.Statistics;
|
using PARR.API.Contracts.V1.Responses.Statistics;
|
||||||
using PARR.API.Controllers.V1.Base;
|
using PARR.API.Controllers.V1.Base;
|
||||||
using PARR.Core.Repositories.Interfaces;
|
using PARR.Core.Repositories.Interfaces;
|
||||||
|
using PARR.Core.Services.RobotSnapshotServices;
|
||||||
using PARR.Domain.Common.Roles;
|
using PARR.Domain.Common.Roles;
|
||||||
|
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||||
using PARR.Domain.Enums;
|
using PARR.Domain.Enums;
|
||||||
|
|
||||||
namespace PARR.API.Controllers.V1.Statistics
|
namespace PARR.API.Controllers.V1.Statistics
|
||||||
@@ -24,13 +26,15 @@ namespace PARR.API.Controllers.V1.Statistics
|
|||||||
private readonly ITaskStatusRepository taskStatusService;
|
private readonly ITaskStatusRepository taskStatusService;
|
||||||
private readonly IRobotHistoryRepository robotHistoryService;
|
private readonly IRobotHistoryRepository robotHistoryService;
|
||||||
private readonly IMapper mapper;
|
private readonly IMapper mapper;
|
||||||
|
private readonly IRobotSnapshotService _robotSnapshotService;
|
||||||
|
|
||||||
public StatRobotTaskController(
|
public StatRobotTaskController(
|
||||||
IRobotRepository robotService,
|
IRobotRepository robotService,
|
||||||
IRobotConfigurationRepository robotConfigurationService,
|
IRobotConfigurationRepository robotConfigurationService,
|
||||||
ITaskStatusRepository taskStatusService,
|
ITaskStatusRepository taskStatusService,
|
||||||
IRobotHistoryRepository robotHistoryService,
|
IRobotHistoryRepository robotHistoryService,
|
||||||
IMapper mapper
|
IMapper mapper,
|
||||||
|
IRobotSnapshotService robotSnapshotService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.robotService = robotService;
|
this.robotService = robotService;
|
||||||
@@ -38,6 +42,7 @@ namespace PARR.API.Controllers.V1.Statistics
|
|||||||
this.taskStatusService = taskStatusService;
|
this.taskStatusService = taskStatusService;
|
||||||
this.robotHistoryService = robotHistoryService;
|
this.robotHistoryService = robotHistoryService;
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
|
_robotSnapshotService = robotSnapshotService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -87,11 +92,11 @@ namespace PARR.API.Controllers.V1.Statistics
|
|||||||
[HttpGet(ApiRoutes.StatRobotTask.GetPeriodStatistics)]
|
[HttpGet(ApiRoutes.StatRobotTask.GetPeriodStatistics)]
|
||||||
public async Task<IActionResult> GetPeriodStatistics([FromRoute] RobotsEnum robot)
|
public async Task<IActionResult> GetPeriodStatistics([FromRoute] RobotsEnum robot)
|
||||||
{
|
{
|
||||||
|
var offset = TimeSpan.FromHours(0);
|
||||||
|
|
||||||
int minusHour = 24;
|
int minusHour = 24;
|
||||||
var queryDate = DateTimeOffset.UtcNow.AddHours(-minusHour);
|
var queryDate = DateTimeOffset.UtcNow.AddHours(-minusHour);
|
||||||
queryDate = new DateTimeOffset(queryDate.Year, queryDate.Month, queryDate.Day, queryDate.Hour, 0, 0, new TimeSpan(0));
|
queryDate = new DateTimeOffset(queryDate.Year, queryDate.Month, queryDate.Day, queryDate.Hour, 0, 0, offset);
|
||||||
//queryDate = queryDate.Date + new TimeSpan(queryDate.Hour, 0, 0);
|
|
||||||
//queryDate=queryDate.ToOffset(TimeSpan.Zero);
|
|
||||||
|
|
||||||
|
|
||||||
var query = robotHistoryService.Get()
|
var query = robotHistoryService.Get()
|
||||||
@@ -110,16 +115,24 @@ namespace PARR.API.Controllers.V1.Statistics
|
|||||||
|
|
||||||
var statistics = await query.ToListAsync();
|
var statistics = await query.ToListAsync();
|
||||||
|
|
||||||
//if (!statistics.Any())
|
|
||||||
// return NoContent();
|
|
||||||
|
|
||||||
var periodList = GetPeriodList(queryDate, DateTimeOffset.UtcNow);
|
var periodList = GetPeriodList(queryDate, DateTimeOffset.UtcNow);
|
||||||
|
|
||||||
if (!periodList.Any())
|
if (!periodList.Any())
|
||||||
return NoContent();
|
return NoContent();
|
||||||
|
|
||||||
|
// Статистика по роботам (кол-во роботов)
|
||||||
|
var robotStats = await _robotSnapshotService.GetHourlyAnalyticsByRobotTypeAsync(new RobotAnalyticsRobotTypeQuery
|
||||||
|
{
|
||||||
|
DateStart = queryDate,
|
||||||
|
DateEnd = DateTimeOffset.UtcNow,
|
||||||
|
Offset = offset,
|
||||||
|
RobotType = robot
|
||||||
|
});
|
||||||
|
|
||||||
periodList.ForEach(item =>
|
periodList.ForEach(item =>
|
||||||
{
|
{
|
||||||
|
var robotCount = robotStats.FirstOrDefault(t => t.Hour.Date == item.Date.Date && t.Hour.Hour == item.Date.Hour);
|
||||||
|
|
||||||
var statItem = statistics.FirstOrDefault(t => t.Date.Date == item.Date.Date && t.Date.Hour == item.Date.Hour);
|
var statItem = statistics.FirstOrDefault(t => t.Date.Date == item.Date.Date && t.Date.Hour == item.Date.Hour);
|
||||||
if (statItem != null)
|
if (statItem != null)
|
||||||
{
|
{
|
||||||
@@ -127,6 +140,7 @@ namespace PARR.API.Controllers.V1.Statistics
|
|||||||
item.Creating = statItem.Creating;
|
item.Creating = statItem.Creating;
|
||||||
item.Updating = statItem.Updating;
|
item.Updating = statItem.Updating;
|
||||||
item.Ok = statItem.Ok;
|
item.Ok = statItem.Ok;
|
||||||
|
item.AvgRobots = robotCount?.AvgRobots ?? 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -150,6 +164,7 @@ namespace PARR.API.Controllers.V1.Statistics
|
|||||||
Errors = 0,
|
Errors = 0,
|
||||||
Ok = 0,
|
Ok = 0,
|
||||||
Updating = 0,
|
Updating = 0,
|
||||||
|
AvgRobots = 0,
|
||||||
Date = new DateTimeOffset(periodDate.Date.Year, periodDate.Date.Month, periodDate.Date.Day, periodDate.Hour, 0, 0, new TimeSpan(0)),
|
Date = new DateTimeOffset(periodDate.Date.Year, periodDate.Date.Month, periodDate.Date.Day, periodDate.Hour, 0, 0, new TimeSpan(0)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -173,14 +173,24 @@ namespace PARR.API.Controllers.V1
|
|||||||
[HttpGet(ApiRoutes.Test.TestHandler)]
|
[HttpGet(ApiRoutes.Test.TestHandler)]
|
||||||
public async Task<IActionResult> Test()
|
public async Task<IActionResult> Test()
|
||||||
{
|
{
|
||||||
var data = await _robotSnapshotService.GetHourlyAnalyticsAsync(new RobotAnalyticsQuery
|
//var data = await _robotSnapshotService.GetHourlyAnalyticsAsync(new RobotAnalyticsQuery
|
||||||
{
|
//{
|
||||||
DateStart = DateTimeOffset.UtcNow.AddHours(-1),
|
// DateStart = DateTimeOffset.UtcNow.AddHours(-1),
|
||||||
DateEnd = DateTimeOffset.UtcNow,
|
// DateEnd = DateTimeOffset.UtcNow,
|
||||||
Offset = TimeSpan.FromMinutes(600)
|
// Offset = TimeSpan.FromMinutes(600)
|
||||||
});
|
//});
|
||||||
|
|
||||||
return Ok(data);
|
//var data = await _robotSnapshotService.GetHourlyAnalyticsByRobotTypeAsync(new RobotAnalyticsRobotTypeQuery
|
||||||
|
//{
|
||||||
|
// DateStart = DateTimeOffset.UtcNow.AddHours(-12),
|
||||||
|
// DateEnd = DateTimeOffset.UtcNow,
|
||||||
|
// Offset = TimeSpan.FromMinutes(600),
|
||||||
|
// RobotType = PARR.Domain.Enums.RobotsEnum.TemplateOrder
|
||||||
|
//});
|
||||||
|
|
||||||
|
//return Ok(data);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,10 +19,19 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
Task<RobotSnapshotItemDto> CreateAsync(CreateRobotSnapshot robotSnapshot);
|
Task<RobotSnapshotItemDto> CreateAsync(CreateRobotSnapshot robotSnapshot);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить аналитику за период
|
/// Получить аналитику за период с группировкой по ip серверов. Разбивка по часам.
|
||||||
|
/// Максимальная одновременная работа роботов. Среднее кол-во роботов в час. Максимально возможное кол-во роботов.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="queryDto"></param>
|
/// <param name="queryDto"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<List<ServerHourlyAnalyticsDto>> GetHourlyAnalyticsAsync(RobotAnalyticsQuery queryDto);
|
Task<List<ServerHourlyAnalyticsDto>> GetHourlyAnalyticsAsync(RobotAnalyticsQuery queryDto);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить аналитику за период по типу робота. Разбивка по часам.
|
||||||
|
/// Среднее кол-во роботов в час.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="queryDto"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<List<HourlyRobotTypeAnalyticsDto>> GetHourlyAnalyticsByRobotTypeAsync(RobotAnalyticsRobotTypeQuery queryDto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
{
|
{
|
||||||
internal class RobotSnapshotService : IRobotSnapshotService
|
internal class RobotSnapshotService : IRobotSnapshotService
|
||||||
{
|
{
|
||||||
private readonly IRobotSnapshotRepository robotSnapshotRepository;
|
private readonly IRobotSnapshotRepository _robotSnapshotRepository;
|
||||||
private readonly IUserRepository userRepository;
|
private readonly IUserRepository _userRepository;
|
||||||
private readonly IMapper mapper;
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
public RobotSnapshotService(
|
public RobotSnapshotService(
|
||||||
IRobotSnapshotRepository robotSnapshotRepository,
|
IRobotSnapshotRepository robotSnapshotRepository,
|
||||||
@@ -21,9 +21,9 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
IMapper mapper
|
IMapper mapper
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.robotSnapshotRepository = robotSnapshotRepository;
|
_robotSnapshotRepository = robotSnapshotRepository;
|
||||||
this.userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
this.mapper = mapper;
|
_mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
var dateEnd = DateTimeOffset.UtcNow;
|
var dateEnd = DateTimeOffset.UtcNow;
|
||||||
var dateStart = dateEnd.AddMinutes(-minutes);
|
var dateStart = dateEnd.AddMinutes(-minutes);
|
||||||
|
|
||||||
var query = robotSnapshotRepository.Get().AsNoTracking()
|
var query = _robotSnapshotRepository.Get().AsNoTracking()
|
||||||
.Where(t => dateStart <= t.DateCreated && t.DateCreated <= dateEnd);
|
.Where(t => dateStart <= t.DateCreated && t.DateCreated <= dateEnd);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(queryDto.Ip))
|
if (!string.IsNullOrEmpty(queryDto.Ip))
|
||||||
@@ -47,7 +47,7 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
|
|
||||||
|
|
||||||
var robotIps = groupingSnapshots.Select(t => t.Key).ToHashSet();
|
var robotIps = groupingSnapshots.Select(t => t.Key).ToHashSet();
|
||||||
var robotList = await userRepository.Get()
|
var robotList = await _userRepository.Get()
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(t => robotIps.Contains(t.Ip))
|
.Where(t => robotIps.Contains(t.Ip))
|
||||||
.ToDictionaryAsync(t => t.Ip);
|
.ToDictionaryAsync(t => t.Ip);
|
||||||
@@ -59,7 +59,7 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
robotList.TryGetValue(item.Key, out var robot);
|
robotList.TryGetValue(item.Key, out var robot);
|
||||||
|
|
||||||
var userDto = new UserBaseDto { Ip = item.Key, Description = robot?.Description ?? string.Empty, Name = robot?.Name ?? string.Empty };
|
var userDto = new UserBaseDto { Ip = item.Key, Description = robot?.Description ?? string.Empty, Name = robot?.Name ?? string.Empty };
|
||||||
var snapshots = mapper.Map<List<RobotSnapshotDto>>(item).OrderBy(t => t.DateCreated).ToList();
|
var snapshots = _mapper.Map<List<RobotSnapshotDto>>(item).OrderBy(t => t.DateCreated).ToList();
|
||||||
|
|
||||||
result.Add(new RobotSnapshotItemDto { Robot = userDto, Snapshots = snapshots });
|
result.Add(new RobotSnapshotItemDto { Robot = userDto, Snapshots = snapshots });
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
|
|
||||||
public async Task<List<ServerHourlyAnalyticsDto>> GetHourlyAnalyticsAsync(RobotAnalyticsQuery queryDto)
|
public async Task<List<ServerHourlyAnalyticsDto>> GetHourlyAnalyticsAsync(RobotAnalyticsQuery queryDto)
|
||||||
{
|
{
|
||||||
var snapshotsQuery = robotSnapshotRepository.Get()
|
var snapshotsQuery = _robotSnapshotRepository.Get()
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(t => queryDto.DateStart <= t.DateCreated && t.DateCreated <= queryDto.DateEnd);
|
.Where(t => queryDto.DateStart <= t.DateCreated && t.DateCreated <= queryDto.DateEnd);
|
||||||
|
|
||||||
@@ -78,9 +78,6 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
if (!string.IsNullOrEmpty(queryDto.Ip))
|
if (!string.IsNullOrEmpty(queryDto.Ip))
|
||||||
snapshotsQuery = snapshotsQuery.Where(t => t.Ip == queryDto.Ip);
|
snapshotsQuery = snapshotsQuery.Where(t => t.Ip == queryDto.Ip);
|
||||||
|
|
||||||
// Превращает TimeSpan в строку вида "+03:00" или "-05:00"
|
|
||||||
string formattedOffset = (queryDto.Offset >= TimeSpan.Zero ? "+" : "-") +
|
|
||||||
queryDto.Offset.ToString(@"hh\:mm");
|
|
||||||
|
|
||||||
// Группируем на стороне PostgreSQL с учетом часового пояса пользователя.
|
// Группируем на стороне PostgreSQL с учетом часового пояса пользователя.
|
||||||
// Метод .Add(offset) сдвигает UTC-дату в Postgres на интервал времени пользователя,
|
// Метод .Add(offset) сдвигает UTC-дату в Postgres на интервал времени пользователя,
|
||||||
@@ -117,12 +114,12 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
|
|
||||||
// Получаем информацию о серверах
|
// Получаем информацию о серверах
|
||||||
var serverIps = rawGroupedData.Select(g => g.Ip).ToHashSet();
|
var serverIps = rawGroupedData.Select(g => g.Ip).ToHashSet();
|
||||||
var serverDictionary = await userRepository.Get()
|
var serverDictionary = await _userRepository.Get()
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(t => serverIps.Contains(t.Ip))
|
.Where(t => serverIps.Contains(t.Ip))
|
||||||
.ToDictionaryAsync(t => t.Ip);
|
.ToDictionaryAsync(t => t.Ip);
|
||||||
|
|
||||||
// Группируем полученные агрегаты по серверам уже в памяти веб-сервера
|
// Группируем полученные агрегаты по серверам уже в памяти
|
||||||
var dataByServers = rawGroupedData.GroupBy(g => g.Ip);
|
var dataByServers = rawGroupedData.GroupBy(g => g.Ip);
|
||||||
var result = new List<ServerHourlyAnalyticsDto>();
|
var result = new List<ServerHourlyAnalyticsDto>();
|
||||||
|
|
||||||
@@ -206,6 +203,103 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<List<HourlyRobotTypeAnalyticsDto>> GetHourlyAnalyticsByRobotTypeAsync(RobotAnalyticsRobotTypeQuery queryDto)
|
||||||
|
{
|
||||||
|
var snapshotsQuery = _robotSnapshotRepository.Get()
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(t => queryDto.DateStart <= t.DateCreated && t.DateCreated <= queryDto.DateEnd)
|
||||||
|
.GroupBy(t => new
|
||||||
|
{
|
||||||
|
// Явно сдвигаем дату
|
||||||
|
Year = (t.DateCreated + queryDto.Offset).DateTime.Year,
|
||||||
|
Month = (t.DateCreated + queryDto.Offset).DateTime.Month,
|
||||||
|
Day = (t.DateCreated + queryDto.Offset).DateTime.Day,
|
||||||
|
Hour = (t.DateCreated + queryDto.Offset).DateTime.Hour
|
||||||
|
});
|
||||||
|
|
||||||
|
IQueryable<RobotSnapshotRobotTypeDbDto> groupedQuery;
|
||||||
|
|
||||||
|
switch (queryDto.RobotType)
|
||||||
|
{
|
||||||
|
case Domain.Enums.RobotsEnum.TemplateOrder:
|
||||||
|
groupedQuery = snapshotsQuery.Select(g => new RobotSnapshotRobotTypeDbDto
|
||||||
|
{
|
||||||
|
// Вытаскиваем компоненты даты из уже смещенного локального времени
|
||||||
|
LocalYear = g.Key.Year,
|
||||||
|
LocalMonth = g.Key.Month,
|
||||||
|
LocalDay = g.Key.Day,
|
||||||
|
LocalHour = g.Key.Hour,
|
||||||
|
|
||||||
|
// Макс не правильно.
|
||||||
|
//MaxAllowed = g.Max(t => t.MaxRobots),
|
||||||
|
Sum = g.Sum(t => t.TemplateRobotsCount)
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case Domain.Enums.RobotsEnum.ScheduleOrder:
|
||||||
|
groupedQuery = snapshotsQuery.Select(g => new RobotSnapshotRobotTypeDbDto
|
||||||
|
{
|
||||||
|
// Вытаскиваем компоненты даты из уже смещенного локального времени
|
||||||
|
LocalYear = g.Key.Year,
|
||||||
|
LocalMonth = g.Key.Month,
|
||||||
|
LocalDay = g.Key.Day,
|
||||||
|
LocalHour = g.Key.Hour,
|
||||||
|
|
||||||
|
// Макс не правильно.
|
||||||
|
//MaxAllowed = g.Max(t => t.MaxRobots),
|
||||||
|
Sum = g.Sum(t => t.ScheduleRobotsCount)
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Не обработано значение параметра", nameof(queryDto.RobotType));
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = await groupedQuery.ToListAsync();
|
||||||
|
|
||||||
|
if (!data.Any())
|
||||||
|
return new List<HourlyRobotTypeAnalyticsDto>();
|
||||||
|
|
||||||
|
var dbDataDict = data.ToDictionary(
|
||||||
|
k => new DateTime(k.LocalYear, k.LocalMonth, k.LocalDay, k.LocalHour, 0, 0),
|
||||||
|
v => new
|
||||||
|
{
|
||||||
|
//MaxAllowedRobots = t.MaxAllowed,
|
||||||
|
AvgRobots = Math.Round(v.Sum / 60.0, 1)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Заполняем модель
|
||||||
|
var statistics = new List<HourlyRobotTypeAnalyticsDto>();
|
||||||
|
|
||||||
|
#region Алгоритм заполнения пропусков во времени (если сервер был выключен)
|
||||||
|
// Превращаем границы в локальное время для генерации сетки часов
|
||||||
|
var currentHour = queryDto.DateStart.ToOffset(queryDto.Offset).DateTime;
|
||||||
|
var localEnd = queryDto.DateEnd.ToOffset(queryDto.Offset).DateTime;
|
||||||
|
|
||||||
|
// Срезаем минуты/секунды для старта
|
||||||
|
currentHour = new DateTime(currentHour.Year, currentHour.Month, currentHour.Day, currentHour.Hour, 0, 0);
|
||||||
|
|
||||||
|
while (currentHour <= localEnd)
|
||||||
|
{
|
||||||
|
// Ищем значение в словаре. Если нет — ставим 0
|
||||||
|
dbDataDict.TryGetValue(currentHour, out var statInfo);
|
||||||
|
|
||||||
|
// 1. Создаем DateTimeOffset для локального времени с правильным смещением
|
||||||
|
var localDateTimeOffset = new DateTimeOffset(currentHour, queryDto.Offset);
|
||||||
|
|
||||||
|
statistics.Add(new HourlyRobotTypeAnalyticsDto
|
||||||
|
{
|
||||||
|
// Возвращаем DateTimeOffset с нулевым смещением (как в вашем коде) или с queryDto.Offset
|
||||||
|
Hour = localDateTimeOffset.ToUniversalTime(),
|
||||||
|
AvgRobots = statInfo?.AvgRobots ?? 0
|
||||||
|
});
|
||||||
|
|
||||||
|
currentHour = currentHour.AddHours(1);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
return statistics;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<RobotSnapshotItemDto> CreateAsync(CreateRobotSnapshot robotSnapshot)
|
public async Task<RobotSnapshotItemDto> CreateAsync(CreateRobotSnapshot robotSnapshot)
|
||||||
{
|
{
|
||||||
var snapshot = new RobotSnapshot
|
var snapshot = new RobotSnapshot
|
||||||
@@ -217,19 +311,19 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
Ip = robotSnapshot.Ip
|
Ip = robotSnapshot.Ip
|
||||||
};
|
};
|
||||||
|
|
||||||
var createdResult = await robotSnapshotRepository.CreateAsync(snapshot);
|
var createdResult = await _robotSnapshotRepository.CreateAsync(snapshot);
|
||||||
var commitResult = await robotSnapshotRepository.CommitAsync();
|
var commitResult = await _robotSnapshotRepository.CommitAsync();
|
||||||
|
|
||||||
if (!createdResult || !commitResult)
|
if (!createdResult || !commitResult)
|
||||||
throw new DbErrorException("Ошибка сохранения в БД");
|
throw new DbErrorException("Ошибка сохранения в БД");
|
||||||
|
|
||||||
var user = await userRepository.Get().AsNoTracking().FirstOrDefaultAsync(t => t.Ip == robotSnapshot.Ip);
|
var user = await _userRepository.Get().AsNoTracking().FirstOrDefaultAsync(t => t.Ip == robotSnapshot.Ip);
|
||||||
var userDto = new UserBaseDto { Ip = robotSnapshot.Ip, Description = user?.Description ?? string.Empty, Name = user?.Name ?? string.Empty };
|
var userDto = new UserBaseDto { Ip = robotSnapshot.Ip, Description = user?.Description ?? string.Empty, Name = user?.Name ?? string.Empty };
|
||||||
|
|
||||||
var result = new RobotSnapshotItemDto
|
var result = new RobotSnapshotItemDto
|
||||||
{
|
{
|
||||||
Robot = userDto,
|
Robot = userDto,
|
||||||
Snapshots = mapper.Map<List<RobotSnapshotDto>>(new List<RobotSnapshot> { snapshot })
|
Snapshots = _mapper.Map<List<RobotSnapshotDto>>(new List<RobotSnapshot> { snapshot })
|
||||||
};
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Почасовая статистика по снапшотам роботов
|
||||||
|
/// </summary>
|
||||||
|
public record HourlyRobotTypeAnalyticsDto
|
||||||
|
{
|
||||||
|
public DateTimeOffset Hour { get; init; }
|
||||||
|
|
||||||
|
//public int MaxAllowedRobots { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Среднее кол-во роботов работающих в течении часа
|
||||||
|
/// </summary>
|
||||||
|
public double AvgRobots { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,30 @@
|
|||||||
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
using PARR.Domain.Enums;
|
||||||
|
|
||||||
|
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
||||||
{
|
{
|
||||||
public record RobotAnalyticsQuery
|
public record RobotAnalyticsBaseQuery
|
||||||
{
|
{
|
||||||
public DateTimeOffset DateStart { get; init; }
|
public DateTimeOffset DateStart { get; init; }
|
||||||
|
|
||||||
public DateTimeOffset DateEnd { get; init; }
|
public DateTimeOffset DateEnd { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Смещение часового пояса
|
/// Смещение часового пояса
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan Offset { get; init; }
|
public TimeSpan Offset { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record RobotAnalyticsRobotTypeQuery : RobotAnalyticsBaseQuery
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Тип робота
|
||||||
|
/// </summary>
|
||||||
|
public RobotsEnum RobotType { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public record RobotAnalyticsQuery : RobotAnalyticsBaseQuery
|
||||||
|
{
|
||||||
public string? Ip { get; init; }
|
public string? Ip { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Селект из БД по снапшотам по типам роботов
|
||||||
|
/// </summary>
|
||||||
|
public record RobotSnapshotRobotTypeDbDto
|
||||||
|
{
|
||||||
|
public int LocalYear { get; init; }
|
||||||
|
|
||||||
|
public int LocalMonth { get; init; }
|
||||||
|
|
||||||
|
public int LocalDay { get; init; }
|
||||||
|
|
||||||
|
public int LocalHour { get; init; }
|
||||||
|
|
||||||
|
//public int MaxAllowed { get; init; }
|
||||||
|
|
||||||
|
public int Sum { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Аналитика по снапшотам роботов
|
/// Аналитика по снапшотам роботов с группировкой по IP робота
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public record ServerHourlyAnalyticsDto
|
public record ServerHourlyAnalyticsDto
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user