优化
This commit is contained in:
@@ -34,31 +34,46 @@ public sealed class GraduationClearanceController(
|
||||
x.Id, x.Name, x.GraduationYear, x.Status, x.Notes,
|
||||
x.ClosedAt, x.CreatedAt, ItemCount = x.Items.Count
|
||||
}).ToListAsync(token);
|
||||
var records = await ScopedRecords().AsNoTracking()
|
||||
.Select(x => new
|
||||
var statistics = await ScopedRecords().AsNoTracking()
|
||||
.GroupBy(x => x.GraduationClearanceItem!.GraduationClearanceBatchId)
|
||||
.Select(group => new
|
||||
{
|
||||
BatchId = x.GraduationClearanceItem!.GraduationClearanceBatchId,
|
||||
x.StudentId, x.Status
|
||||
}).ToListAsync(token);
|
||||
BatchId = group.Key,
|
||||
StudentCount = group.Select(x => x.StudentId).Distinct().Count(),
|
||||
RecordCount = group.Count(),
|
||||
CompletedCount = group.Count(x =>
|
||||
x.Status != GraduationClearanceRecordStatus.Pending)
|
||||
}).ToDictionaryAsync(x => x.BatchId, token);
|
||||
return Ok(batches.Select(batch =>
|
||||
{
|
||||
var scoped = records.Where(x => x.BatchId == batch.Id).ToList();
|
||||
statistics.TryGetValue(batch.Id, out var summary);
|
||||
return new
|
||||
{
|
||||
batch.Id, batch.Name, batch.GraduationYear, batch.Status,
|
||||
batch.Notes, batch.ClosedAt, batch.CreatedAt, batch.ItemCount,
|
||||
StudentCount = scoped.Select(x => x.StudentId).Distinct().Count(),
|
||||
RecordCount = scoped.Count,
|
||||
CompletedCount = scoped.Count(x =>
|
||||
x.Status != GraduationClearanceRecordStatus.Pending)
|
||||
StudentCount = summary?.StudentCount ?? 0,
|
||||
RecordCount = summary?.RecordCount ?? 0,
|
||||
CompletedCount = summary?.CompletedCount ?? 0
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
[HttpGet("batches/{id:guid}")]
|
||||
[Authorize(Roles = Workers)]
|
||||
public async Task<ActionResult> GetBatch(Guid id, CancellationToken token)
|
||||
public async Task<ActionResult> GetBatch(
|
||||
Guid id,
|
||||
[FromQuery] int page = 1,
|
||||
[FromQuery] int pageSize = 20,
|
||||
[FromQuery] string? keyword = null,
|
||||
[FromQuery] string? progress = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
page = Math.Max(page, 1);
|
||||
pageSize = Math.Clamp(pageSize, 10, 100);
|
||||
var normalizedProgress = progress?.Trim();
|
||||
if (normalizedProgress is not null and not "Pending" and not "Completed")
|
||||
return ValidationProblem("离校办理进度筛选值无效。");
|
||||
|
||||
var batch = await db.GraduationClearanceBatches.AsNoTracking()
|
||||
.Where(x => x.Id == id)
|
||||
.Select(x => new
|
||||
@@ -72,8 +87,56 @@ public sealed class GraduationClearanceController(
|
||||
})
|
||||
}).FirstOrDefaultAsync(token);
|
||||
if (batch is null) return NotFound();
|
||||
var records = await ScopedRecords().AsNoTracking()
|
||||
.Where(x => x.GraduationClearanceItem!.GraduationClearanceBatchId == id)
|
||||
|
||||
var records = ScopedRecords().AsNoTracking()
|
||||
.Where(x => x.GraduationClearanceItem!.GraduationClearanceBatchId == id);
|
||||
var summary = await records
|
||||
.GroupBy(_ => 1)
|
||||
.Select(group => new
|
||||
{
|
||||
StudentCount = group.Select(x => x.StudentId).Distinct().Count(),
|
||||
RecordCount = group.Count(),
|
||||
CompletedCount = group.Count(x =>
|
||||
x.Status != GraduationClearanceRecordStatus.Pending)
|
||||
})
|
||||
.FirstOrDefaultAsync(token);
|
||||
|
||||
var students = db.Students.AsNoTracking()
|
||||
.Where(student => records.Any(record => record.StudentId == student.Id));
|
||||
var normalizedKeyword = keyword?.Trim();
|
||||
if (!string.IsNullOrWhiteSpace(normalizedKeyword))
|
||||
students = students.Where(student =>
|
||||
student.StudentNumber.Contains(normalizedKeyword) ||
|
||||
student.Name.Contains(normalizedKeyword) ||
|
||||
student.AdministrativeClass!.Name.Contains(normalizedKeyword) ||
|
||||
student.AdministrativeClass.Major!.Name.Contains(normalizedKeyword));
|
||||
if (normalizedProgress == "Pending")
|
||||
students = students.Where(student => records.Any(record =>
|
||||
record.StudentId == student.Id &&
|
||||
record.GraduationClearanceItem!.IsRequired &&
|
||||
record.Status == GraduationClearanceRecordStatus.Pending));
|
||||
else if (normalizedProgress == "Completed")
|
||||
students = students.Where(student => !records.Any(record =>
|
||||
record.StudentId == student.Id &&
|
||||
record.GraduationClearanceItem!.IsRequired &&
|
||||
record.Status == GraduationClearanceRecordStatus.Pending));
|
||||
|
||||
var total = await students.CountAsync(token);
|
||||
var studentPage = await students
|
||||
.OrderBy(student => student.StudentNumber)
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.Select(student => new
|
||||
{
|
||||
student.Id,
|
||||
student.StudentNumber,
|
||||
student.Name,
|
||||
ClassName = student.AdministrativeClass!.Name,
|
||||
MajorName = student.AdministrativeClass.Major!.Name
|
||||
}).ToListAsync(token);
|
||||
var studentIds = studentPage.Select(student => student.Id).ToArray();
|
||||
var pageRecords = await records
|
||||
.WhereIn(studentIds, x => x.StudentId)
|
||||
.OrderBy(x => x.Student!.StudentNumber)
|
||||
.ThenBy(x => x.GraduationClearanceItem!.SortOrder)
|
||||
.Select(x => new
|
||||
@@ -89,11 +152,32 @@ public sealed class GraduationClearanceController(
|
||||
x.GraduationClearanceItem.IsRequired,
|
||||
x.Status, x.Notes, x.CompletedAt
|
||||
}).ToListAsync(token);
|
||||
var recordsByStudent = pageRecords
|
||||
.GroupBy(record => record.StudentId)
|
||||
.ToDictionary(group => group.Key, group => group.ToList());
|
||||
var studentItems = studentPage.Select(student => new
|
||||
{
|
||||
StudentId = student.Id,
|
||||
student.StudentNumber,
|
||||
student.Name,
|
||||
student.ClassName,
|
||||
student.MajorName,
|
||||
Records = recordsByStudent.GetValueOrDefault(student.Id) ?? []
|
||||
}).ToList();
|
||||
return Ok(new
|
||||
{
|
||||
batch.Id, batch.Name, batch.GraduationYear, batch.Status,
|
||||
batch.Notes, batch.ClosedAt, batch.CreatedAt, batch.Items,
|
||||
Records = records
|
||||
StudentCount = summary?.StudentCount ?? 0,
|
||||
RecordCount = summary?.RecordCount ?? 0,
|
||||
CompletedCount = summary?.CompletedCount ?? 0,
|
||||
Students = new
|
||||
{
|
||||
Items = studentItems,
|
||||
Total = total,
|
||||
Page = page,
|
||||
PageSize = pageSize
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -150,16 +234,15 @@ public sealed class GraduationClearanceController(
|
||||
if (batch.Status != GraduationClearanceBatchStatus.Open)
|
||||
return ConflictProblem("已关闭批次不能重新生成办理记录。");
|
||||
|
||||
var eligibleAudits = await db.GraduationAuditResults.AsNoTracking()
|
||||
var studentIds = await db.GraduationAuditResults.AsNoTracking()
|
||||
.Where(x =>
|
||||
x.GraduationAuditBatch!.GraduationYear == batch.GraduationYear &&
|
||||
x.GraduationAuditBatch.Status == GraduationAuditBatchStatus.Published &&
|
||||
x.Conclusion == GraduationAuditConclusion.Eligible &&
|
||||
x.Student!.Status == StudentStatus.Graduated)
|
||||
.OrderByDescending(x => x.GraduationAuditBatch!.PublishedAt)
|
||||
.Select(x => new { x.StudentId })
|
||||
.Select(x => x.StudentId)
|
||||
.Distinct()
|
||||
.ToListAsync(token);
|
||||
var studentIds = eligibleAudits.Select(x => x.StudentId).Distinct().ToArray();
|
||||
var existing = await db.GraduationClearanceRecords.AsNoTracking()
|
||||
.Where(x => x.GraduationClearanceItem!.GraduationClearanceBatchId == id)
|
||||
.Select(x => new { x.GraduationClearanceItemId, x.StudentId })
|
||||
@@ -180,7 +263,7 @@ public sealed class GraduationClearanceController(
|
||||
created++;
|
||||
}
|
||||
await db.SaveChangesAsync(token);
|
||||
return Ok(new { StudentCount = studentIds.Length, CreatedRecordCount = created });
|
||||
return Ok(new { StudentCount = studentIds.Count, CreatedRecordCount = created });
|
||||
}
|
||||
|
||||
[HttpPut("records/{id:guid}")]
|
||||
@@ -221,15 +304,17 @@ public sealed class GraduationClearanceController(
|
||||
public async Task<ActionResult> Close(Guid id, CancellationToken token)
|
||||
{
|
||||
var batch = await db.GraduationClearanceBatches
|
||||
.Include(x => x.Items)
|
||||
.ThenInclude(x => x.Records)
|
||||
.FirstOrDefaultAsync(x => x.Id == id, token);
|
||||
if (batch is null) return NotFound();
|
||||
if (batch.Status != GraduationClearanceBatchStatus.Open)
|
||||
return ConflictProblem("该批次已经关闭。");
|
||||
var records = batch.Items.SelectMany(item => item.Records.Select(record =>
|
||||
(item.IsRequired, record.Status)));
|
||||
if (!GraduationClearanceRules.CanClose(records))
|
||||
var hasIncompleteRequiredItem = await db.GraduationClearanceRecords
|
||||
.AnyAsync(record =>
|
||||
record.GraduationClearanceItem!.GraduationClearanceBatchId == id &&
|
||||
record.GraduationClearanceItem.IsRequired &&
|
||||
record.Status == GraduationClearanceRecordStatus.Pending,
|
||||
token);
|
||||
if (hasIncompleteRequiredItem)
|
||||
return ConflictProblem("仍有必办离校事项尚未完成。");
|
||||
batch.Status = GraduationClearanceBatchStatus.Closed;
|
||||
batch.ClosedAt = DateTime.UtcNow;
|
||||
|
||||
Reference in New Issue
Block a user