diff --git a/VOL.Business/IServices/School/IS_StudentService.cs b/VOL.Business/IServices/School/IS_StudentService.cs
index b8504a8..2ef95fc 100644
--- a/VOL.Business/IServices/School/IS_StudentService.cs
+++ b/VOL.Business/IServices/School/IS_StudentService.cs
@@ -62,6 +62,13 @@ namespace VOL.Business.IServices.School
///
Task UpdateStudentPwd(UpdateStudentPwdParam paramDto);
+ ///
+ /// 批量删除当前学校学生
+ ///
+ /// 学生Id
+ /// 实际删除数量
+ Task BatchDeleteStudents(List ids);
+
///
/// 转班
///
@@ -169,5 +176,20 @@ namespace VOL.Business.IServices.School
///
///
Task ReplaceClasses(List studentNoList, int classId);
+
+ ///
+ /// 获取当前学校一键升学状态
+ ///
+ Task GetPromotionStatus();
+
+ ///
+ /// 当前学校学生一键升学
+ ///
+ Task PromoteStudents();
+
+ ///
+ /// 撤回当前学校最近一次升学
+ ///
+ Task UndoPromotion();
}
}
diff --git a/VOL.Business/Services/School/S_StudentService.cs b/VOL.Business/Services/School/S_StudentService.cs
index b419996..8c36a8c 100644
--- a/VOL.Business/Services/School/S_StudentService.cs
+++ b/VOL.Business/Services/School/S_StudentService.cs
@@ -420,6 +420,47 @@ namespace VOL.Business.Services.School
});
}
+ public async Task BatchDeleteStudents(List ids)
+ {
+ if (UserContext.Current.RoleId != 1 && UserContext.Current.RoleId != 2)
+ throw new Exception("仅管理员可以批量删除学生");
+
+ var studentIds = ids?.Where(x => x > 0).Distinct().ToList() ?? new List();
+ if (studentIds.Count == 0)
+ throw new ArgumentException("请至少选择一名学生");
+
+ 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()
+ .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()
+ .CountAsync(x => x.BatchId == activeBatchId.Value && studentIds.Contains(x.StudentId));
+ if (promotionStudentCount > 0)
+ throw new Exception($"所选学生中有{promotionStudentCount}人属于当前可撤回的升学记录,请先撤回升学后再删除");
+ }
+
+ _studentRepository.DbContext.RemoveRange(students);
+ await _studentRepository.SaveChangesAsync();
+
+ await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
+ {
+ EventType = EventType.Delete.GetDisplayName(),
+ DataType = IOTDataSyncType.Student.GetDisplayName(),
+ Json = JsonConvert.SerializeObject(students)
+ });
+
+ return students.Count;
+ }
+
public async Task ChangeClasses(string studentNo, int classId)
{
var student = await _studentRepository.FindAsyncFirst(x => x.StudentNo == studentNo);
@@ -1324,5 +1365,434 @@ namespace VOL.Business.Services.School
await _studentRepository.SaveChangesAsync();
}
+
+ public async Task GetPromotionStatus()
+ {
+ var school = await GetPromotionSchool();
+ var academicYear = GetAcademicYear(DateTime.Now);
+ var latestBatch = await _studentRepository.DbContext.Set()
+ .Where(x => x.SchoolCode == school.SchoolCode)
+ .OrderByDescending(x => x.Id)
+ .FirstOrDefaultAsync();
+ var currentBatchExists = await _studentRepository.DbContext.Set()
+ .AnyAsync(x => x.SchoolCode == school.SchoolCode &&
+ x.AcademicYear == academicYear &&
+ x.Status == 1);
+
+ var gradeIds = new List();
+ string gradeConfigurationReason = null;
+ try
+ {
+ gradeIds = await GetPromotionGradeIds(school);
+ var existingGradeCount = await _studentRepository.DbContext.Set()
+ .CountAsync(x => gradeIds.Contains(x.Id));
+ if (existingGradeCount != gradeIds.Count)
+ gradeConfigurationReason = $"年级基础数据不完整,应存在{gradeIds.Count}个年级,实际存在{existingGradeCount}个";
+ }
+ catch (InvalidOperationException ex)
+ {
+ gradeConfigurationReason = ex.Message;
+ }
+
+ var studentCount = 0;
+ if (string.IsNullOrWhiteSpace(gradeConfigurationReason))
+ {
+ studentCount = await _studentRepository.FindAsIQueryable(x =>
+ x.SchoolCode == school.SchoolCode &&
+ x.StudentStatus == StudentStatus.Normal)
+ .Join(_studentRepository.DbContext.Set().Where(x => gradeIds.Contains(x.GradeId)),
+ student => student.ClassId,
+ schoolClass => schoolClass.Id,
+ (student, schoolClass) => student.Id)
+ .CountAsync();
+ }
+
+ var cannotPromoteReason = currentBatchExists
+ ? $"{academicYear}学年已经执行过一键升学,如需重新操作请先撤回升学"
+ : gradeConfigurationReason ?? (studentCount == 0 ? "当前学校没有可升学的在读学生" : null);
+ var cannotUndoReason = latestBatch == null
+ ? "当前学校没有升学记录"
+ : latestBatch.Status != 1 ? "最近一次升学已经撤回,没有可撤回的升学记录" : null;
+
+ return new StudentPromotionStatusModel
+ {
+ SchoolNature = latestBatch?.SchoolNatureName ?? await GetSchoolNatureName(school.SchoolNatureId),
+ AcademicYear = academicYear,
+ CanPromote = string.IsNullOrWhiteSpace(cannotPromoteReason),
+ CannotPromoteReason = cannotPromoteReason,
+ CanUndo = latestBatch?.Status == 1,
+ CannotUndoReason = cannotUndoReason,
+ StudentCount = studentCount,
+ PromotedCount = latestBatch?.PromotedCount ?? 0,
+ GraduatedCount = latestBatch?.GraduatedCount ?? 0,
+ PromotionTime = latestBatch?.CreateDate
+ };
+ }
+
+ public async Task PromoteStudents()
+ {
+ var school = await GetPromotionSchool();
+ var academicYear = GetAcademicYear(DateTime.Now);
+ var gradeIds = await GetPromotionGradeIds(school);
+ var natureName = await GetSchoolNatureName(school.SchoolNatureId);
+
+ var hasPromoted = await _studentRepository.DbContext.Set()
+ .AnyAsync(x => x.SchoolCode == school.SchoolCode &&
+ x.AcademicYear == academicYear &&
+ x.Status == 1);
+ if (hasPromoted)
+ throw new Exception($"{academicYear}学年已经执行过升学,请勿重复操作");
+
+ var grades = await _studentRepository.DbContext.Set()
+ .Where(x => gradeIds.Contains(x.Id))
+ .OrderBy(x => x.Id)
+ .ToListAsync();
+ var classes = await _studentRepository.DbContext.Set()
+ .Where(x => x.SchoolCode == school.SchoolCode && gradeIds.Contains(x.GradeId))
+ .ToListAsync();
+ var classIds = classes.Select(x => x.Id).ToList();
+ var students = await _studentRepository.FindAsIQueryable(x =>
+ x.SchoolCode == school.SchoolCode &&
+ x.StudentStatus == StudentStatus.Normal &&
+ classIds.Contains(x.ClassId))
+ .ToListAsync();
+
+ if (students.Count == 0)
+ throw new Exception("当前学校没有可升学的在读学生");
+
+ var classById = classes.ToDictionary(x => x.Id);
+ var gradeIndex = grades.Select((grade, index) => new { grade.Id, Index = index })
+ .ToDictionary(x => x.Id, x => x.Index);
+ var targetClasses = new Dictionary();
+ var classesToCreate = new List();
+ var classLookup = classes
+ .GroupBy(x => $"{x.GradeId}|{GetClassKey(x.ClassName, x.GradeName).ToUpperInvariant()}")
+ .ToDictionary(x => x.Key, x => x.First());
+ var now = DateTime.Now;
+
+ foreach (var sourceClassId in classes.Select(x => x.Id).Distinct())
+ {
+ var sourceClass = classById[sourceClassId];
+ var sourceGradeIndex = gradeIndex[sourceClass.GradeId];
+ if (sourceGradeIndex == grades.Count - 1)
+ continue;
+
+ var targetGrade = grades[sourceGradeIndex + 1];
+ var classKey = GetClassKey(sourceClass.ClassName, sourceClass.GradeName);
+ var lookupKey = $"{targetGrade.Id}|{classKey.ToUpperInvariant()}";
+ if (!classLookup.TryGetValue(lookupKey, out var targetClass))
+ {
+ var sourceClassName = (sourceClass.ClassName ?? string.Empty).Trim();
+ var sourceGradeName = (sourceClass.GradeName ?? string.Empty).Trim();
+ var targetClassName = !string.IsNullOrEmpty(sourceGradeName) &&
+ sourceClassName.StartsWith(sourceGradeName, StringComparison.OrdinalIgnoreCase)
+ ? $"{targetGrade.GradeName}{classKey}"
+ : sourceClassName;
+ targetClass = new S_Class
+ {
+ SchoolCode = school.SchoolCode,
+ GradeId = targetGrade.Id,
+ GradeName = targetGrade.GradeName,
+ ClassName = targetClassName,
+ Creator = UserContext.Current.UserId,
+ CreateDate = now
+ };
+ classesToCreate.Add(targetClass);
+ classLookup[lookupKey] = targetClass;
+ }
+
+ targetClasses[sourceClassId] = targetClass;
+ }
+
+ var highestGradeId = grades.Last().Id;
+ var teacherAssociations = await _studentRepository.DbContext.Set()
+ .Where(x => classIds.Contains(x.ClassId))
+ .ToListAsync();
+ var batch = new S_StudentPromotionBatch
+ {
+ SchoolCode = school.SchoolCode,
+ SchoolNatureId = school.SchoolNatureId,
+ SchoolNatureName = natureName,
+ AcademicYear = academicYear,
+ Status = 1,
+ PromotedCount = students.Count(x => classById[x.ClassId].GradeId != highestGradeId),
+ GraduatedCount = students.Count(x => classById[x.ClassId].GradeId == highestGradeId),
+ OperatorId = UserContext.Current.UserId,
+ CreateDate = now
+ };
+
+ using (var transaction = await _studentRepository.DbContext.Database.BeginTransactionAsync())
+ {
+ try
+ {
+ await _studentRepository.DbContext.Set().AddAsync(batch);
+ await _studentRepository.SaveChangesAsync();
+
+ if (classesToCreate.Count > 0)
+ {
+ classesToCreate.ForEach(x => x.Remarks = $"一键升学自动创建,批次Id:{batch.Id}");
+ await _studentRepository.DbContext.Set().AddRangeAsync(classesToCreate);
+ await _studentRepository.SaveChangesAsync();
+ }
+
+ var teacherSnapshots = teacherAssociations.Select(association =>
+ {
+ var sourceClass = classById[association.ClassId];
+ var isGraduating = sourceClass.GradeId == highestGradeId;
+ return new TeacherPromotionSnapshotItem
+ {
+ AssociationId = association.Id,
+ TeacherId = association.TeacherId,
+ OriginalClassId = association.ClassId,
+ TargetClassId = isGraduating ? 0 : targetClasses[sourceClass.Id].Id,
+ Creator = association.Creator,
+ CreateDate = association.CreateDate,
+ Modifier = association.Modifier,
+ ModifyDate = association.ModifyDate
+ };
+ }).ToList();
+ batch.TeacherSnapshot = JsonConvert.SerializeObject(teacherSnapshots);
+ _studentRepository.DbContext.Set().Update(batch);
+
+ foreach (var association in teacherAssociations)
+ {
+ var sourceClass = classById[association.ClassId];
+ if (sourceClass.GradeId == highestGradeId)
+ {
+ _studentRepository.DbContext.Set().Remove(association);
+ continue;
+ }
+
+ association.ClassId = targetClasses[sourceClass.Id].Id;
+ association.Modifier = UserContext.Current.UserId;
+ association.ModifyDate = now;
+ _studentRepository.DbContext.Set().Update(association);
+ }
+
+ var details = new List();
+ foreach (var student in students)
+ {
+ var sourceClass = classById[student.ClassId];
+ var isGraduating = sourceClass.GradeId == highestGradeId;
+ var targetClass = isGraduating ? sourceClass : targetClasses[sourceClass.Id];
+ var targetStatus = isGraduating ? StudentStatus.Grad : student.StudentStatus;
+
+ details.Add(new S_StudentPromotionDetail
+ {
+ BatchId = batch.Id,
+ StudentId = student.Id,
+ OriginalClassId = student.ClassId,
+ OriginalClassName = student.ClassName,
+ OriginalStatus = student.StudentStatus,
+ OriginalAge = student.Age,
+ TargetClassId = targetClass.Id,
+ TargetClassName = targetClass.ClassName,
+ TargetStatus = targetStatus,
+ TargetAge = student.Age + 1
+ });
+
+ student.ClassId = targetClass.Id;
+ student.ClassName = targetClass.ClassName;
+ student.StudentStatus = targetStatus;
+ student.Age += 1;
+ student.Modifier = UserContext.Current.UserId;
+ student.ModifyDate = now;
+ }
+
+ await _studentRepository.DbContext.Set().AddRangeAsync(details);
+ _studentRepository.UpdateRange(students);
+ await _studentRepository.SaveChangesAsync();
+ await transaction.CommitAsync();
+ }
+ catch
+ {
+ await transaction.RollbackAsync();
+ throw;
+ }
+ }
+
+ return await GetPromotionStatus();
+ }
+
+ public async Task UndoPromotion()
+ {
+ var school = await GetPromotionSchool();
+ var batch = await _studentRepository.DbContext.Set()
+ .Where(x => x.SchoolCode == school.SchoolCode)
+ .OrderByDescending(x => x.Id)
+ .FirstOrDefaultAsync();
+ if (batch == null || batch.Status != 1)
+ throw new Exception("当前学校没有可撤回的升学记录");
+
+ var details = await _studentRepository.DbContext.Set()
+ .Where(x => x.BatchId == batch.Id)
+ .ToListAsync();
+ var studentIds = details.Select(x => x.StudentId).ToList();
+ var students = await _studentRepository.FindAsIQueryable(x => studentIds.Contains(x.Id)).ToListAsync();
+ var studentById = students.ToDictionary(x => x.Id);
+ var teacherSnapshots = string.IsNullOrWhiteSpace(batch.TeacherSnapshot)
+ ? new List()
+ : JsonConvert.DeserializeObject>(batch.TeacherSnapshot)
+ ?? new List();
+ var shiftedAssociationIds = teacherSnapshots
+ .Where(x => x.TargetClassId > 0)
+ .Select(x => x.AssociationId)
+ .ToList();
+ var currentTeacherAssociations = await _studentRepository.DbContext.Set()
+ .Where(x => shiftedAssociationIds.Contains(x.Id))
+ .ToListAsync();
+ var currentTeacherAssociationById = currentTeacherAssociations.ToDictionary(x => x.Id);
+
+ var changedCount = details.Count(detail =>
+ !studentById.TryGetValue(detail.StudentId, out var student) ||
+ student.ClassId != detail.TargetClassId ||
+ student.StudentStatus != detail.TargetStatus ||
+ student.Age != detail.TargetAge);
+ if (changedCount > 0)
+ throw new Exception($"升学后已有{changedCount}名学生的班级、状态或年龄被修改,无法自动撤回");
+
+ var changedTeacherCount = teacherSnapshots.Count(snapshot =>
+ snapshot.TargetClassId > 0 &&
+ (!currentTeacherAssociationById.TryGetValue(snapshot.AssociationId, out var association) ||
+ association.TeacherId != snapshot.TeacherId ||
+ association.ClassId != snapshot.TargetClassId));
+ if (changedTeacherCount > 0)
+ throw new Exception($"升学后已有{changedTeacherCount}条教师班级关系被修改,无法自动撤回");
+
+ var now = DateTime.Now;
+ using (var transaction = await _studentRepository.DbContext.Database.BeginTransactionAsync())
+ {
+ try
+ {
+ 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().Update(association);
+ }
+ else
+ {
+ await _studentRepository.DbContext.Set().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().Update(batch);
+ await _studentRepository.SaveChangesAsync();
+ await transaction.CommitAsync();
+ }
+ catch
+ {
+ await transaction.RollbackAsync();
+ throw;
+ }
+ }
+
+ return await GetPromotionStatus();
+ }
+
+ private async Task GetPromotionSchool()
+ {
+ if (UserContext.Current.RoleId != 2)
+ throw new Exception("仅学校管理员可以执行一键升学");
+
+ var school = await _studentRepository.DbContext.Set()
+ .FirstOrDefaultAsync(x => x.SchoolCode == UserContext.Current.TenantId && x.SchoolType == SchoolType.School);
+ if (school == null)
+ throw new Exception("未找到当前学校信息");
+
+ return school;
+ }
+
+ private async Task> GetPromotionGradeIds(S_School school)
+ {
+ var natureGradeIds = await _studentRepository.DbContext.Set()
+ .Where(x => x.NatureId == school.SchoolNatureId)
+ .OrderBy(x => x.GradeId)
+ .Select(x => x.GradeId)
+ .Distinct()
+ .ToListAsync();
+ if (natureGradeIds.Count == 0)
+ throw new InvalidOperationException("当前学校性质未配置年级,无法执行一键升学");
+
+ var schoolGradeIds = await _studentRepository.DbContext.Set()
+ .Where(x => x.SchoolCode == school.SchoolCode)
+ .Select(x => x.GradeId)
+ .Distinct()
+ .ToListAsync();
+ var gradeIds = natureGradeIds.Where(schoolGradeIds.Contains).ToList();
+ if (gradeIds.Count != natureGradeIds.Count)
+ throw new InvalidOperationException($"当前学校年级配置不完整,应配置{natureGradeIds.Count}个年级,实际配置{gradeIds.Count}个");
+
+ return gradeIds;
+ }
+
+ private async Task GetSchoolNatureName(int natureId)
+ {
+ return await _studentRepository.DbContext.Set()
+ .Where(x => x.Id == natureId)
+ .Select(x => x.NatureName)
+ .FirstOrDefaultAsync() ?? "未知";
+ }
+
+ private static string GetAcademicYear(DateTime date)
+ {
+ var startYear = date.Month >= 7 ? date.Year : date.Year - 1;
+ return $"{startYear}-{startYear + 1}";
+ }
+
+ private static string GetClassKey(string className, string gradeName)
+ {
+ var value = (className ?? string.Empty).Trim();
+ var grade = (gradeName ?? string.Empty).Trim();
+ if (!string.IsNullOrEmpty(grade) && value.StartsWith(grade, StringComparison.OrdinalIgnoreCase))
+ value = value.Substring(grade.Length).Trim();
+ return value;
+ }
+
+ private class TeacherPromotionSnapshotItem
+ {
+ public int AssociationId { get; set; }
+
+ public int TeacherId { get; set; }
+
+ public int OriginalClassId { get; set; }
+
+ public int TargetClassId { get; set; }
+
+ public int Creator { get; set; }
+
+ public DateTime? CreateDate { get; set; }
+
+ public int Modifier { get; set; }
+
+ public DateTime? ModifyDate { get; set; }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/VOL.Core/Migrations/20260722034330_20260722StudentPromotion.Designer.cs b/VOL.Core/Migrations/20260722034330_20260722StudentPromotion.Designer.cs
new file mode 100644
index 0000000..b46ed25
--- /dev/null
+++ b/VOL.Core/Migrations/20260722034330_20260722StudentPromotion.Designer.cs
@@ -0,0 +1,8294 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using VOL.Core.EFDbContext;
+
+#nullable disable
+
+namespace VOL.Core.Migrations
+{
+ [DbContext(typeof(VOLContext))]
+ [Migration("20260722034330_20260722StudentPromotion")]
+ partial class _20260722StudentPromotion
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "6.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_ActivitiestData", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("ActivitiesId")
+ .HasColumnType("int")
+ .HasComment("活动Id");
+
+ b.Property("AdditionalScore")
+ .HasColumnType("float")
+ .HasComment("附加分");
+
+ b.Property("CategoryValue")
+ .HasColumnType("int")
+ .HasComment("项目类型");
+
+ b.Property("ClassId")
+ .HasColumnType("int")
+ .HasComment("班级Id");
+
+ b.Property("ClassName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("班级名称");
+
+ b.Property("ClassRoomRecordId")
+ .HasColumnType("int")
+ .HasComment("课堂记录Id");
+
+ b.Property("Code")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("AI设备的唯一编码");
+
+ b.Property("CorrectJudge")
+ .HasColumnType("nvarchar(4000)")
+ .HasComment("动作解析");
+
+ b.Property("CorrectNumber")
+ .HasColumnType("int")
+ .HasComment("正确个数");
+
+ b.Property("DataType")
+ .HasColumnType("int")
+ .HasComment("模式类型");
+
+ b.Property("Duration")
+ .HasColumnType("int")
+ .HasComment("持续时间");
+
+ b.Property("EndTime")
+ .HasColumnType("datetime")
+ .HasComment("结束时间");
+
+ b.Property("ErrorNumber")
+ .HasColumnType("int")
+ .HasComment("错误个数");
+
+ b.Property("GradeId")
+ .HasColumnType("int")
+ .HasComment("年级编号");
+
+ b.Property("GradeName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("年级名称");
+
+ b.Property("IsDisplay")
+ .HasColumnType("bit")
+ .HasComment("是否显示");
+
+ b.Property("MaxValue")
+ .HasColumnType("int")
+ .HasComment("最大");
+
+ b.Property("MinValue")
+ .HasColumnType("int")
+ .HasComment("最小");
+
+ b.Property("ModeType")
+ .HasColumnType("int")
+ .HasComment("模式类型");
+
+ b.Property("ModelName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("模式名称");
+
+ b.Property("MotionDuration")
+ .HasColumnType("int")
+ .HasComment("运动时长/分钟");
+
+ b.Property("Rank")
+ .HasColumnType("int")
+ .HasComment("训练成绩等级");
+
+ b.Property("RankStr")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("等级");
+
+ b.Property("Remark")
+ .HasColumnType("nvarchar(4000)")
+ .HasComment("设备评价语");
+
+ b.Property("SchoolCode")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学校Code");
+
+ b.Property("Score")
+ .HasColumnType("float")
+ .HasComment("得分");
+
+ b.Property("ScoreTime")
+ .HasColumnType("datetime")
+ .HasComment("测试时间");
+
+ b.Property("Semester")
+ .HasColumnType("int)")
+ .HasComment("学期");
+
+ b.Property("Sex")
+ .HasColumnType("int")
+ .HasComment("学校Co性别de");
+
+ b.Property("StartTime")
+ .HasColumnType("datetime")
+ .HasComment("开始时间");
+
+ b.Property("StudentName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("姓名");
+
+ b.Property("StudentNo")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学号");
+
+ b.Property("TeacherId")
+ .HasColumnType("int")
+ .HasComment("老师Id");
+
+ b.Property("UniqueId")
+ .HasColumnType("bigint")
+ .HasComment("设备上传成绩时唯一标识, 重复时服务端不保存数据");
+
+ b.Property("Value")
+ .HasColumnType("float")
+ .HasComment("测试成绩");
+
+ b.Property("WrongResults")
+ .HasColumnType("float")
+ .HasComment("错误成绩");
+
+ b.Property("Year")
+ .HasColumnType("int)")
+ .HasComment("当前年份");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_ActivitiestData");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_ClassRoomRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("AddCount")
+ .HasColumnType("int")
+ .HasComment("新增人数");
+
+ b.Property("ClassId")
+ .HasColumnType("int")
+ .HasComment("班级Id");
+
+ b.Property("ClassName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("班级名称");
+
+ b.Property("Code")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("AI设备的唯一编码");
+
+ b.Property("EndTime")
+ .HasColumnType("datetime")
+ .HasComment("结束时间");
+
+ b.Property("GradeId")
+ .HasColumnType("int")
+ .HasComment("年级编号");
+
+ b.Property("GradeName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("年级名称");
+
+ b.Property("IsDisplay")
+ .HasColumnType("bit")
+ .HasComment("是否显示");
+
+ b.Property("Name")
+ .HasColumnType("nvarchar(200)")
+ .HasComment("名称");
+
+ b.Property("NoParticipateCount")
+ .HasColumnType("int")
+ .HasComment("缺勤人数");
+
+ b.Property("ParticipateCount")
+ .HasColumnType("int")
+ .HasComment("参与人数");
+
+ b.Property("Remarks")
+ .HasColumnType("text")
+ .HasComment("备注");
+
+ b.Property("SchoolCode")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学校Code");
+
+ b.Property("Semester")
+ .HasColumnType("int)")
+ .HasComment("学期");
+
+ b.Property("StartTime")
+ .HasColumnType("datetime")
+ .HasComment("开始时间");
+
+ b.Property("StudentCount")
+ .HasColumnType("int")
+ .HasComment("班级下学生人数");
+
+ b.Property("TeacherId")
+ .HasColumnType("int")
+ .HasComment("老师Id");
+
+ b.Property("TeacherName")
+ .HasColumnType("nvarchar(200)")
+ .HasComment("老师姓名");
+
+ b.Property("TrainingModuleEnum")
+ .HasColumnType("int")
+ .HasComment("训练模块枚举");
+
+ b.Property("Year")
+ .HasColumnType("int)")
+ .HasComment("当前年份");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_ClassRoomRecord");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_ClassroomSetting", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("ClassRoomRecordId")
+ .HasColumnType("int")
+ .HasComment("课堂记录Id");
+
+ b.Property("ClassroomStageId")
+ .HasColumnType("int")
+ .HasComment("阶段Id");
+
+ b.Property("Density")
+ .HasColumnType("int")
+ .HasComment("密度");
+
+ b.Property("Duration")
+ .HasColumnType("int")
+ .HasComment("时长");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_ClassroomSetting");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_ClassroomStage", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("Name")
+ .HasColumnType("nvarchar(200)")
+ .HasComment("名称");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_ClassroomStage");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_ClassroomStudentRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("Age")
+ .HasColumnType("int")
+ .HasComment("年龄");
+
+ b.Property("ClassId")
+ .HasColumnType("int")
+ .HasComment("班级Id");
+
+ b.Property("ClassName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("班级名称");
+
+ b.Property("ClassRoomRecordId")
+ .HasColumnType("int")
+ .HasComment("课堂记录Id");
+
+ b.Property("Code")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("AI设备的唯一编码");
+
+ b.Property("GradeId")
+ .HasColumnType("int")
+ .HasComment("年级编号");
+
+ b.Property("GradeName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("年级名称");
+
+ b.Property("IsDisplay")
+ .HasColumnType("bit")
+ .HasComment("是否显示");
+
+ b.Property("SchoolCode")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学校Code");
+
+ b.Property("Sex")
+ .HasColumnType("int")
+ .HasComment("学校Co性别de");
+
+ b.Property("StudentName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("姓名");
+
+ b.Property("StudentNo")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学号");
+
+ b.Property("TeacherId")
+ .HasColumnType("int")
+ .HasComment("老师Id");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ClassRoomRecordId");
+
+ b.ToTable("Ai_ClassroomStudentRecord");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_Device", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("Code")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("AI设备的唯一编码");
+
+ b.Property("CreateDate")
+ .HasColumnType("datetime")
+ .HasComment("创建时间");
+
+ b.Property("Creator")
+ .HasColumnType("int)")
+ .HasComment("创建人");
+
+ b.Property("DeviceType")
+ .HasColumnType("int")
+ .HasComment("设备类型");
+
+ b.Property("EndTime")
+ .HasColumnType("datetime")
+ .HasComment("有效期结束时间");
+
+ b.Property("Modifier")
+ .HasColumnType("int)")
+ .HasComment("修改人");
+
+ b.Property("ModifyDate")
+ .HasColumnType("datetime")
+ .HasComment("修改时间");
+
+ b.Property("Name")
+ .HasColumnType("nvarchar(200)")
+ .HasComment("AI设备名称");
+
+ b.Property("Remarks")
+ .HasColumnType("text")
+ .HasComment("备注");
+
+ b.Property("StartTime")
+ .HasColumnType("datetime")
+ .HasComment("有效期开始时间");
+
+ b.Property("Status")
+ .HasColumnType("int")
+ .HasComment("设备状态 固定值:1:启用2:禁用,禁用的设备无法使用");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_Device");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_DeviceAssocSchool", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("Code")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("AI设备的唯一编码");
+
+ b.Property("SchoolCode")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学校编号");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_DeviceAssocSchool");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_FastJumpRopeData", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("ClassId")
+ .HasColumnType("int")
+ .HasComment("班级Id");
+
+ b.Property("ClassName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("班级名称");
+
+ b.Property("ClassRoomRecordId")
+ .HasColumnType("int")
+ .HasComment("课堂记录Id");
+
+ b.Property("Code")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("AI设备的唯一编码");
+
+ b.Property("EndTime")
+ .HasColumnType("datetime")
+ .HasComment("结束时间");
+
+ b.Property("ErrorNumber")
+ .HasColumnType("int")
+ .HasComment("错误个数");
+
+ b.Property("GradeId")
+ .HasColumnType("int")
+ .HasComment("年级编号");
+
+ b.Property("GradeName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("年级名称");
+
+ b.Property("GroupId")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("GroupId");
+
+ b.Property("IsDisplay")
+ .HasColumnType("bit")
+ .HasComment("是否显示");
+
+ b.Property("JumpValue")
+ .HasColumnType("int")
+ .HasComment("正确个数");
+
+ b.Property("ModeType")
+ .HasColumnType("int")
+ .HasComment("模式类型");
+
+ b.Property("ModelName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("模式名称");
+
+ b.Property("MotionDuration")
+ .HasColumnType("int")
+ .HasComment("运动时长/秒");
+
+ b.Property("Rank")
+ .HasColumnType("int")
+ .HasComment("等级");
+
+ b.Property("RankEnum")
+ .HasColumnType("int")
+ .HasComment("训练成绩等级");
+
+ b.Property("SchoolCode")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学校Code");
+
+ b.Property("ScoreTime")
+ .HasColumnType("datetime")
+ .HasComment("测试时间");
+
+ b.Property("Sex")
+ .HasColumnType("int")
+ .HasComment("学校Co性别de");
+
+ b.Property("StartTime")
+ .HasColumnType("datetime")
+ .HasComment("开始时间");
+
+ b.Property("StudentCount")
+ .HasColumnType("int")
+ .HasComment("测试人数");
+
+ b.Property("StudentName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("姓名");
+
+ b.Property("StudentNo")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学号");
+
+ b.Property("TeacherId")
+ .HasColumnType("int")
+ .HasComment("老师Id");
+
+ b.Property("TrainingModule")
+ .HasColumnType("int")
+ .HasComment("训练模块[[1:专项教学/2:测评考级/3:AI赛场/4:AI体测]/5:速度跳绳");
+
+ b.Property("UniqueId")
+ .HasColumnType("bigint")
+ .HasComment("设备上传成绩时唯一标识, 重复时服务端不保存数据");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_FastJumpRopeData");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_HeartRateData", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("ClassId")
+ .HasColumnType("int")
+ .HasComment("班级Id");
+
+ b.Property("ClassName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("班级名称");
+
+ b.Property("ClassRoomRecordId")
+ .HasColumnType("int")
+ .HasComment("课堂记录Id");
+
+ b.Property("ClassroomStageId")
+ .HasColumnType("int")
+ .HasComment("阶段Id");
+
+ b.Property("Code")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("AI设备的唯一编码");
+
+ b.Property("Consumption")
+ .HasColumnType("int")
+ .HasComment("运动消耗");
+
+ b.Property("GradeId")
+ .HasColumnType("int")
+ .HasComment("年级编号");
+
+ b.Property("GradeName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("年级名称");
+
+ b.Property("IsDisplay")
+ .HasColumnType("bit")
+ .HasComment("是否显示");
+
+ b.Property("MotionDuration")
+ .HasColumnType("int")
+ .HasComment("运动时长/分钟");
+
+ b.Property("Remarks")
+ .HasColumnType("text")
+ .HasComment("备注");
+
+ b.Property("SchoolCode")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学校Code");
+
+ b.Property("ScoreTime")
+ .HasColumnType("datetime")
+ .HasComment("测试时间");
+
+ b.Property("Sex")
+ .HasColumnType("int")
+ .HasComment("学校Co性别de");
+
+ b.Property("Strength")
+ .HasColumnType("double")
+ .HasComment("运动强度");
+
+ b.Property("StudentName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("姓名");
+
+ b.Property("StudentNo")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学号");
+
+ b.Property("TeacherId")
+ .HasColumnType("int")
+ .HasComment("老师Id");
+
+ b.Property("Value")
+ .HasColumnType("double")
+ .HasComment("心率");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_HeartRateData");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_LevelExamData", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("AssessmentResults")
+ .HasColumnType("int")
+ .HasComment("是否通过");
+
+ b.Property("ClassId")
+ .HasColumnType("int")
+ .HasComment("班级Id");
+
+ b.Property("ClassName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("班级名称");
+
+ b.Property("ClassRoomRecordId")
+ .HasColumnType("int")
+ .HasComment("课堂记录Id");
+
+ b.Property("Code")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("AI设备的唯一编码");
+
+ b.Property("CorrectJudge")
+ .HasColumnType("nvarchar(4000)")
+ .HasComment("动作解析");
+
+ b.Property("CorrectNumber")
+ .HasColumnType("int")
+ .HasComment("正确个数");
+
+ b.Property("Duration")
+ .HasColumnType("int")
+ .HasComment("持续时间");
+
+ b.Property("EndTime")
+ .HasColumnType("datetime")
+ .HasComment("结束时间");
+
+ b.Property("ErrorNumber")
+ .HasColumnType("int")
+ .HasComment("错误个数");
+
+ b.Property("FileName")
+ .HasColumnType("nvarchar(2000)")
+ .HasComment("文件名称");
+
+ b.Property("FileUrl")
+ .HasColumnType("nvarchar(2000)")
+ .HasComment("文件路径");
+
+ b.Property("GradeId")
+ .HasColumnType("int")
+ .HasComment("年级编号");
+
+ b.Property("GradeName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("年级名称");
+
+ b.Property("IsDisplay")
+ .HasColumnType("bit")
+ .HasComment("是否显示");
+
+ b.Property("MaxValue")
+ .HasColumnType("int")
+ .HasComment("最大");
+
+ b.Property("MinValue")
+ .HasColumnType("int")
+ .HasComment("最小");
+
+ b.Property("MotionDuration")
+ .HasColumnType("int")
+ .HasComment("运动时长/分钟");
+
+ b.Property("Rank")
+ .HasColumnType("int")
+ .HasComment("专项测评等级");
+
+ b.Property("RankStr")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("专项测评等级");
+
+ b.Property("Remark")
+ .HasColumnType("nvarchar(4000)")
+ .HasComment("设备评价语");
+
+ b.Property("SchoolCode")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学校Code");
+
+ b.Property("Score")
+ .HasColumnType("float")
+ .HasComment("得分");
+
+ b.Property("ScoreTime")
+ .HasColumnType("datetime")
+ .HasComment("测试时间");
+
+ b.Property("Semester")
+ .HasColumnType("int)")
+ .HasComment("学期");
+
+ b.Property("Sex")
+ .HasColumnType("int")
+ .HasComment("学校Co性别de");
+
+ b.Property("SpecialId")
+ .HasColumnType("int")
+ .HasComment("专项类型Id");
+
+ b.Property("StartTime")
+ .HasColumnType("datetime")
+ .HasComment("开始时间");
+
+ b.Property("StudentName")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("姓名");
+
+ b.Property("StudentNo")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学号");
+
+ b.Property("TeacherId")
+ .HasColumnType("int")
+ .HasComment("老师Id");
+
+ b.Property("TeacherPhone")
+ .HasColumnType("varchar(11)")
+ .HasComment("老师手机号");
+
+ b.Property("UniqueId")
+ .HasColumnType("bigint")
+ .HasComment("设备上传成绩时唯一标识, 重复时服务端不保存数据");
+
+ b.Property("Value")
+ .HasColumnType("float")
+ .HasComment("测试成绩");
+
+ b.Property("WrongResults")
+ .HasColumnType("float")
+ .HasComment("错误成绩");
+
+ b.Property("Year")
+ .HasColumnType("int)")
+ .HasComment("当前年份");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_LevelExamData");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_Mode", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("ModeEnum")
+ .HasColumnType("int")
+ .HasComment("模式枚举");
+
+ b.Property("ModeName")
+ .HasColumnType("nvarchar(200)")
+ .HasComment("AI模式名称");
+
+ b.Property("Remarks")
+ .HasColumnType("text")
+ .HasComment("备注");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_Mode");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_ModeAssocModule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("ModeId")
+ .HasColumnType("int")
+ .HasComment("模式Id");
+
+ b.Property("TrainingModuleId")
+ .HasColumnType("int")
+ .HasComment("模块Id");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_ModeAssocModule");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_ScanCodeLogin", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
+
+ b.Property("Code")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("AI设备的唯一编码");
+
+ b.Property("CreateDate")
+ .HasColumnType("datetime")
+ .HasComment("创建时间");
+
+ b.Property("SchoolCode")
+ .HasColumnType("nvarchar(100)")
+ .HasComment("学校编号");
+
+ b.Property("TeacherId")
+ .HasColumnType("int")
+ .HasComment("老师Id");
+
+ b.Property("TeacherPhoneNo")
+ .HasColumnType("nvarchar(20)")
+ .HasComment("老师联系方式");
+
+ b.HasKey("Id");
+
+ b.ToTable("Ai_ScanCodeLogin");
+ });
+
+ modelBuilder.Entity("VOL.Entity.DomainModels.Ai_Special", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasComment("Id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property