using AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using System;
using System.Collections.Generic;
using System.Data;
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;
private readonly IotDataSyncService _iotDataSyncService;
IN_HealthStandardsRepository _healthStandardsRepository;
IN_SportsTestResultRepository _sportsTestResultRepository;
[ActivatorUtilitiesConstructor]
public SportsHallService(IS_ClassRepository classRepository,
IS_GradeRepository gradeRepository,
IS_ClassAssocTeacherRepository classAssocTeacherRepository,
IS_StudentRepository studentRepository,
IotDataSyncService iotDataSyncService,
IN_HealthStandardsRepository healthStandardsRepository,
IN_SportsTestResultRepository sportsTestResultRepository)
{
_classRepository = classRepository;
_gradeRepository = gradeRepository;
_classAssocTeacherRepository = classAssocTeacherRepository;
_studentRepository = studentRepository;
_iotDataSyncService = iotDataSyncService;
_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 BatchDeleteClasses(List ids)
{
var user = UserContext.Current;
var classIds = ids?.Where(id => id > 0).Distinct().ToList() ?? new List();
if (classIds.Count == 0 || classIds.Count > 100)
throw new ArgumentException("请选择1至100个班级");
if (user.RoleId != 1)
{
var menuIds = await _classRepository.DbContext.Set()
.Where(menu => menu.Url == "/sportsHallClass" && menu.ParentId > 0)
.Select(menu => menu.Menu_Id)
.ToListAsync();
if (!user.Permissions.Any(permission =>
menuIds.Contains(permission.Menu_Id) && permission.UserAuthArr.Contains("BatchDelete")))
throw new Exception("没有批量删除运动馆班级的权限");
}
var gradeId = await _gradeRepository.FindAsIQueryable(grade => grade.GradeName == "运动馆")
.Select(grade => grade.Id)
.FirstOrDefaultAsync();
if (gradeId == 0)
throw new Exception("未找到运动馆年级");
await using var transaction = await _classRepository.DbContext.Database.BeginTransactionAsync(IsolationLevel.Serializable);
var classes = await _classRepository.DbContext.Set()
.Where(item => item.SchoolCode == user.TenantId && item.GradeId == gradeId && classIds.Contains(item.Id))
.ToListAsync();
if (classes.Count != classIds.Count)
throw new Exception("部分班级不存在或不属于当前学校,请刷新列表后重试");
var occupiedClassIds = await _classRepository.DbContext.Set()
.Where(student => classIds.Contains(student.ClassId))
.Select(student => student.ClassId)
.Distinct()
.ToListAsync();
if (occupiedClassIds.Count > 0)
{
var names = classes.Where(item => occupiedClassIds.Contains(item.Id)).Select(item => item.ClassName);
throw new Exception($"班级 {string.Join("、", names)} 仍有学生,请先调整学生后再删除");
}
var teacherAssociations = await _classRepository.DbContext.Set()
.Where(item => classIds.Contains(item.ClassId))
.ToListAsync();
_classRepository.DbContext.RemoveRange(teacherAssociations);
_classRepository.DbContext.RemoveRange(classes);
await _classRepository.SaveChangesAsync();
await transaction.CommitAsync();
foreach (var item in classes)
{
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
EventType = EventType.Delete.GetDisplayName(),
DataType = IOTDataSyncType.Class.GetDisplayName(),
Json = JsonConvert.SerializeObject(item)
});
}
return classes.Count;
}
///
/// 导入运动馆学生体测成绩
///
///
///
///
public async Task SportsHallImportStudentsTestData(IFormFile file)
{
await ImportStudentsTestData(file, false);
}
///
/// 导入体测成绩管理学生体测成绩
///
///
///
///
public async Task SummaryOfGradesImportStudentsTestData(IFormFile file)
{
await ImportStudentsTestData(file, true);
}
private async Task ImportStudentsTestData(IFormFile file, bool isDisplay)
{
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 = data.ScoreTime;
// 为每个学生添加多条体测数据
if (data.BMIValue > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.BMI, student, data.GradeId, timeNow, isDisplay));
//if (data.Sit_And_ReachValue > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.Sit_And_Reach, student, data.GradeId, timeNow, isDisplay));
if (data.VitalCapacityValue > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.VitalCapacity, student, data.GradeId, timeNow, isDisplay));
if (data.MeterRun_50Value > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.MeterRun_50, student, data.GradeId, timeNow, isDisplay));
if (data.OneMinuteJumpRopeValue > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.OneMinuteJumpRope, student, data.GradeId, timeNow, isDisplay));
if (data.One_Minute_Sit_UpValue > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.One_Minute_Sit_Up, student, data.GradeId, timeNow, isDisplay));
if (data.ShuttleRun_50x8Value > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.ShuttleRun_50x8, student, data.GradeId, timeNow, isDisplay));
if (data.StandingLongJumpValue > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.StandingLongJump, student, data.GradeId, timeNow, isDisplay));
if (data.MeterRun_800Value > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.MeterRun_800, student, data.GradeId, timeNow, isDisplay));
if (data.MeterRun_1000Value > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.MeterRun_1000, student, data.GradeId, timeNow, isDisplay));
if (data.Pull_UpValue > 0)
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.Pull_Up, student, data.GradeId, timeNow, isDisplay));
}
// 批量添加数据
await _sportsTestResultRepository.AddRangeAsync(entityList);
// 一次性保存所有修改
await _sportsTestResultRepository.SaveChangesAsync();
}
public async Task AddSportsHallEnumStudentsTestData(SportsHallImportStudentsTestDataParam data, SportsTestItemType type, dynamic student, int gradeId, DateTime timeNow, bool isDisplay = false)
{
var entity = new N_SportsTestValue
{
TeacherId = 0,
TeacherName = "",
DataSource = DataSource.Im,
ScoreTime = timeNow,
GradeId = 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 = isDisplay
};
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.MeterRun_50)
{
entity.Value = data.MeterRun_50Value;
// 根据测试项目查找标准
var standard = await _healthStandardsRepository.FindFirstAsync(x =>
x.CategoryEnum.Equals(typeStr) &&
x.GradeId == gradeId &&
x.Sex == sexType &&
data.MeterRun_50Value >= x.MinValue &&
data.MeterRun_50Value < 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.ShuttleRun_50x8)
{
entity.Value = data.ShuttleRun_50x8Value;
// 根据测试项目查找标准
var standard = await _healthStandardsRepository.FindFirstAsync(x =>
x.CategoryEnum.Equals(typeStr) &&
x.GradeId == gradeId &&
x.Sex == sexType &&
data.ShuttleRun_50x8Value >= x.MinValue &&
data.ShuttleRun_50x8Value < 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;
}
}
else if (type == SportsTestItemType.MeterRun_800)
{
entity.Value = data.MeterRun_800Value;
// 根据测试项目查找标准
var standard = await _healthStandardsRepository.FindFirstAsync(x =>
x.CategoryEnum.Equals(typeStr) &&
x.GradeId == gradeId &&
x.Sex == sexType &&
data.MeterRun_800Value >= x.MinValue &&
data.MeterRun_800Value < x.MaxValue
);
if (standard != null)
{
entity.Score = standard.Score;
entity.Rank = standard.Rank;
}
}
else if (type == SportsTestItemType.MeterRun_1000)
{
entity.Value = data.MeterRun_1000Value;
// 根据测试项目查找标准
var standard = await _healthStandardsRepository.FindFirstAsync(x =>
x.CategoryEnum.Equals(typeStr) &&
x.GradeId == gradeId &&
x.Sex == sexType &&
data.MeterRun_1000Value >= x.MinValue &&
data.MeterRun_1000Value < x.MaxValue
);
if (standard != null)
{
entity.Score = standard.Score;
entity.Rank = standard.Rank;
}
}
else if (type == SportsTestItemType.Pull_Up)
{
entity.Value = data.Pull_UpValue;
// 根据测试项目查找标准
var standard = await _healthStandardsRepository.FindFirstAsync(x =>
x.CategoryEnum.Equals(typeStr) &&
x.GradeId == gradeId &&
x.Sex == sexType &&
data.Pull_UpValue >= x.MinValue &&
data.Pull_UpValue < 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 result = new PageDataDto();
// 基础查询(带租户过滤)
var baseQuery = _sportsTestResultRepository.DbContext.Set()
.Where(s => s.SchoolCode == UserContext.Current.TenantId);
// 公共条件过滤(时间、班级、性别、等级)
if (paramDto.StartTime.HasValue)
baseQuery = baseQuery.Where(x => x.CreateDate >= paramDto.StartTime.Value);
if (paramDto.EndTime.HasValue)
baseQuery = baseQuery.Where(x => x.CreateDate <= paramDto.EndTime.Value);
if (paramDto.ClassId.HasValue)
baseQuery = baseQuery.Where(x => x.ClassId == paramDto.ClassId.Value);
if (paramDto.Sex.HasValue)
baseQuery = baseQuery.Where(x => (int)x.Sex == paramDto.Sex);
if (!string.IsNullOrWhiteSpace(paramDto.ResultLevel))
baseQuery = baseQuery.Where(x => x.Rank == paramDto.ResultLevel);
// Step 1: 获取每个学生最新的 ScoreTime(子查询)
var latestScoreTimeQuery = baseQuery
.GroupBy(x => x.StudentNo)
.Select(g => new { StudentNo = g.Key, MaxScoreTime = g.Max(x => x.ScoreTime) });
// Step 2: 关联原表,只保留每个学生最新测试时间的记录
var latestRecordsQuery = from record in baseQuery
join latest in latestScoreTimeQuery
on new { record.StudentNo, record.ScoreTime }
equals new { latest.StudentNo, ScoreTime = latest.MaxScoreTime }
select record;
// Step 3: 获取符合条件的学生总数(去重)
result.Total = await latestRecordsQuery
.Select(x => x.StudentNo)
.Distinct()
.CountAsync();
// Step 4: 分页获取当前页的学生学号列表(先按最新测试时间倒序排)
var pagedStudentNos = await latestRecordsQuery
.OrderByDescending(x => x.ScoreTime) // 按最新测试时间整体倒序
.Select(x => x.StudentNo)
.Distinct()
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
.Take(paramDto.PageSize)
.ToListAsync();
if (!pagedStudentNos.Any())
{
result.Datas = new List();
return result;
}
// Step 5: 获取当前页学生的最新测试所有项目记录(包含 pivot 需要的数据)
var pageRecords = await (from record in latestRecordsQuery
where pagedStudentNos.Contains(record.StudentNo)
select new
{
record.Id,
record.StudentNo,
record.StudentName,
record.Sex,
record.ClassName,
record.GradeName,
record.ScoreTime,
record.IsDisplay,
record.CategoryValue,
record.Value
}).ToListAsync();
// Step 6: 在内存中完成 pivot(因为同一学生同一测试时间的项目数量有限,性能可接受)
var grouped = pageRecords
.GroupBy(x => new
{
x.StudentNo,
x.StudentName,
x.Sex,
x.ClassName,
x.GradeName,
x.ScoreTime,
x.IsDisplay
})
.Select(g => new SportsHallStudentsTestModel
{
Id = g.Max(x => x.Id), // 取组内最大 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,
// 各项指标:根据 CategoryValue 匹配,使用 Max(如果同一个 CategoryValue 有多条,取最大值)
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) // 按测试时间倒序
.ToList();
result.Datas = grouped;
return result;
}
///
/// 体测成绩管理分页列表(全部体测项目)
///
///
///
public async Task> GetSummaryOfGradesStudentsTestPageList(SportsHallStudentsTestParam paramDto)
{
var result = new PageDataDto();
paramDto.PageIndex = paramDto.PageIndex <= 0 ? 1 : paramDto.PageIndex;
paramDto.PageSize = paramDto.PageSize <= 0 ? 10 : paramDto.PageSize;
var baseQuery = _sportsTestResultRepository.DbContext.Set()
.Where(s => s.SchoolCode == UserContext.Current.TenantId);
if (paramDto.StartTime.HasValue)
baseQuery = baseQuery.Where(x => x.CreateDate >= paramDto.StartTime.Value);
if (paramDto.EndTime.HasValue)
baseQuery = baseQuery.Where(x => x.CreateDate <= paramDto.EndTime.Value);
if (paramDto.ClassId.HasValue)
baseQuery = baseQuery.Where(x => x.ClassId == paramDto.ClassId.Value);
if (paramDto.Sex.HasValue)
baseQuery = baseQuery.Where(x => (int)x.Sex == paramDto.Sex);
if (!string.IsNullOrWhiteSpace(paramDto.ResultLevel))
baseQuery = baseQuery.Where(x => x.Rank == paramDto.ResultLevel);
var filteredQuery = baseQuery;
if (paramDto.ItemType.HasValue && paramDto.ItemType.Value > 0)
filteredQuery = filteredQuery.Where(x => x.CategoryValue == paramDto.ItemType.Value);
var latestScoreTimeQuery = filteredQuery
.GroupBy(x => x.StudentNo)
.Select(g => new { StudentNo = g.Key, MaxScoreTime = g.Max(x => x.ScoreTime) });
var latestRecordsQuery = from record in filteredQuery
join latest in latestScoreTimeQuery
on new { record.StudentNo, record.ScoreTime }
equals new { latest.StudentNo, ScoreTime = latest.MaxScoreTime }
select record;
result.Total = await latestRecordsQuery
.Select(x => x.StudentNo)
.Distinct()
.CountAsync();
var pagedStudentKeys = await latestRecordsQuery
.OrderByDescending(x => x.ScoreTime)
.Select(x => new { x.StudentNo, x.ScoreTime })
.Distinct()
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
.Take(paramDto.PageSize)
.ToListAsync();
if (!pagedStudentKeys.Any())
{
result.Datas = new List();
return result;
}
var pagedStudentNos = pagedStudentKeys.Select(x => x.StudentNo).Distinct().ToList();
var pageRecords = await baseQuery
.Where(x => pagedStudentNos.Contains(x.StudentNo))
.Select(x => new
{
x.Id,
x.StudentNo,
x.StudentName,
x.Sex,
x.ClassName,
x.GradeName,
x.ScoreTime,
x.IsDisplay,
x.CategoryValue,
x.CategoryEnum,
x.Value,
x.Score,
x.Rank
})
.ToListAsync();
pageRecords = pageRecords
.Where(x => pagedStudentKeys.Any(k => k.StudentNo == x.StudentNo && k.ScoreTime == x.ScoreTime))
.ToList();
var sportsTestItemTypes = Enum.GetValues(typeof(SportsTestItemType))
.Cast()
.OrderBy(x => (int)x)
.ToList();
result.Datas = pageRecords
.GroupBy(x => new
{
x.StudentNo,
x.StudentName,
x.Sex,
x.ClassName,
x.GradeName,
x.ScoreTime,
x.IsDisplay
})
.Select(g =>
{
var records = g
.GroupBy(x => x.CategoryValue)
.ToDictionary(x => x.Key, x => x.OrderByDescending(r => r.Id).First());
return new SummaryOfGradesStudentsTestModel
{
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,
Items = sportsTestItemTypes.Select(itemType =>
{
records.TryGetValue((int)itemType, out var record);
return new SummaryOfGradesSportsTestItemModel
{
ItemType = (int)itemType,
ItemCode = itemType.ToString(),
ItemName = itemType.GetDisplayName(),
Unit = itemType.GetDisplayDescription(),
Value = record?.Value,
Score = record?.Score,
Rank = record?.Rank ?? string.Empty
};
}).ToList()
};
})
.OrderByDescending(x => x.ScoreTime)
.ToList();
return result;
}
///
/// 成绩推送
///
///
///
///
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