using AutoMapper; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using VOL.Business.IServices; using VOL.Business.IServices.Norm; using VOL.Business.IServices.School; using VOL.Business.IServices.SportsHall; using VOL.Business.Services.School; using VOL.Core.CacheManager; using VOL.Core.Extensions.AutofacManager; using VOL.Core.ManageUser; using VOL.Core.Utilities; using VOL.Entity.DomainModels; using VOL.Entity.Enum; using VOL.Model; using VOL.Model.IOT.Request; using VOL.Model.School.Request; using VOL.Model.School.Response; using VOL.Model.SportsHall; using VOL.System.IRepositories; using VOL.System.Repositories; namespace VOL.Business.Services.SportsHall { /// /// 运动馆 /// public class SportsHallService : ISportsHallService, IDependency { #region 初始化 private readonly IS_ClassRepository _classRepository; private readonly IS_GradeRepository _gradeRepository; private readonly IS_ClassAssocTeacherRepository _classAssocTeacherRepository; private readonly IS_StudentRepository _studentRepository; IN_HealthStandardsRepository _healthStandardsRepository; IN_SportsTestResultRepository _sportsTestResultRepository; [ActivatorUtilitiesConstructor] public SportsHallService(IS_ClassRepository classRepository, IS_GradeRepository gradeRepository, IS_ClassAssocTeacherRepository classAssocTeacherRepository, IS_StudentRepository studentRepository, IN_HealthStandardsRepository healthStandardsRepository, IN_SportsTestResultRepository sportsTestResultRepository) { _classRepository = classRepository; _gradeRepository = gradeRepository; _classAssocTeacherRepository = classAssocTeacherRepository; _studentRepository = studentRepository; _healthStandardsRepository = healthStandardsRepository; _sportsTestResultRepository = sportsTestResultRepository; } #endregion /// /// 新增班级 /// /// /// public async Task AddClass(AddSportsHallClassParam paramDto) { var tenantId = UserContext.Current.TenantId; var grade = await _gradeRepository.FindAsIQueryable(x => x.GradeName == "运动馆").Select(x => new { x.Id, x.GradeName }).FirstAsync(); var exist = await _classRepository.ExistsAsync(x => x.SchoolCode == tenantId && x.ClassName == paramDto.ClassName && x.GradeId == grade.Id); if (exist) throw new Exception("班级名称已存在"); var classEntity = new S_Class() { GradeId = grade.Id, GradeName = grade.GradeName, ClassName = paramDto.ClassName, Creator = UserContext.Current.UserId, SchoolCode = UserContext.Current.TenantId, CreateDate = DateTime.Now }; using (var transaction = _classRepository.DbContext.Database.BeginTransaction()) { try { await _classRepository.AddAsync(classEntity); await _classRepository.SaveChangesAsync(); int classId = classEntity.Id; var classAssocTeacherList = new List(); paramDto.TeacherIds.ForEach(x => { classAssocTeacherList.Add(new S_ClassAssocTeacher() { ClassId = classId, TeacherId = x, Creator = UserContext.Current.UserId, CreateDate = DateTime.Now, Modifier = UserContext.Current.UserId, ModifyDate = DateTime.Now, }); }); await _classAssocTeacherRepository.AddRangeAsync(classAssocTeacherList); var students = await _studentRepository.FindAsync(x => paramDto.studentNoList.Contains(x.StudentNo)); foreach (var student in students) { student.ClassId = classId; int index = paramDto.studentNoList.IndexOf(student.StudentNo); student.OrderNo = index >= 0 ? index + 1 : 0; } _studentRepository.UpdateRange(students); await _studentRepository.SaveChangesAsync(); // 提交事务 transaction.Commit(); } catch (Exception ex) { // 发生错误,回滚事务 transaction.Rollback(); Console.WriteLine("事务回滚:" + ex.Message); } } } /// /// 更新班级 /// /// /// public async Task ModifyClass(ModifySportsHallClassParam paramDto) { var tenantId = UserContext.Current.TenantId; var classModel = await _classRepository.FindAsyncFirst(x => x.Id == paramDto.ClassId); var grade = await _gradeRepository.FindAsIQueryable(x => x.GradeName == "运动馆").Select(x => new { x.Id, x.GradeName }).FirstAsync(); if (classModel == null) throw new ArgumentNullException("未找到要更新得数据"); var exist = await _classRepository.ExistsAsync( x => x.SchoolCode == tenantId && x.ClassName == paramDto.ClassName && x.GradeId == grade.Id && x.Id != paramDto.ClassId); if (exist) throw new Exception("班级名称已存在"); classModel.ClassName = paramDto.ClassName; using (var transaction = _classRepository.DbContext.Database.BeginTransaction()) { try { _classRepository.Update(classModel); var teacherList = await _classAssocTeacherRepository.FindAsync(x => x.ClassId == paramDto.ClassId); _classAssocTeacherRepository.DbContext.RemoveRange(teacherList); var classAssocTeacherList = new List(); paramDto.TeacherIds.ForEach(x => { classAssocTeacherList.Add(new S_ClassAssocTeacher() { ClassId = paramDto.ClassId, TeacherId = x, Creator = UserContext.Current.UserId, CreateDate = DateTime.Now, Modifier = UserContext.Current.UserId, ModifyDate = DateTime.Now, }); }); await _classAssocTeacherRepository.AddRangeAsync(classAssocTeacherList); var oldStudents = await _studentRepository.FindAsync(x => x.ClassId == classModel.Id); var newStudents = await _studentRepository.FindAsync(x => paramDto.studentNoList.Contains(x.StudentNo)); var allStudents = oldStudents.UnionBy(newStudents, s => s.Id).ToList(); foreach (var student in allStudents) { if (paramDto.studentNoList.Contains(student.StudentNo)) { student.ClassId = classModel.Id; student.OrderNo = paramDto.studentNoList.IndexOf(student.StudentNo) + 1; } else { student.ClassId = 0; student.OrderNo = 0; } } _studentRepository.UpdateRange(allStudents); await _classRepository.SaveChangesAsync(); transaction.Commit(); } catch (Exception ex) { // 发生错误,回滚事务 transaction.Rollback(); Console.WriteLine("事务回滚:" + ex.Message); } } } /// /// 导入运动馆学生体测成绩 /// /// /// /// public async Task SportsHallImportStudentsTestData(IFormFile file) { if (file == null || file.Length <= 0) throw new Exception("操作失败"); List dataObjects; using (var fileStream = file.OpenReadStream()) { dataObjects = Tool.ConvertExcelToList(fileStream); } var studentNos = dataObjects.Select(x => x.StudentNo).Distinct().ToList(); // 用一个查询一次性获取所有学生信息 var students = await (from s in _studentRepository.DbContext.Set() join c in _studentRepository.DbContext.Set() on s.ClassId equals c.Id join g in _studentRepository.DbContext.Set() on c.GradeId equals g.Id where c.SchoolCode.Equals(UserContext.Current.TenantId) select new { s.Id, s.Age, s.ClassId, c.ClassName, s.StudentName, GradeId = g.Id, g.GradeName, s.Sex, s.StudentNo }).ToListAsync(); // 将学生信息存入字典,快速查找 var studentsDict = students.ToDictionary(x => x.StudentNo); var entityList = new List(); foreach (var data in dataObjects) { if (!studentsDict.TryGetValue(data.StudentNo, out var student)) { throw new Exception($"未找到此编号为{data.StudentNo}的学生"); } var timeNow = Convert.ToDateTime(data.ScoreTime); // 为每个学生添加多条体测数据 if (data.BMIValue > 0) entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.BMI, student, data.GradeId, timeNow)); if (data.Sit_And_ReachValue > 0) entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.Sit_And_Reach, student, data.GradeId, timeNow)); if (data.VitalCapacityValue > 0) entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.VitalCapacity, student, data.GradeId, timeNow)); if (data.OneMinuteJumpRopeValue > 0) entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.OneMinuteJumpRope, student, data.GradeId, timeNow)); if (data.One_Minute_Sit_UpValue > 0) entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.One_Minute_Sit_Up, student, data.GradeId, timeNow)); if (data.StandingLongJumpValue > 0) entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.StandingLongJump, student, data.GradeId, timeNow)); } // 批量添加数据 await _sportsTestResultRepository.AddRangeAsync(entityList); // 一次性保存所有修改 await _sportsTestResultRepository.SaveChangesAsync(); } public async Task AddSportsHallEnumStudentsTestData(SportsHallImportStudentsTestDataParam data, SportsTestItemType type, dynamic student, int gradeId, DateTime timeNow) { var entity = new N_SportsTestValue { TeacherId = 0, TeacherName = "", DataSource = DataSource.IOT, ScoreTime = timeNow, GradeId = student.GradeId, ClassId = student.ClassId, GradeName = student.GradeName, ClassName = student.ClassName, SchoolCode = UserContext.Current.TenantId, Sex = student.Sex, StudentNo = data.StudentNo, StudentName = student.StudentName, Creator = UserContext.Current.UserId, CreateDate = timeNow, IsDisplay = false }; SexType sexType = student.Sex; string sex = sexType == SexType.Male ? "男" : "女"; string typeStr = type.ToString(); // 根据测试项目类型设置对应的值 if (type == SportsTestItemType.BMI) { entity.Value = data.BMIValue; // 根据测试项目查找标准 var standard = await _healthStandardsRepository.FindFirstAsync(x => x.CategoryEnum.Equals(typeStr) && x.GradeId == gradeId && x.Sex == sexType && data.BMIValue >= x.MinValue && data.BMIValue < x.MaxValue ); if (standard != null) { entity.Score = standard.Score; entity.Rank = standard.Rank; } } else if (type == SportsTestItemType.Sit_And_Reach) { entity.Value = data.Sit_And_ReachValue; // 根据测试项目查找标准 var standard = await _healthStandardsRepository.FindFirstAsync(x => x.CategoryEnum.Equals(typeStr) && x.GradeId == gradeId && x.Sex == sexType && data.Sit_And_ReachValue >= x.MinValue && data.Sit_And_ReachValue < x.MaxValue ); if (standard != null) { entity.Score = standard.Score; entity.Rank = standard.Rank; } } else if (type == SportsTestItemType.VitalCapacity) { entity.Value = data.VitalCapacityValue; // 根据测试项目查找标准 var standard = await _healthStandardsRepository.FindFirstAsync(x => x.CategoryEnum.Equals(typeStr) && x.GradeId == gradeId && x.Sex == sexType && data.VitalCapacityValue >= x.MinValue && data.VitalCapacityValue < x.MaxValue ); if (standard != null) { entity.Score = standard.Score; entity.Rank = standard.Rank; } } else if (type == SportsTestItemType.OneMinuteJumpRope) { entity.Value = data.OneMinuteJumpRopeValue; // 根据测试项目查找标准 var standard = await _healthStandardsRepository.FindFirstAsync(x => x.CategoryEnum.Equals(typeStr) && x.GradeId == gradeId && x.Sex == sexType && data.OneMinuteJumpRopeValue >= x.MinValue && data.OneMinuteJumpRopeValue < x.MaxValue ); if (standard != null) { entity.Score = standard.Score; entity.Rank = standard.Rank; } } else if (type == SportsTestItemType.One_Minute_Sit_Up) { entity.Value = data.One_Minute_Sit_UpValue; // 根据测试项目查找标准 var standard = await _healthStandardsRepository.FindFirstAsync(x => x.CategoryEnum.Equals(typeStr) && x.GradeId == gradeId && x.Sex == sexType && data.One_Minute_Sit_UpValue >= x.MinValue && data.One_Minute_Sit_UpValue < x.MaxValue ); if (standard != null) { entity.Score = standard.Score; entity.Rank = standard.Rank; } } else if (type == SportsTestItemType.StandingLongJump) { entity.Value = data.StandingLongJumpValue; // 根据测试项目查找标准 var standard = await _healthStandardsRepository.FindFirstAsync(x => x.CategoryEnum.Equals(typeStr) && x.GradeId == gradeId && x.Sex == sexType && data.StandingLongJumpValue >= x.MinValue && data.StandingLongJumpValue < x.MaxValue ); if (standard != null) { entity.Score = standard.Score; entity.Rank = standard.Rank; } } entity.CategoryEnum = type.ToString(); entity.CategoryValue = (int)type; return entity; } /// /// 运动馆体测成绩分页列表 /// /// /// /// public async Task> GetSportsHallStudentsTestPageList(SportsHallStudentsTestParam paramDto) { var res = new PageDataDto(); var query = _sportsTestResultRepository.DbContext.Set() .Where(s => s.SchoolCode == UserContext.Current.TenantId); // 条件过滤 if (paramDto.StartTime.HasValue) query = query.Where(x => x.CreateDate >= paramDto.StartTime.Value); if (paramDto.EndTime.HasValue) query = query.Where(x => x.CreateDate <= paramDto.EndTime.Value); if (paramDto.ClassId.HasValue) query = query.Where(x => x.ClassId == paramDto.ClassId.Value); if (paramDto.Sex.HasValue) query = query.Where(x => (int)x.Sex == paramDto.Sex); if (!string.IsNullOrWhiteSpace(paramDto.ResultLevel)) query = query.Where(x => x.Rank == paramDto.ResultLevel); // ✅ 正确分组(去掉 Id) var groupedQuery = query.GroupBy(x => new { x.StudentNo, x.StudentName, x.Sex, x.ClassName, x.GradeName, x.ScoreTime, x.IsDisplay }); res.Total = await groupedQuery.CountAsync(); var list = await groupedQuery .Select(g => new SportsHallStudentsTestModel { // 👉 可以取组内任意一条的Id Id = g.Max(x => x.Id), StudentNo = g.Key.StudentNo, StudentName = g.Key.StudentName, SexName = g.Key.Sex.GetDescription(), GradeAndClass = g.Key.GradeName + " " + g.Key.ClassName, ScoreTime = g.Key.ScoreTime, IsDisplay = g.Key.IsDisplay, // 👇 pivot(用 Max 比 FirstOrDefault 更稳) BMIValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.BMI) .Max(x => (float?)x.Value) ?? 0, VitalCapacityValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.VitalCapacity) .Max(x => (float?)x.Value) ?? 0, Sit_And_ReachValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.Sit_And_Reach) .Max(x => (float?)x.Value) ?? 0, OneMinuteJumpRopeValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.OneMinuteJumpRope) .Max(x => (int?)x.Value) ?? 0, One_Minute_Sit_UpValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.One_Minute_Sit_Up) .Max(x => (int?)x.Value) ?? 0, StandingLongJumpValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.StandingLongJump) .Max(x => (float?)x.Value) ?? 0 }) .OrderByDescending(x => x.ScoreTime) .Skip((paramDto.PageIndex - 1) * paramDto.PageSize) .Take(paramDto.PageSize) .ToListAsync(); res.Datas = list; return res; } /// /// 成绩推送 /// /// /// /// public async Task ScorePush(SportsHallStudentsTestParam paramDto) { var sql = new StringBuilder(); sql.Append("UPDATE N_SportsTestValue SET IsDisplay = 1 WHERE SchoolCode = {0} "); var parameters = new List { UserContext.Current.TenantId }; if (paramDto.StartTime.HasValue) { sql.Append(" AND CreateDate >= {1} "); parameters.Add(paramDto.StartTime.Value); } if (paramDto.EndTime.HasValue) { sql.Append(" AND CreateDate <= {2} "); parameters.Add(paramDto.EndTime.Value); } if (paramDto.ClassId > 0) { sql.Append(" AND ClassId = {3} "); parameters.Add(paramDto.ClassId.Value); } if (paramDto.Sex > 0) { sql.Append(" AND Sex = {4} "); parameters.Add(paramDto.Sex.Value); } if (!string.IsNullOrWhiteSpace(paramDto.ResultLevel)) { sql.Append(" AND Rank = {5} "); parameters.Add(paramDto.ResultLevel); } await _sportsTestResultRepository.DbContext.Database .ExecuteSqlRawAsync(sql.ToString(), parameters.ToArray()); } /// /// 成绩修成 /// /// /// public async Task ScoreUpdate(SportsHallStudentsTestDataUpdateParam paramDto) { // 获取该学生每个项目的最新一条记录 var list = await _sportsTestResultRepository.DbContext.Set() .Where(s => s.SchoolCode == "202506170049" && s.StudentNo == paramDto.StudentNo) .GroupBy(x => x.CategoryValue) .Select(g => g.OrderByDescending(x => x.ScoreTime).FirstOrDefault()) .ToListAsync(); if (list == null || !list.Any()) return; foreach (var entity in list) { switch (entity.CategoryValue) { case (int)SportsTestItemType.BMI: entity.Value = paramDto.BMIValue; break; case (int)SportsTestItemType.VitalCapacity: entity.Value = paramDto.VitalCapacityValue; break; case (int)SportsTestItemType.Sit_And_Reach: entity.Value = paramDto.Sit_And_ReachValue; break; case (int)SportsTestItemType.OneMinuteJumpRope: entity.Value = paramDto.OneMinuteJumpRopeValue; break; case (int)SportsTestItemType.One_Minute_Sit_Up: entity.Value = paramDto.One_Minute_Sit_UpValue; break; case (int)SportsTestItemType.StandingLongJump: entity.Value = paramDto.StandingLongJumpValue; break; } } _sportsTestResultRepository.UpdateRange(list); await _sportsTestResultRepository.DbContext.SaveChangesAsync(); } } }