Add grid auto-build functionality with profile management and preview capabilities
Implemented new API endpoints and frontend components for grid auto-building based on predefined profiles. Added functionality to list grid profiles, preview generated grids, and generate grids with specified parameters. Enhanced the TemplateEndpoints and related services to support these features, improving the user experience for channel scheduling. Localization updates were made to accommodate new features in both English and Russian.
This commit is contained in:
+12
-37
@@ -14,8 +14,6 @@ public sealed class ValidateTemplateQueryHandler(
|
||||
DynamicGroupResolver dynamicResolver
|
||||
) : IQueryHandler<ValidateTemplateQuery, Result<IReadOnlyList<TemplateIssueDto>>>
|
||||
{
|
||||
private const int MinutesInDay = 24 * 60;
|
||||
|
||||
public async Task<Result<IReadOnlyList<TemplateIssueDto>>> Handle(
|
||||
ValidateTemplateQuery query,
|
||||
CancellationToken cancellationToken
|
||||
@@ -167,7 +165,9 @@ public sealed class ValidateTemplateQueryHandler(
|
||||
/// </summary>
|
||||
private static IEnumerable<TemplateIssueDto> FindOverlaps(GridLayer layer, TimeOnly dayStart)
|
||||
{
|
||||
var slots = layer.Slots.OrderBy(s => OffsetInDay(s.TargetStart, dayStart)).ToList();
|
||||
var slots = layer
|
||||
.Slots.OrderBy(s => GridCoverage.OffsetInDay(s.TargetStart, dayStart))
|
||||
.ToList();
|
||||
|
||||
// Внешний цикл в фигурных скобках намеренно: без них вложенный for выглядит как соседний,
|
||||
// и «телом» внешнего цикла его читает только компилятор.
|
||||
@@ -180,8 +180,8 @@ public sealed class ValidateTemplateQueryHandler(
|
||||
if (!SameDays(a, b))
|
||||
continue;
|
||||
|
||||
var aFrom = OffsetInDay(a.TargetStart, dayStart);
|
||||
var bFrom = OffsetInDay(b.TargetStart, dayStart);
|
||||
var aFrom = GridCoverage.OffsetInDay(a.TargetStart, dayStart);
|
||||
var bFrom = GridCoverage.OffsetInDay(b.TargetStart, dayStart);
|
||||
if (
|
||||
aFrom < bFrom + b.TargetDurationMinutes
|
||||
&& bFrom < aFrom + a.TargetDurationMinutes
|
||||
@@ -210,30 +210,11 @@ public sealed class ValidateTemplateQueryHandler(
|
||||
TimeOnly dayStart
|
||||
)
|
||||
{
|
||||
foreach (var weekday in new[] { 1, 2, 3, 4, 5, 6, 0 })
|
||||
{
|
||||
var intervals = layers
|
||||
.SelectMany(l => l.Slots)
|
||||
.Where(s => s.Weekday is null || s.Weekday == weekday)
|
||||
.Select(s =>
|
||||
{
|
||||
var from = OffsetInDay(s.TargetStart, dayStart);
|
||||
return (From: from, To: from + s.TargetDurationMinutes);
|
||||
})
|
||||
.OrderBy(i => i.From)
|
||||
.ToList();
|
||||
var slots = layers.SelectMany(l => l.Slots).ToList();
|
||||
|
||||
var cursor = 0;
|
||||
foreach (var interval in intervals)
|
||||
{
|
||||
if (interval.From > cursor)
|
||||
yield return Gap(weekday, cursor, interval.From, dayStart);
|
||||
cursor = Math.Max(cursor, Math.Min(interval.To, MinutesInDay));
|
||||
}
|
||||
|
||||
if (cursor < MinutesInDay)
|
||||
yield return Gap(weekday, cursor, MinutesInDay, dayStart);
|
||||
}
|
||||
foreach (var weekday in GridCoverage.Week)
|
||||
foreach (var (from, to) in GridCoverage.Gaps(slots, weekday, dayStart))
|
||||
yield return Gap(weekday, from, to, dayStart);
|
||||
}
|
||||
|
||||
private static TemplateIssueDto Gap(int weekday, int from, int to, TimeOnly dayStart)
|
||||
@@ -241,7 +222,7 @@ public sealed class ValidateTemplateQueryHandler(
|
||||
var day = new[] { "вс", "пн", "вт", "ср", "чт", "пт", "сб" }[weekday];
|
||||
// Сутки целиком: «00:00–00:00» читалось бы как пустой интервал, а это ровно наоборот.
|
||||
var interval =
|
||||
to - from >= MinutesInDay
|
||||
to - from >= GridCoverage.MinutesInDay
|
||||
? "весь день"
|
||||
: $"{Clock(from, dayStart)}–{Clock(to, dayStart)}";
|
||||
|
||||
@@ -256,14 +237,8 @@ public sealed class ValidateTemplateQueryHandler(
|
||||
|
||||
private static string Clock(int offsetMinutes, TimeOnly dayStart)
|
||||
{
|
||||
var minutes = ((int)dayStart.ToTimeSpan().TotalMinutes + offsetMinutes) % MinutesInDay;
|
||||
return $"{minutes / 60:00}:{minutes % 60:00}";
|
||||
}
|
||||
|
||||
private static int OffsetInDay(TimeOnly time, TimeOnly dayStart)
|
||||
{
|
||||
var diff = (int)(time.ToTimeSpan() - dayStart.ToTimeSpan()).TotalMinutes;
|
||||
return diff >= 0 ? diff : diff + MinutesInDay;
|
||||
var time = GridCoverage.AtOffset(offsetMinutes, dayStart);
|
||||
return $"{time.Hour:00}:{time.Minute:00}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user