允许删除已升学学生并校验空班级删除

This commit is contained in:
ltx 2026-10-08 15:18:44 +08:00
parent bfea00c64f
commit de898f75ce
4 changed files with 122 additions and 61 deletions

View File

@ -57,6 +57,11 @@ namespace VOL.Business.IServices.School
/// <returns></returns>
Task ModifyClass(ModifyClassParam paramDto);
/// <summary>
/// 删除没有学生的班级
/// </summary>
Task<bool> DeleteClass(int classId);
/// <summary>
/// 班级数据统计
///</summary>

View File

@ -3,6 +3,7 @@ using Castle.DynamicProxy.Generators;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System.Data;
using VOL.Business.IServices.Norm;
using VOL.Business.IServices.School;
using VOL.Core.CacheManager;
@ -384,6 +385,44 @@ namespace VOL.Business.Services.School
}
}
/// <summary>
/// 删除空班级,同时清理班级与老师的关联
/// </summary>
public async Task<bool> DeleteClass(int classId)
{
if (classId <= 0)
throw new ArgumentException("班级参数无效");
var tenantId = UserContext.Current.TenantId;
await using var transaction = await _classRepository.DbContext.Database.BeginTransactionAsync(IsolationLevel.Serializable);
var classModel = await _classRepository.DbContext.Set<S_Class>()
.FirstOrDefaultAsync(x => x.Id == classId && x.SchoolCode == tenantId);
if (classModel == null)
throw new Exception("班级不存在或无权删除,请刷新列表后重试");
var hasStudents = await _classRepository.DbContext.Set<S_Student>()
.AnyAsync(x => x.ClassId == classId);
if (hasStudents)
return false;
var teacherAssociations = await _classRepository.DbContext.Set<S_ClassAssocTeacher>()
.Where(x => x.ClassId == classId)
.ToListAsync();
_classRepository.DbContext.RemoveRange(teacherAssociations);
_classRepository.DbContext.Remove(classModel);
await _classRepository.SaveChangesAsync();
await transaction.CommitAsync();
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
EventType = EventType.Delete.GetDisplayName(),
DataType = IOTDataSyncType.Class.GetDisplayName(),
Json = JsonConvert.SerializeObject(classModel)
});
return true;
}
/// <summary>
/// 添加班级
/// </summary>
@ -902,4 +941,4 @@ namespace VOL.Business.Services.School
return result;
}
}
}
}

View File

