实验批量发布现在会创建持久化后台任务,不再在 HTTP 请求里逐项校验和通知。
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
using Jiaowu.Api.Domain.Academic;
|
||||
using Jiaowu.Api.Domain.System;
|
||||
using Jiaowu.Api.Infrastructure.Caching;
|
||||
using Jiaowu.Api.Controllers;
|
||||
using Jiaowu.Api.Infrastructure.Persistence;
|
||||
using Jiaowu.Api.Infrastructure.Teaching;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Jiaowu.Api.Infrastructure.Exams;
|
||||
|
||||
@@ -39,6 +42,9 @@ public sealed class ExamPublishJobProcessor(
|
||||
case ExamPublishJobKind.MakeupExam:
|
||||
await PublishMakeupExamAsync(job, stoppingToken);
|
||||
break;
|
||||
case ExamPublishJobKind.ExperimentProjects:
|
||||
await PublishExperimentProjectsAsync(job, stoppingToken);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException(
|
||||
$"不支持的考试发布类型:{job.Kind}。");
|
||||
@@ -248,6 +254,58 @@ public sealed class ExamPublishJobProcessor(
|
||||
await db.SaveChangesAsync(ct);
|
||||
}
|
||||
|
||||
private async Task PublishExperimentProjectsAsync(ExamPublishJob job, CancellationToken ct)
|
||||
{
|
||||
var ids = JsonSerializer.Deserialize<List<Guid>>(job.ProjectIdsJson ?? "[]")?
|
||||
.Where(x => x != Guid.Empty).Distinct().ToList() ?? [];
|
||||
if (ids.Count is 0 or > 100)
|
||||
throw new ExamPublishValidationException("实验发布任务的数据无效。请重新提交。");
|
||||
|
||||
var projects = await db.ExperimentProjects
|
||||
.Include(x => x.Sessions)
|
||||
.Include(x => x.TeachingTask)
|
||||
.ThenInclude(x => x!.Course)
|
||||
.Where(x => ids.Contains(x.Id))
|
||||
.ToListAsync(ct);
|
||||
if (projects.Count != ids.Count)
|
||||
throw new ExamPublishValidationException("部分实验项目不存在,请刷新后重新提交。");
|
||||
|
||||
foreach (var project in projects)
|
||||
{
|
||||
if (project.Status != ExperimentProjectStatus.Draft)
|
||||
throw new ExamPublishValidationException("批量发布只能包含草稿实验项目。");
|
||||
var hasSchedule = project.ArrangementMode == ExperimentArrangementMode.Centralized
|
||||
? project.ScheduleEntryId.HasValue || project.Sessions.Any(x => x.Status == ExperimentSessionStatus.Scheduled)
|
||||
: project.Sessions.Any(x => x.Status == ExperimentSessionStatus.Scheduled);
|
||||
if (!hasSchedule)
|
||||
throw new ExamPublishValidationException($"“{project.Name}”尚未具备发布条件。");
|
||||
if (project.Sessions.Any(x => x.Status == ExperimentSessionStatus.Scheduled &&
|
||||
(x.SessionDate < project.StartDate || x.SessionDate > project.EndDate)))
|
||||
throw new ExamPublishValidationException($"“{project.Name}”存在不在开放日期范围内的实验场次。");
|
||||
}
|
||||
|
||||
job.CurrentStep = "正在发布实验项目";
|
||||
await db.SaveChangesAsync(ct);
|
||||
var publishedAt = DateTime.UtcNow;
|
||||
foreach (var project in projects)
|
||||
{
|
||||
project.Status = ExperimentProjectStatus.Published;
|
||||
project.PublishedAt = publishedAt;
|
||||
}
|
||||
await db.SaveChangesAsync(ct);
|
||||
|
||||
foreach (var project in projects)
|
||||
{
|
||||
var userIds = await TeachingTaskRosterQuery.ForTask(db, project.TeachingTaskId)
|
||||
.Where(x => x.UserId.HasValue).Select(x => x.UserId!.Value).Distinct().ToListAsync(ct);
|
||||
if (userIds.Count == 0) continue;
|
||||
var mode = project.ArrangementMode == ExperimentArrangementMode.Centralized ? "集中安排" : "自行预约";
|
||||
await NotificationService.SendToUserIdsAsync(db, userIds, "实验项目已发布",
|
||||
$"《{project.TeachingTask!.Course!.Name}》已发布“{project.Name}”({mode}),请查看实验安排。",
|
||||
"/experiments", ct, NotificationCategory.Schedule);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task MarkFailedAsync(Guid jobId, string message)
|
||||
{
|
||||
db.ChangeTracker.Clear();
|
||||
|
||||
Reference in New Issue
Block a user