feature: Digitization Workstation UI
This commit is contained in:
@@ -9,10 +9,12 @@ using Microsoft.EntityFrameworkCore;
|
||||
public class WorkQueueService : IWorkQueueService
|
||||
{
|
||||
private readonly AppDbContext _db;
|
||||
private readonly ILogger<WorkQueueService> _logger;
|
||||
|
||||
public WorkQueueService(AppDbContext db)
|
||||
public WorkQueueService(AppDbContext db, ILogger<WorkQueueService> logger)
|
||||
{
|
||||
_db = db;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<WorkQueueResponse> GetVerificationQueueAsync(int page, int pageSize)
|
||||
@@ -80,4 +82,77 @@ public class WorkQueueService : IWorkQueueService
|
||||
|
||||
return new WorkQueueResponse(queueName, items, page, pageSize, totalCount, totalPages);
|
||||
}
|
||||
|
||||
public async Task<WorkQueueOverviewResponse> GetOverviewAsync()
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
var statusGroups = await _db.DigitizationBatches
|
||||
.AsNoTracking()
|
||||
.GroupBy(b => b.Status)
|
||||
.Select(g => new { Status = g.Key, Count = g.Count() })
|
||||
.ToListAsync();
|
||||
|
||||
var statusCounts = new Dictionary<string, int>();
|
||||
foreach (var status in Enum.GetValues<BatchStatus>())
|
||||
{
|
||||
var count = statusGroups.FirstOrDefault(g => g.Status == status)?.Count ?? 0;
|
||||
statusCounts[status.ToDbString()] = count;
|
||||
}
|
||||
|
||||
var pendingBatches = await _db.DigitizationBatches
|
||||
.AsNoTracking()
|
||||
.Where(b => b.Status == BatchStatus.PendingVerification)
|
||||
.Select(b => b.UpdatedAt)
|
||||
.ToListAsync();
|
||||
|
||||
double avgTimeInQueueMinutes = 0;
|
||||
double oldestPendingMinutes = 0;
|
||||
|
||||
if (pendingBatches.Count > 0)
|
||||
{
|
||||
var ages = pendingBatches
|
||||
.Select(updatedAt => (now - updatedAt).TotalMinutes)
|
||||
.ToList();
|
||||
|
||||
avgTimeInQueueMinutes = ages.Average();
|
||||
oldestPendingMinutes = ages.Max();
|
||||
}
|
||||
|
||||
var cutoff = now.AddHours(-24);
|
||||
|
||||
var recentEvents = await _db.DigitizationEvents
|
||||
.AsNoTracking()
|
||||
.Where(e => e.OccurredAt >= cutoff)
|
||||
.Where(e => e.EventType == DigitizationEventType.Rejected
|
||||
|| e.EventType == DigitizationEventType.Verified
|
||||
|| e.EventType == DigitizationEventType.VerifiedPendingClinical)
|
||||
.GroupBy(e => e.EventType)
|
||||
.Select(g => new { EventType = g.Key, Count = g.Count() })
|
||||
.ToListAsync();
|
||||
|
||||
var rejections = recentEvents
|
||||
.Where(e => e.EventType == DigitizationEventType.Rejected)
|
||||
.Sum(e => e.Count);
|
||||
|
||||
var verifications = recentEvents
|
||||
.Where(e => e.EventType == DigitizationEventType.Verified
|
||||
|| e.EventType == DigitizationEventType.VerifiedPendingClinical)
|
||||
.Sum(e => e.Count);
|
||||
|
||||
var totalDecisions = rejections + verifications;
|
||||
var rejectRate = totalDecisions > 0
|
||||
? (double)rejections / totalDecisions
|
||||
: 0.0;
|
||||
|
||||
_logger.LogDebug(
|
||||
"Work queue overview: {PendingCount} pending, avg queue {AvgMinutes:F1}m, reject rate {RejectRate:P1}",
|
||||
pendingBatches.Count, avgTimeInQueueMinutes, rejectRate);
|
||||
|
||||
return new WorkQueueOverviewResponse(
|
||||
StatusCounts: statusCounts,
|
||||
AverageTimeInQueueMinutes: Math.Round(avgTimeInQueueMinutes, 1),
|
||||
RejectRate: Math.Round(rejectRate, 4),
|
||||
OldestPendingVerificationMinutes: Math.Round(oldestPendingMinutes, 1));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user