2025-06-06 16:55:14 +08:00
|
|
|
|
using AutoMapper;
|
2026-04-24 13:53:01 +08:00
|
|
|
|
using Microsoft.AspNetCore.Http;
|
2025-06-06 16:55:14 +08:00
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
|
using Newtonsoft.Json;
|
2026-05-06 13:59:17 +08:00
|
|
|
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
|
2025-06-06 16:55:14 +08:00
|
|
|
|
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;
|
2026-04-24 13:53:01 +08:00
|
|
|
|
using VOL.Core.Utilities;
|
2025-06-06 16:55:14 +08:00
|
|
|
|
using VOL.Entity.DomainModels;
|
|
|
|
|
|
using VOL.Entity.Enum;
|
|
|
|
|
|
using VOL.Model;
|
|
|
|
|
|
using VOL.Model.IOT.Request;
|
2026-04-24 13:53:01 +08:00
|
|
|
|
using VOL.Model.School.Request;
|
|
|
|
|
|
using VOL.Model.School.Response;
|
2025-06-06 16:55:14 +08:00
|
|
|
|
using VOL.Model.SportsHall;
|
|
|
|
|
|
using VOL.System.IRepositories;
|
|
|
|
|
|
using VOL.System.Repositories;
|
|
|
|
|
|
|
|
|
|
|
|
namespace VOL.Business.Services.SportsHall
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 运动馆
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
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;
|
2026-04-24 13:53:01 +08:00
|
|
|
|
IN_HealthStandardsRepository _healthStandardsRepository;
|
|
|
|
|
|
IN_SportsTestResultRepository _sportsTestResultRepository;
|
2025-06-06 16:55:14 +08:00
|
|
|
|
|
|
|
|
|
|
[ActivatorUtilitiesConstructor]
|
2026-04-24 13:53:01 +08:00
|
|
|
|
public SportsHallService(IS_ClassRepository classRepository,
|
|
|
|
|
|
IS_GradeRepository gradeRepository,
|
|
|
|
|
|
IS_ClassAssocTeacherRepository classAssocTeacherRepository,
|
|
|
|
|
|
IS_StudentRepository studentRepository,
|
|
|
|
|
|
IN_HealthStandardsRepository healthStandardsRepository,
|
|
|
|
|
|
IN_SportsTestResultRepository sportsTestResultRepository)
|
2025-06-06 16:55:14 +08:00
|
|
|
|
{
|
|
|
|
|
|
_classRepository = classRepository;
|
|
|
|
|
|
_gradeRepository = gradeRepository;
|
|
|
|
|
|
_classAssocTeacherRepository = classAssocTeacherRepository;
|
|
|
|
|
|
_studentRepository = studentRepository;
|
2026-04-24 13:53:01 +08:00
|
|
|
|
_healthStandardsRepository = healthStandardsRepository;
|
|
|
|
|
|
_sportsTestResultRepository = sportsTestResultRepository;
|
2025-06-06 16:55:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 新增班级
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="paramDto"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
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<S_ClassAssocTeacher>();
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新班级
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="paramDto"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
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<S_ClassAssocTeacher>();
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
{
|
2026-04-24 13:53:01 +08:00
|
|
|
|
student.ClassId = 0;
|
2025-06-06 16:55:14 +08:00
|
|
|
|
student.OrderNo = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_studentRepository.UpdateRange(allStudents);
|
|
|
|
|
|
await _classRepository.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
|
|
transaction.Commit();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 发生错误,回滚事务
|
|
|
|
|
|
transaction.Rollback();
|
|
|
|
|
|
Console.WriteLine("事务回滚:" + ex.Message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-24 13:53:01 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 导入运动馆学生体测成绩
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="file"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="NotImplementedException"></exception>
|
|
|
|
|
|
public async Task SportsHallImportStudentsTestData(IFormFile file)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (file == null || file.Length <= 0)
|
|
|
|
|
|
throw new Exception("操作失败");
|
|
|
|
|
|
|
|
|
|
|
|
List<SportsHallImportStudentsTestDataParam> dataObjects;
|
|
|
|
|
|
|
|
|
|
|
|
using (var fileStream = file.OpenReadStream())
|
|
|
|
|
|
{
|
|
|
|
|
|
dataObjects = Tool.ConvertExcelToList<SportsHallImportStudentsTestDataParam>(fileStream);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var studentNos = dataObjects.Select(x => x.StudentNo).Distinct().ToList();
|
|
|
|
|
|
|
|
|
|
|
|
// 用一个查询一次性获取所有学生信息
|
|
|
|
|
|
var students = await (from s in _studentRepository.DbContext.Set<S_Student>()
|
|
|
|
|
|
join c in _studentRepository.DbContext.Set<S_Class>() on s.ClassId equals c.Id
|
|
|
|
|
|
join g in _studentRepository.DbContext.Set<S_Grade>() 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<N_SportsTestValue>();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var data in dataObjects)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!studentsDict.TryGetValue(data.StudentNo, out var student))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception($"未找到此编号为{data.StudentNo}的学生");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-06 13:59:17 +08:00
|
|
|
|
var timeNow = data.ScoreTime;
|
2026-04-24 13:53:01 +08:00
|
|
|
|
|
|
|
|
|
|
// 为每个学生添加多条体测数据
|
|
|
|
|
|
if (data.BMIValue > 0)
|
2026-04-24 16:10:17 +08:00
|
|
|
|
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.BMI, student, data.GradeId, timeNow));
|
2026-04-24 13:53:01 +08:00
|
|
|
|
|
2026-06-08 17:09:28 +08:00
|
|
|
|
//if (data.Sit_And_ReachValue > 0)
|
|
|
|
|
|
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.Sit_And_Reach, student, data.GradeId, timeNow));
|
2026-04-24 13:53:01 +08:00
|
|
|
|
|
|
|
|
|
|
if (data.VitalCapacityValue > 0)
|
2026-04-24 16:10:17 +08:00
|
|
|
|
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.VitalCapacity, student, data.GradeId, timeNow));
|
2026-04-24 13:53:01 +08:00
|
|
|
|
|
|
|
|
|
|
if (data.OneMinuteJumpRopeValue > 0)
|
2026-04-24 16:10:17 +08:00
|
|
|
|
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.OneMinuteJumpRope, student, data.GradeId, timeNow));
|
2026-04-24 13:53:01 +08:00
|
|
|
|
|
|
|
|
|
|
if (data.One_Minute_Sit_UpValue > 0)
|
2026-04-24 16:10:17 +08:00
|
|
|
|
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.One_Minute_Sit_Up, student, data.GradeId, timeNow));
|
2026-04-24 13:53:01 +08:00
|
|
|
|
|
|
|
|
|
|
if (data.StandingLongJumpValue > 0)
|
2026-04-24 16:10:17 +08:00
|
|
|
|
entityList.Add(await AddSportsHallEnumStudentsTestData(data, SportsTestItemType.StandingLongJump, student, data.GradeId, timeNow));
|
2026-04-24 13:53:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 批量添加数据
|
|
|
|
|
|
await _sportsTestResultRepository.AddRangeAsync(entityList);
|
|
|
|
|
|
|
|
|
|
|
|
// 一次性保存所有修改
|
|
|
|
|
|
await _sportsTestResultRepository.SaveChangesAsync();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-24 16:10:17 +08:00
|
|
|
|
public async Task<N_SportsTestValue> AddSportsHallEnumStudentsTestData(SportsHallImportStudentsTestDataParam data, SportsTestItemType type, dynamic student, int gradeId, DateTime timeNow)
|
2026-04-24 13:53:01 +08:00
|
|
|
|
{
|
|
|
|
|
|
var entity = new N_SportsTestValue
|
|
|
|
|
|
{
|
|
|
|
|
|
TeacherId = 0,
|
|
|
|
|
|
TeacherName = "",
|
2026-05-06 13:59:17 +08:00
|
|
|
|
DataSource = DataSource.Im,
|
2026-04-24 13:53:01 +08:00
|
|
|
|
ScoreTime = timeNow,
|
2026-05-06 13:59:17 +08:00
|
|
|
|
GradeId = gradeId,
|
2026-04-24 13:53:01 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 运动馆体测成绩分页列表
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="paramDto"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="NotImplementedException"></exception>
|
|
|
|
|
|
public async Task<PageDataDto<SportsHallStudentsTestModel>> GetSportsHallStudentsTestPageList(SportsHallStudentsTestParam paramDto)
|
|
|
|
|
|
{
|
2026-05-06 13:59:17 +08:00
|
|
|
|
var result = new PageDataDto<SportsHallStudentsTestModel>();
|
2026-04-24 13:53:01 +08:00
|
|
|
|
|
2026-05-06 13:59:17 +08:00
|
|
|
|
// 基础查询(带租户过滤)
|
|
|
|
|
|
var baseQuery = _sportsTestResultRepository.DbContext.Set<N_SportsTestValue>()
|
2026-04-24 13:53:01 +08:00
|
|
|
|
.Where(s => s.SchoolCode == UserContext.Current.TenantId);
|
|
|
|
|
|
|
2026-05-06 13:59:17 +08:00
|
|
|
|
// 公共条件过滤(时间、班级、性别、等级)
|
2026-04-24 13:53:01 +08:00
|
|
|
|
if (paramDto.StartTime.HasValue)
|
2026-05-06 13:59:17 +08:00
|
|
|
|
baseQuery = baseQuery.Where(x => x.CreateDate >= paramDto.StartTime.Value);
|
2026-04-24 13:53:01 +08:00
|
|
|
|
if (paramDto.EndTime.HasValue)
|
2026-05-06 13:59:17 +08:00
|
|
|
|
baseQuery = baseQuery.Where(x => x.CreateDate <= paramDto.EndTime.Value);
|
2026-04-24 13:53:01 +08:00
|
|
|
|
if (paramDto.ClassId.HasValue)
|
2026-05-06 13:59:17 +08:00
|
|
|
|
baseQuery = baseQuery.Where(x => x.ClassId == paramDto.ClassId.Value);
|
2026-04-24 13:53:01 +08:00
|
|
|
|
if (paramDto.Sex.HasValue)
|
2026-05-06 13:59:17 +08:00
|
|
|
|
baseQuery = baseQuery.Where(x => (int)x.Sex == paramDto.Sex);
|
2026-04-24 13:53:01 +08:00
|
|
|
|
if (!string.IsNullOrWhiteSpace(paramDto.ResultLevel))
|
2026-05-06 13:59:17 +08:00
|
|
|
|
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();
|
2026-04-24 13:53:01 +08:00
|
|
|
|
|
2026-05-06 13:59:17 +08:00
|
|
|
|
if (!pagedStudentNos.Any())
|
2026-04-24 13:53:01 +08:00
|
|
|
|
{
|
2026-05-06 13:59:17 +08:00
|
|
|
|
result.Datas = new List<SportsHallStudentsTestModel>();
|
|
|
|
|
|
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
|
|
|
|
|
|
})
|
2026-04-24 13:53:01 +08:00
|
|
|
|
.Select(g => new SportsHallStudentsTestModel
|
|
|
|
|
|
{
|
2026-05-06 13:59:17 +08:00
|
|
|
|
Id = g.Max(x => x.Id), // 取组内最大 Id(或任意一个,仅作标识)
|
2026-04-24 13:53:01 +08:00
|
|
|
|
StudentNo = g.Key.StudentNo,
|
|
|
|
|
|
StudentName = g.Key.StudentName,
|
|
|
|
|
|
SexName = g.Key.Sex.GetDescription(),
|
2026-05-06 13:59:17 +08:00
|
|
|
|
GradeAndClass = $"{g.Key.GradeName} {g.Key.ClassName}",
|
2026-04-24 13:53:01 +08:00
|
|
|
|
ScoreTime = g.Key.ScoreTime,
|
|
|
|
|
|
IsDisplay = g.Key.IsDisplay,
|
|
|
|
|
|
|
2026-05-06 13:59:17 +08:00
|
|
|
|
// 各项指标:根据 CategoryValue 匹配,使用 Max(如果同一个 CategoryValue 有多条,取最大值)
|
2026-04-24 13:53:01 +08:00
|
|
|
|
BMIValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.BMI)
|
|
|
|
|
|
.Max(x => (float?)x.Value) ?? 0,
|
|
|
|
|
|
VitalCapacityValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.VitalCapacity)
|
2026-05-06 13:59:17 +08:00
|
|
|
|
.Max(x => (float?)x.Value) ?? 0,
|
2026-04-24 13:53:01 +08:00
|
|
|
|
Sit_And_ReachValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.Sit_And_Reach)
|
2026-05-06 13:59:17 +08:00
|
|
|
|
.Max(x => (float?)x.Value) ?? 0,
|
2026-04-24 13:53:01 +08:00
|
|
|
|
OneMinuteJumpRopeValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.OneMinuteJumpRope)
|
2026-05-06 13:59:17 +08:00
|
|
|
|
.Max(x => (int?)x.Value) ?? 0,
|
2026-04-24 13:53:01 +08:00
|
|
|
|
One_Minute_Sit_UpValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.One_Minute_Sit_Up)
|
2026-05-06 13:59:17 +08:00
|
|
|
|
.Max(x => (int?)x.Value) ?? 0,
|
2026-04-24 13:53:01 +08:00
|
|
|
|
StandingLongJumpValue = g.Where(x => x.CategoryValue == (int)SportsTestItemType.StandingLongJump)
|
2026-05-06 13:59:17 +08:00
|
|
|
|
.Max(x => (float?)x.Value) ?? 0
|
2026-04-24 13:53:01 +08:00
|
|
|
|
})
|
2026-05-06 13:59:17 +08:00
|
|
|
|
.OrderByDescending(x => x.ScoreTime) // 按测试时间倒序
|
|
|
|
|
|
.ToList();
|
2026-04-24 13:53:01 +08:00
|
|
|
|
|
2026-05-06 13:59:17 +08:00
|
|
|
|
result.Datas = grouped;
|
|
|
|
|
|
return result;
|
2026-04-24 13:53:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 成绩推送
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="paramDto"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="NotImplementedException"></exception>
|
|
|
|
|
|
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<object>
|
|
|
|
|
|
{
|
|
|
|
|
|
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());
|
|
|
|
|
|
}
|
2026-04-27 16:01:33 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 成绩修成
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="paramDto"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public async Task ScoreUpdate(SportsHallStudentsTestDataUpdateParam paramDto)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取该学生每个项目的最新一条记录
|
|
|
|
|
|
var list = await _sportsTestResultRepository.DbContext.Set<N_SportsTestValue>()
|
2026-05-06 13:59:17 +08:00
|
|
|
|
.Where(s => s.SchoolCode == UserContext.Current.TenantId && s.StudentNo == paramDto.StudentNo)
|
2026-04-27 16:01:33 +08:00
|
|
|
|
.GroupBy(x => x.CategoryValue)
|
|
|
|
|
|
.Select(g => g.OrderByDescending(x => x.ScoreTime).FirstOrDefault())
|
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
|
|
if (list == null || !list.Any())
|
2026-05-06 13:59:17 +08:00
|
|
|
|
throw new Exception($"未找到要修改得数据");
|
|
|
|
|
|
|
2026-04-27 16:01:33 +08:00
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
}
|
2025-06-06 16:55:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|