@ -8,6 +8,7 @@ using Newtonsoft.Json;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
@ -443,27 +444,25 @@ namespace VOL.Business.Services.School
if (studentIds.Count == 0)
throw new ArgumentException("请至少选择一名学生");
await using var transaction = await _studentRepository.DbContext.Database.BeginTransactionAsync(IsolationLevel.Serializable);
var activeBatchIds = await _studentRepository.DbContext.Set<S_StudentPromotionBatch>()
.Where(x => x.SchoolCode == UserContext.Current.TenantId && x.Status == 1)
.Select(x => x.Id)
.ToListAsync();
var promotionDetails = await _studentRepository.DbContext.Set<S_StudentPromotionDetail>()
.Where(x => activeBatchIds.Contains(x.BatchId) && studentIds.Contains(x.StudentId))
.ToListAsync();
var students = await _studentRepository.FindAsIQueryable(x =>
x.SchoolCode == UserContext.Current.TenantId && studentIds.Contains(x.Id))
.ToListAsync();
if (students.Count != studentIds.Count)
throw new Exception("部分学生不存在或不属于当前学校,请刷新列表后重新选择");
var activeBatchId = await _studentRepository.DbContext.Set<S_StudentPromotionBatch>()
.Where(x => x.SchoolCode == UserContext.Current.TenantId && x.Status == 1)
.OrderByDescending(x => x.Id)
.Select(x => (int?)x.Id)
.FirstOrDefaultAsync();
if (activeBatchId.HasValue)
{
var promotionStudentCount = await _studentRepository.DbContext.Set<S_StudentPromotionDetail>()
.CountAsync(x => x.BatchId == activeBatchId.Value && studentIds.Contains(x.StudentId));
if (promotionStudentCount > 0)
throw new Exception($"所选学生中有{promotionStudentCount}人属于当前可撤回的升学记录,请先撤回升学后再删除");
}
_studentRepository.DbContext.RemoveRange(promotionDetails);
_studentRepository.DbContext.RemoveRange(students);
await _studentRepository.SaveChangesAsync();
await transaction.CommitAsync();
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
@ -1789,6 +1788,8 @@ namespace VOL.Business.Services.School
public async Task<StudentPromotionStatusModel> UndoPromotion()
{
var school = await GetPromotionSchool();
await using (var transaction = await _studentRepository.DbContext.Database.BeginTransactionAsync(IsolationLevel.Serializable))
{
var batch = await _studentRepository.DbContext.Set<S_StudentPromotionBatch>()
.Where(x => x.SchoolCode == school.SchoolCode)
.OrderByDescending(x => x.Id)
@ -1832,58 +1833,56 @@ namespace VOL.Business.Services.School
throw new Exception($"升学后已有{changedTeacherCount}条教师班级关系被修改,无法自动撤回");
var now = DateTime.Now;
using (var transaction = await _studentRepository.DbContext.Database.BeginTransactionAsync())
try
{
try
foreach (var detail in details)
{
foreach (var detail in details)
{
var student = studentById[detail.StudentId];
student.ClassId = detail.OriginalClassId;
student.ClassName = detail.OriginalClassName;
student.StudentStatus = detail.OriginalStatus;
student.Age = detail.OriginalAge;
student.Modifier = UserContext.Current.UserId;
student.ModifyDate = now;
}
foreach (var snapshot in teacherSnapshots)
{
if (snapshot.TargetClassId > 0)
{
var association = currentTeacherAssociationById[snapshot.AssociationId];
association.ClassId = snapshot.OriginalClassId;
association.Modifier = snapshot.Modifier;
association.ModifyDate = snapshot.ModifyDate;
_studentRepository.DbContext.Set<S_ClassAssocTeacher>().Update(association);
}
else
{
await _studentRepository.DbContext.Set<S_ClassAssocTeacher>().AddAsync(new S_ClassAssocTeacher
{
ClassId = snapshot.OriginalClassId,
TeacherId = snapshot.TeacherId,
Creator = snapshot.Creator,
CreateDate = snapshot.CreateDate,
Modifier = snapshot.Modifier,
ModifyDate = snapshot.ModifyDate
});
}
}
batch.Status = 2;
batch.RevokeOperatorId = UserContext.Current.UserId;
batch.RevokeDate = now;
_studentRepository.UpdateRange(students);
_studentRepository.DbContext.Set<S_StudentPromotionBatch>().Update(batch);
await _studentRepository.SaveChangesAsync();
await transaction.CommitAsync();
var student = studentById[detail.StudentId];
student.ClassId = detail.OriginalClassId;
student.ClassName = detail.OriginalClassName;
student.StudentStatus = detail.OriginalStatus;
student.Age = detail.OriginalAge;
student.Modifier = UserContext.Current.UserId;
student.ModifyDate = now;
}
catch
foreach (var snapshot in teacherSnapshots)
{
await transaction.RollbackAsync();
throw;
if (snapshot.TargetClassId > 0)
{
var association = currentTeacherAssociationById[snapshot.AssociationId];
association.ClassId = snapshot.OriginalClassId;
association.Modifier = snapshot.Modifier;
association.ModifyDate = snapshot.ModifyDate;
_studentRepository.DbContext.Set<S_ClassAssocTeacher>().Update(association);
}
else
{
await _studentRepository.DbContext.Set<S_ClassAssocTeacher>().AddAsync(new S_ClassAssocTeacher
{
ClassId = snapshot.OriginalClassId,
TeacherId = snapshot.TeacherId,
Creator = snapshot.Creator,
CreateDate = snapshot.CreateDate,
Modifier = snapshot.Modifier,
ModifyDate = snapshot.ModifyDate
});
}
}
batch.Status = 2;
batch.RevokeOperatorId = UserContext.Current.UserId;
batch.RevokeDate = now;
_studentRepository.UpdateRange(students);
_studentRepository.DbContext.Set<S_StudentPromotionBatch>().Update(batch);
await _studentRepository.SaveChangesAsync();
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
return await GetPromotionStatus();

View File

@ -101,6 +101,24 @@ namespace VOL.WebApi.Controllers.Business
return Ok("更新成功");
}
/// <summary>
/// 删除空班级
/// </summary>
[HttpPost(nameof(DeleteClass))]
public async Task<ActionResult> DeleteClass([FromQuery] int classId)
{
if (!await _classService.DeleteClass(classId))
{
return new JsonResult(new WebResponseContent
{
Code = 409,
Status = false,
Message = "班级内还有学生,请先删除学生后再删除班级"
});
}
return Ok("删除成功");
}
/// <summary>
/// 班级列表导出
/// </summary>