已完成教学任务归档纠错功能:

已归档任务新增“撤销归档”和“删除”,支持单条及批量操作。
撤销后恢复为“已发布”状态。
已发布任务仍不可直接删除;被排课、选课、成绩或考试引用的归档任务也会拒绝删除并明确提示。
状态与操作文案统一为“归档”
This commit is contained in:
2026-07-25 11:03:42 +08:00 Unverified
parent e4a12931ea
commit a63c943815
3 changed files with 279 additions and 24 deletions
@@ -228,10 +228,14 @@ public sealed class TeachingTasksController(
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
if (task is null) return NotFound();
if (!CanManage(task.Course!)) return Forbid();
if (task.Status != TeachingTaskStatus.Draft)
return ConflictProblem("仅草稿教学任务可以删除。");
if (task.Status is not (TeachingTaskStatus.Draft or TeachingTaskStatus.Closed))
return ConflictProblem("仅草稿或已归档的教学任务可以删除。");
db.TeachingTasks.Remove(task);
return await SaveAsync(id, false, cancellationToken);
return await SaveAsync(
id,
false,
cancellationToken,
"教学任务已被排课、选课、成绩或考试等业务引用,不能删除;如需继续使用,可撤销归档。");
}
[HttpPost("{id:guid}/publish")]
@@ -263,11 +267,25 @@ public sealed class TeachingTasksController(
if (task is null) return NotFound();
if (!CanManage(task.Course!)) return Forbid();
if (task.Status != TeachingTaskStatus.Published)
return ConflictProblem("只有已发布的教学任务可以结课。");
return ConflictProblem("只有已发布的教学任务可以归档。");
task.Status = TeachingTaskStatus.Closed;
return await SaveAsync(id, false, cancellationToken);
}
[HttpPost("{id:guid}/unarchive")]
public async Task<ActionResult> Unarchive(Guid id, CancellationToken cancellationToken)
{
var task = await ScopedTasks()
.Include(x => x.Course)
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
if (task is null) return NotFound();
if (!CanManage(task.Course!)) return Forbid();
if (task.Status != TeachingTaskStatus.Closed)
return ConflictProblem("只有已归档的教学任务可以撤销归档。");
task.Status = TeachingTaskStatus.Published;
return await SaveAsync(id, false, cancellationToken);
}
[HttpPost("batch")]
public async Task<ActionResult> Batch(
TeachingTaskBatchRequest request,
@@ -305,9 +323,10 @@ public sealed class TeachingTasksController(
break;
}
case TeachingTaskBatchOperation.Delete:
if (tasks.Any(x => x.Status != TeachingTaskStatus.Draft))
if (tasks.Any(x =>
x.Status is not (TeachingTaskStatus.Draft or TeachingTaskStatus.Closed)))
return ConflictProblem(
$"教学任务“{tasks.First(x => x.Status != TeachingTaskStatus.Draft).Name}”不是草稿,整批未删除。");
$"教学任务“{tasks.First(x => x.Status is not (TeachingTaskStatus.Draft or TeachingTaskStatus.Closed)).Name}”不是草稿或已归档状态,整批未删除。");
db.TeachingTasks.RemoveRange(tasks);
break;
case TeachingTaskBatchOperation.Archive:
@@ -316,6 +335,12 @@ public sealed class TeachingTasksController(
$"教学任务“{tasks.First(x => x.Status != TeachingTaskStatus.Published).Name}”不是已发布状态,整批未归档。");
foreach (var task in tasks) task.Status = TeachingTaskStatus.Closed;
break;
case TeachingTaskBatchOperation.Unarchive:
if (tasks.Any(x => x.Status != TeachingTaskStatus.Closed))
return ConflictProblem(
$"教学任务“{tasks.First(x => x.Status != TeachingTaskStatus.Closed).Name}”不是已归档状态,整批未撤销归档。");
foreach (var task in tasks) task.Status = TeachingTaskStatus.Published;
break;
default:
return ValidationProblem("不支持的批量操作。");
}
@@ -664,7 +689,8 @@ public sealed class TeachingTasksController(
private async Task<ActionResult> SaveAsync(
Guid id,
bool created,
CancellationToken cancellationToken)
CancellationToken cancellationToken,
string conflictMessage = "教学任务编号重复,或关联数据已失效。")
{
try
{
@@ -673,7 +699,7 @@ public sealed class TeachingTasksController(
}
catch (DbUpdateException)
{
return ConflictProblem("教学任务编号重复,或关联数据已失效。");
return ConflictProblem(conflictMessage);
}
}
@@ -739,5 +765,6 @@ public enum TeachingTaskBatchOperation
{
Publish = 1,
Delete = 2,
Archive = 3
Archive = 3,
Unarchive = 4
}