1327 lines
57 KiB
C#
1327 lines
57 KiB
C#
using AutoMapper;
|
||
using Castle.DynamicProxy.Generators;
|
||
using Google.Protobuf.Collections;
|
||
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.IO.Compression;
|
||
using System.Linq;
|
||
using System.Linq.Expressions;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using VOL.Business.IRepositories;
|
||
using VOL.Business.IServices.Norm;
|
||
using VOL.Business.IServices.School;
|
||
using VOL.Core.CacheManager;
|
||
using VOL.Core.Extensions;
|
||
using VOL.Core.Extensions.AutofacManager;
|
||
using VOL.Core.ManageUser;
|
||
using VOL.Core.Utilities;
|
||
using VOL.Entity.DomainModels;
|
||
using VOL.Entity.DomainModels.Business.People;
|
||
using VOL.Entity.Enum;
|
||
using VOL.Model;
|
||
using VOL.Model.Ai;
|
||
using VOL.Model.IOT.Request;
|
||
using VOL.Model.School.Request;
|
||
using VOL.Model.School.Response;
|
||
using VOL.System.IRepositories;
|
||
using VOL.System.Repositories;
|
||
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
|
||
|
||
namespace VOL.Business.Services.School
|
||
{
|
||
public class S_StudentService : IS_StudentService, IDependency
|
||
{
|
||
#region 初始化
|
||
private readonly IMapper _mapper;
|
||
private readonly ICacheService _cacheService;
|
||
private readonly ICacheQueryService _cacheQueryService;
|
||
private readonly IotDataSyncService _iotDataSyncService;
|
||
private readonly IS_StudentRepository _studentRepository;
|
||
private readonly IS_GradeRepository _gradeRepository;
|
||
private readonly IS_ClassRepository _classRepository;
|
||
private readonly IN_SportsTestResultRepository _sportsTestResultRepository;
|
||
private readonly IN_SportsTestCategoryRepository _sportsTestCategoryRepository;
|
||
|
||
|
||
[ActivatorUtilitiesConstructor]
|
||
public S_StudentService(IMapper mapper,
|
||
ICacheService cacheService,
|
||
ICacheQueryService cacheQueryService,
|
||
IS_StudentRepository studentRepository,
|
||
IS_GradeRepository gradeRepository,
|
||
IS_ClassRepository classRepository,
|
||
IN_SportsTestResultRepository sportsTestResultRepository,
|
||
IN_SportsTestCategoryRepository sportsTestCategoryRepository,
|
||
IotDataSyncService iotDataSyncService)
|
||
{
|
||
_mapper = mapper;
|
||
_cacheService = cacheService;
|
||
_cacheQueryService = cacheQueryService;
|
||
_studentRepository = studentRepository;
|
||
_gradeRepository = gradeRepository;
|
||
_classRepository = classRepository;
|
||
_sportsTestResultRepository = sportsTestResultRepository;
|
||
_sportsTestCategoryRepository = sportsTestCategoryRepository;
|
||
_iotDataSyncService = iotDataSyncService;
|
||
}
|
||
#endregion
|
||
|
||
public async Task<PageDataDto<StudentPageListModel>> GetStudentPageList(StudentPageListParam paramDto)
|
||
{
|
||
var res = new PageDataDto<StudentPageListModel>();
|
||
|
||
var classIds = new List<int>();
|
||
var isTeacher = (UserContext.Current.RoleId == 3);
|
||
|
||
if (isTeacher)
|
||
{
|
||
var teacher = await _studentRepository.DbContext.Set<S_Teacher>().FirstOrDefaultAsync(x => x.SchoolCode == UserContext.Current.TenantId && x.TeacherPhoneNo == UserContext.Current.UserInfo.PhoneNo);
|
||
|
||
var teacherClassList = await (
|
||
from at in _studentRepository.DbContext.Set<S_ClassAssocTeacher>()
|
||
join c in _studentRepository.DbContext.Set<S_Class>() on at.ClassId equals c.Id
|
||
where at.TeacherId == teacher.Id
|
||
select c).ToListAsync();
|
||
|
||
classIds = teacherClassList.Select(c => c.Id).Distinct().ToList();
|
||
}
|
||
|
||
|
||
var query = from s in _studentRepository.DbContext.Set<S_Student>()
|
||
join c in _studentRepository.DbContext.Set<S_Class>() on s.ClassId equals c.Id
|
||
|
||
where s.SchoolCode.Equals(UserContext.Current.TenantId) && s.StudentStatus == StudentStatus.Normal && (!isTeacher || classIds.Contains(c.Id))
|
||
|
||
select new StudentPageListModel()
|
||
{
|
||
Id = s.Id,
|
||
Age = s.Age,
|
||
ClassId = s.ClassId,
|
||
ClassName = c.ClassName,
|
||
GradeName = c.GradeName,
|
||
HeartRateFrontNo = s.HeartRateFrontNo,
|
||
HeartRateId = s.HeartRateId,
|
||
Photo = s.Photo,
|
||
RopeSkipQRCode = s.RopeSkipQRCode,
|
||
SchoolRollNo = s.SchoolRollNo,
|
||
Sex = s.Sex,
|
||
StudentName = s.StudentName,
|
||
StudentNo = s.StudentNo,
|
||
OrderNo = s.OrderNo,
|
||
StudentStatus = s.StudentStatus
|
||
};
|
||
|
||
if (!string.IsNullOrWhiteSpace(paramDto.StudentName))
|
||
{
|
||
query = query.Where(x => x.StudentName.Contains(paramDto.StudentName));
|
||
}
|
||
|
||
if (!string.IsNullOrWhiteSpace(paramDto.StudentNo))
|
||
{
|
||
query = query.Where(x => x.StudentNo.Contains(paramDto.StudentNo));
|
||
}
|
||
|
||
if (paramDto.Sex > 0)
|
||
{
|
||
query = query.Where(x => x.Sex == paramDto.Sex);
|
||
}
|
||
|
||
if (paramDto.ClassId > 0)
|
||
{
|
||
query = query.Where(x => x.ClassId == paramDto.ClassId);
|
||
}
|
||
|
||
if (paramDto.StudentStatus > 0)
|
||
{
|
||
query = query.Where(x => x.StudentStatus == paramDto.StudentStatus);
|
||
}
|
||
|
||
res.Total = await query.CountAsync();
|
||
|
||
var list = await query
|
||
.OrderBy(x => x.Id)
|
||
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
|
||
.Take(paramDto.PageSize)
|
||
.ToListAsync();
|
||
res.Datas = list;
|
||
|
||
return res;
|
||
}
|
||
|
||
public async Task<List<StudentPageListModel>> GetStudentList(StudentExportParam paramDto)
|
||
{
|
||
var classIds = new List<int>();
|
||
var isTeacher = (UserContext.Current.RoleId == 3);
|
||
|
||
if (isTeacher)
|
||
{
|
||
var teacher = await _studentRepository.DbContext.Set<S_Teacher>().FirstOrDefaultAsync(x => x.SchoolCode == UserContext.Current.TenantId && x.TeacherPhoneNo == UserContext.Current.UserInfo.PhoneNo);
|
||
|
||
var teacherClassList = await (
|
||
from at in _studentRepository.DbContext.Set<S_ClassAssocTeacher>()
|
||
join c in _studentRepository.DbContext.Set<S_Class>() on at.ClassId equals c.Id
|
||
where at.TeacherId == teacher.Id
|
||
select c).ToListAsync();
|
||
|
||
classIds = teacherClassList.Select(c => c.Id).Distinct().ToList();
|
||
}
|
||
|
||
var query = from s in _studentRepository.DbContext.Set<S_Student>()
|
||
join c in _studentRepository.DbContext.Set<S_Class>() on s.ClassId equals c.Id
|
||
|
||
where c.SchoolCode.Equals(UserContext.Current.TenantId) && s.StudentStatus == StudentStatus.Normal && s.StudentStatus == StudentStatus.Normal && (!isTeacher || classIds.Contains(c.Id))
|
||
|
||
select new StudentPageListModel()
|
||
{
|
||
Id = s.Id,
|
||
Age = s.Age,
|
||
ClassId = s.ClassId,
|
||
ClassName = c.ClassName,
|
||
GradeName = c.GradeName,
|
||
HeartRateFrontNo = s.HeartRateFrontNo,
|
||
HeartRateId = s.HeartRateId,
|
||
Photo = s.Photo,
|
||
RopeSkipQRCode = s.RopeSkipQRCode,
|
||
SchoolRollNo = s.SchoolRollNo,
|
||
Sex = s.Sex,
|
||
StudentName = s.StudentName,
|
||
StudentNo = s.StudentNo,
|
||
StudentStatus = s.StudentStatus
|
||
};
|
||
|
||
|
||
if (!string.IsNullOrWhiteSpace(paramDto.StudentName))
|
||
{
|
||
query = query.Where(x => x.StudentName.Contains(paramDto.StudentName));
|
||
}
|
||
|
||
if (!string.IsNullOrWhiteSpace(paramDto.StudentNo))
|
||
{
|
||
query = query.Where(x => x.StudentNo.Contains(paramDto.StudentNo));
|
||
}
|
||
|
||
if (paramDto.Sex > 0)
|
||
{
|
||
query = query.Where(x => x.Sex == paramDto.Sex);
|
||
}
|
||
|
||
if (paramDto.ClassId > 0)
|
||
{
|
||
query = query.Where(x => x.ClassId == paramDto.ClassId);
|
||
}
|
||
|
||
if (paramDto.StudentStatus > 0)
|
||
{
|
||
query = query.Where(x => x.StudentStatus == paramDto.StudentStatus);
|
||
}
|
||
|
||
|
||
var list = await query.OrderBy(x => x.Id).ToListAsync();
|
||
|
||
return list;
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 获取场馆学员
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<List<StudentPageListModel>> GetStudentListBySportsHall(StudentExportParam paramDto)
|
||
{
|
||
var query = from s in _studentRepository.DbContext.Set<S_Student>()
|
||
|
||
where s.SchoolCode.Equals(UserContext.Current.TenantId) && s.StudentStatus == StudentStatus.Normal && s.StudentStatus == StudentStatus.Normal
|
||
|
||
select new StudentPageListModel()
|
||
{
|
||
Id = s.Id,
|
||
Age = s.Age,
|
||
ClassId = s.ClassId,
|
||
ClassName = s.ClassName,
|
||
GradeName = "运动馆",
|
||
HeartRateFrontNo = s.HeartRateFrontNo,
|
||
HeartRateId = s.HeartRateId,
|
||
Photo = s.Photo,
|
||
RopeSkipQRCode = s.RopeSkipQRCode,
|
||
SchoolRollNo = s.SchoolRollNo,
|
||
Sex = s.Sex,
|
||
StudentName = s.StudentName,
|
||
StudentNo = s.StudentNo,
|
||
StudentStatus = s.StudentStatus,
|
||
OrderNo = s.OrderNo,
|
||
};
|
||
|
||
|
||
if (!string.IsNullOrWhiteSpace(paramDto.StudentName))
|
||
{
|
||
query = query.Where(x => x.StudentName.Contains(paramDto.StudentName));
|
||
}
|
||
|
||
if (!string.IsNullOrWhiteSpace(paramDto.StudentNo))
|
||
{
|
||
query = query.Where(x => x.StudentNo.Contains(paramDto.StudentNo));
|
||
}
|
||
|
||
if (paramDto.Sex > 0)
|
||
{
|
||
query = query.Where(x => x.Sex == paramDto.Sex);
|
||
}
|
||
|
||
if (paramDto.ClassId > 0)
|
||
{
|
||
query = query.Where(x => x.ClassId == paramDto.ClassId);
|
||
}
|
||
|
||
if (paramDto.StudentStatus > 0)
|
||
{
|
||
query = query.Where(x => x.StudentStatus == paramDto.StudentStatus);
|
||
}
|
||
|
||
var list = await query.OrderBy(x => x.OrderNo).ToListAsync();
|
||
|
||
return list;
|
||
}
|
||
|
||
public async Task AddStudent(AddStudentParam paramDto)
|
||
{
|
||
var stuExists = await _studentRepository.ExistsAsync(x => x.StudentNo == paramDto.StudentNo);
|
||
if (stuExists)
|
||
throw new Exception($"学号{paramDto.StudentNo}的学生已存在!");
|
||
|
||
var studentEntity = _mapper.Map<S_Student>(paramDto);
|
||
studentEntity.StudentStatus = StudentStatus.Normal;
|
||
studentEntity.SchoolCode = UserContext.Current.TenantId;
|
||
studentEntity.Creator = UserContext.Current.UserId;
|
||
studentEntity.CreateDate = DateTime.Now;
|
||
|
||
await _studentRepository.AddAsync(studentEntity);
|
||
await _studentRepository.SaveChangesAsync();
|
||
|
||
//调用回调函数,同步数据到IOT
|
||
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
|
||
//{
|
||
// EventType = EventType.Add.GetDisplayName(),
|
||
// DataType = IOTDataSyncType.Student.GetDisplayName(),
|
||
// Json = JsonConvert.SerializeObject(new List<S_Student>() { studentEntity })
|
||
//}));
|
||
|
||
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
|
||
{
|
||
EventType = EventType.Add.GetDisplayName(),
|
||
DataType = IOTDataSyncType.Student.GetDisplayName(),
|
||
Json = JsonConvert.SerializeObject(new List<S_Student>() { studentEntity })
|
||
});
|
||
}
|
||
public async Task ModifyStudent(AddStudentParam paramDto)
|
||
{
|
||
if (paramDto == null || string.IsNullOrEmpty(paramDto.StudentNo))
|
||
{
|
||
throw new ArgumentNullException("学生学号必填");
|
||
}
|
||
|
||
var student = await _studentRepository.FindAsyncFirst(x => x.Id == paramDto.Id);
|
||
if (student == null)
|
||
throw new ArgumentNullException("未找到要更新的数据");
|
||
|
||
var stuExists = await _studentRepository.ExistsAsync(x => x.StudentNo == paramDto.StudentNo && x.Id != student.Id);
|
||
if (stuExists)
|
||
throw new Exception($"学号{paramDto.StudentNo}的学生已存在!");
|
||
|
||
student.StudentName = paramDto.StudentName; // 学生名称
|
||
student.ClassId = paramDto.ClassId; // 班级
|
||
student.Sex = paramDto.Sex; // 性别
|
||
student.Age = paramDto.Age; // 年龄
|
||
student.Birthday = paramDto.Birthday; // 出生日期
|
||
student.IDCard = paramDto.IDCard; // 身份证
|
||
student.Photo = paramDto.Photo; // 学生照片
|
||
student.HeartRateFrontNo = paramDto.HeartRateFrontNo; // 心率设备正面编号
|
||
student.HeartRateId = paramDto.HeartRateId; // 心率设备ID
|
||
student.RunChipNo = paramDto.RunChipNo; // 中长跑芯片编号
|
||
student.RopeSkipNo = paramDto.RopeSkipQRCode; // 跳绳编号
|
||
|
||
|
||
student.OrderNo = 1;
|
||
|
||
student.Creator = UserContext.Current.UserId;
|
||
student.Modifier = UserContext.Current.UserId;
|
||
student.ModifyDate = DateTime.Now;
|
||
student.StudentStatus = StudentStatus.Normal;
|
||
_studentRepository.Update(student);
|
||
await _studentRepository.SaveChangesAsync();
|
||
|
||
//调用回调函数,同步数据到IOT
|
||
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
|
||
//{
|
||
// EventType = EventType.Update.GetDisplayName(),
|
||
// DataType = IOTDataSyncType.Student.GetDisplayName(),
|
||
// Json = JsonConvert.SerializeObject(student)
|
||
//}));
|
||
|
||
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
|
||
{
|
||
EventType = EventType.Update.GetDisplayName(),
|
||
DataType = IOTDataSyncType.Student.GetDisplayName(),
|
||
Json = JsonConvert.SerializeObject(student)
|
||
});
|
||
}
|
||
|
||
public async Task UpdateStudentStatus(UpdateStudentStatusParam paramDto)
|
||
{
|
||
var student = await _studentRepository.FindAsyncFirst(x => x.StudentNo == paramDto.StudentNo);
|
||
if (student == null)
|
||
throw new ArgumentNullException("未找到要更新的数据");
|
||
student.StudentStatus = paramDto.Status;
|
||
|
||
_studentRepository.Update(student);
|
||
await _studentRepository.SaveChangesAsync();
|
||
|
||
//调用回调函数,同步数据到IOT
|
||
_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
|
||
{
|
||
EventType = EventType.Update.GetDisplayName(),
|
||
DataType = IOTDataSyncType.Student.GetDisplayName(),
|
||
Json = JsonConvert.SerializeObject(student)
|
||
}));
|
||
}
|
||
|
||
public async Task UpdateStudentPwd(UpdateStudentPwdParam paramDto)
|
||
{
|
||
var student = await _studentRepository.FindAsyncFirst(x => x.StudentNo == paramDto.StudentNo);
|
||
if (student == null)
|
||
throw new ArgumentNullException("未找到要更新的数据");
|
||
student.AppletPwd = paramDto.StudentNo;
|
||
|
||
_studentRepository.Update(student);
|
||
await _studentRepository.SaveChangesAsync();
|
||
|
||
//调用回调函数,同步数据到IOT
|
||
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
|
||
//{
|
||
// EventType = EventType.Update.GetDisplayName(),
|
||
// DataType = IOTDataSyncType.Student.GetDisplayName(),
|
||
// Json = JsonConvert.SerializeObject(student)
|
||
//}));
|
||
|
||
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
|
||
{
|
||
EventType = EventType.Update.GetDisplayName(),
|
||
DataType = IOTDataSyncType.Student.GetDisplayName(),
|
||
Json = JsonConvert.SerializeObject(student)
|
||
});
|
||
}
|
||
|
||
public async Task ChangeClasses(string studentNo, int classId)
|
||
{
|
||
var student = await _studentRepository.FindAsyncFirst(x => x.StudentNo == studentNo);
|
||
|
||
if (student == null)
|
||
throw new ArgumentNullException("未找到更新的数据");
|
||
|
||
var classModel = await _classRepository.FindAsyncFirst(x => x.Id == student.ClassId);
|
||
|
||
var sportsTestResults = await _sportsTestResultRepository.FindAsIQueryable(x => x.ClassId == student.ClassId && x.StudentNo == studentNo).ToListAsync();
|
||
|
||
using (var transaction = _studentRepository.DbContext.Database.BeginTransaction())
|
||
{
|
||
try
|
||
{
|
||
student.ClassId = classId;
|
||
student.ClassName = classModel.ClassName;
|
||
student.Modifier = UserContext.Current.UserId;
|
||
student.ModifyDate = DateTime.Now;
|
||
|
||
_studentRepository.Update(student);
|
||
|
||
foreach (var item in sportsTestResults)
|
||
{
|
||
item.ClassId = classId;
|
||
item.ClassName = classModel.ClassName;
|
||
item.Modifier = UserContext.Current.UserId;
|
||
item.ModifyDate = DateTime.Now;
|
||
}
|
||
|
||
|
||
_sportsTestResultRepository.UpdateRange(sportsTestResults);
|
||
|
||
await _studentRepository.SaveChangesAsync();
|
||
|
||
// 提交事务
|
||
transaction.Commit();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 发生错误,回滚事务
|
||
transaction.Rollback();
|
||
throw new Exception("操作失败");
|
||
}
|
||
}
|
||
}
|
||
|
||
public async Task ImportStudents(IFormFile file)
|
||
{
|
||
if (file == null || file.Length <= 0)
|
||
throw new Exception("操作失败");
|
||
var tenantId = UserContext.Current.TenantId;
|
||
|
||
var dataObjects = new List<ImportStudentParam>();
|
||
|
||
using (var fileStream = file.OpenReadStream())
|
||
{
|
||
dataObjects = Tool.ConvertExcelToList<ImportStudentParam>(fileStream);
|
||
}
|
||
var greadNames = dataObjects.Select(x => x.GradeName).Distinct().ToList();
|
||
|
||
var greadList = await _gradeRepository.FindAsync(x => greadNames.Contains(x.GradeName));
|
||
|
||
var greadIds = greadList.Select(x => x.Id).ToList();
|
||
|
||
var classList = await _classRepository.FindAsync(x => greadIds.Contains(x.GradeId) && x.SchoolCode == tenantId);
|
||
|
||
var groupedStudentNos = dataObjects.GroupBy(x => x.StudentNo);
|
||
foreach (var group in groupedStudentNos)
|
||
{
|
||
if (!string.IsNullOrWhiteSpace(group.Key) && group.Count() > 1)
|
||
{
|
||
throw new Exception($"存在重复的学号:{group.Key},请检查后重新操作");
|
||
}
|
||
}
|
||
|
||
var stuNos = groupedStudentNos.Select(g => g.Key).ToList();
|
||
var stuList = await _studentRepository.FindAsync(x => x.SchoolCode == tenantId && stuNos.Contains(x.StudentNo));
|
||
|
||
var entitys = new List<S_Student>();
|
||
|
||
foreach (var data in dataObjects)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(data.StudentNo))
|
||
{
|
||
throw new Exception("学号不能为空");
|
||
}
|
||
|
||
var stuExists = stuList.Exists(x => x.StudentNo == data.StudentNo);
|
||
if (stuExists)
|
||
throw new Exception($"学号{data.StudentNo}的学生已存在!");
|
||
|
||
if (string.IsNullOrWhiteSpace(data.StudentNo))
|
||
{
|
||
throw new Exception("姓名不能为空");
|
||
}
|
||
if (string.IsNullOrWhiteSpace(data.StudentNo))
|
||
{
|
||
throw new Exception("性别不能为空");
|
||
}
|
||
if (string.IsNullOrWhiteSpace(data.StudentNo))
|
||
{
|
||
throw new Exception("年龄不能为空");
|
||
}
|
||
|
||
var greadModel = greadList.Where(x => x.GradeName.Equals(data.GradeName)).FirstOrDefault();
|
||
if (greadModel == null)
|
||
throw new Exception("未找到年级信息");
|
||
|
||
var classModel = classList.Where(x => x.GradeId == greadModel.Id && x.ClassName == data.ClassName).FirstOrDefault();
|
||
if (classModel == null)
|
||
throw new Exception("未找到班级信息");
|
||
|
||
var studentEntity = new S_Student()
|
||
{
|
||
SchoolCode = tenantId,
|
||
StudentName = data.StudentName,
|
||
StudentNo = data.StudentNo,
|
||
ClassId = classModel.Id,
|
||
Age = data.Age,
|
||
IDCard = data.IDCard,
|
||
Birthday = data.Birthday,
|
||
HeartRateFrontNo = data.HeartRateFrontNo,
|
||
HeartRateId = data.HeartRateId,
|
||
RopeSkipQRCode = data.RopeSkipQRCode,
|
||
Sex = data.Sex == "男" ? SexType.Male : SexType.Female,
|
||
RunChipNo = data.RunChipNo,
|
||
StudentStatus = StudentStatus.Normal,
|
||
Creator = UserContext.Current.UserId,
|
||
CreateDate = DateTime.Now
|
||
};
|
||
|
||
entitys.Add(studentEntity);
|
||
}
|
||
|
||
await _studentRepository.AddRangeAsync(entitys);
|
||
await _studentRepository.SaveChangesAsync();
|
||
|
||
//调用回调函数,同步数据到IOT
|
||
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
|
||
//{
|
||
// EventType = EventType.Add.GetDisplayName(),
|
||
// DataType = IOTDataSyncType.Student.GetDisplayName(),
|
||
// Json = JsonConvert.SerializeObject(entitys)
|
||
//}));
|
||
|
||
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
|
||
{
|
||
EventType = EventType.Add.GetDisplayName(),
|
||
DataType = IOTDataSyncType.Student.GetDisplayName(),
|
||
Json = JsonConvert.SerializeObject(entitys)
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 上传学生头像
|
||
/// </summary>
|
||
public async Task<string> UploadPhoto(IFormFile file, int gradeId, int classId, string studentNo, string studentName)
|
||
{
|
||
//var student = _studentRepository.FindFirst(c => c.StudentNo == studentNo);
|
||
//if (student == null)
|
||
//{
|
||
// throw new Exception("学生未找到");
|
||
//}
|
||
|
||
// 设置照片最大允许大小 (5MB)
|
||
const long MaxFileSize = 2 * 1024 * 1024;
|
||
|
||
// 检查文件大小是否超过限制
|
||
if (file.Length > MaxFileSize)
|
||
{
|
||
throw new Exception("上传的照片文件大小不能超过2MB");
|
||
}
|
||
|
||
|
||
var url = ALiYunOss.Upload(file, $"Upload/{UserContext.Current.TenantId}/Photo/Student/{gradeId}/{classId}/", studentNo);
|
||
|
||
var faceEntityWithRequest = new FaceEntityWithDto()
|
||
{
|
||
EntityId = studentNo,
|
||
SchoolCode = UserContext.Current.TenantId,
|
||
IsStudent = true
|
||
};
|
||
|
||
await ALiYunFace.DeleteFaceEntityWith(faceEntityWithRequest);
|
||
|
||
var faceEntityWithReuslt = await ALiYunFace.FaceEntityWith(faceEntityWithRequest);
|
||
if (!faceEntityWithReuslt)
|
||
{
|
||
throw new Exception("上传失败");
|
||
}
|
||
|
||
var faceWithReuslt = await ALiYunFace.FaceWith(new FaceWithDto()
|
||
{
|
||
SchoolCode = UserContext.Current.TenantId,
|
||
Name = studentName,
|
||
IsStudent = true,
|
||
EntityId = studentNo,
|
||
ImageUrl = url
|
||
});
|
||
if (!faceWithReuslt)
|
||
{
|
||
throw new Exception("上传失败");
|
||
}
|
||
|
||
return url;
|
||
}
|
||
|
||
public async Task BatchUploadPhoto(IFormFile zipFile)
|
||
{
|
||
// 解压缩 zip 文件
|
||
var uploadPath = Path.Combine("Upload", "Student");
|
||
Directory.CreateDirectory(uploadPath);
|
||
var zipFilePath = Path.Combine(uploadPath, zipFile.FileName);
|
||
|
||
using (var fileStream = new FileStream(zipFilePath, FileMode.Create))
|
||
{
|
||
await zipFile.CopyToAsync(fileStream);
|
||
}
|
||
// 解压后的目录路径
|
||
var extractPath = Path.Combine(uploadPath, Path.GetFileNameWithoutExtension(zipFile.FileName));
|
||
|
||
// 检查并删除已存在的目录
|
||
if (Directory.Exists(extractPath))
|
||
{
|
||
Directory.Delete(extractPath, true);
|
||
}
|
||
ZipFile.ExtractToDirectory(zipFilePath, extractPath);
|
||
|
||
// 递归获取所有文件
|
||
var files = Directory.GetFiles(extractPath, "*.*", SearchOption.AllDirectories)
|
||
.Select(filePath => new FileInfo(filePath))
|
||
.ToList();
|
||
|
||
// 获取学号列表
|
||
var studentNos = files.Select(x => Path.GetFileNameWithoutExtension(x.Name)).ToList();
|
||
|
||
var students = await _studentRepository.FindAsync(x => studentNos.Contains(x.StudentNo) && x.SchoolCode.Equals(UserContext.Current.TenantId));
|
||
var classList = await _classRepository.FindAsync(x => x.SchoolCode.Equals(UserContext.Current.TenantId));
|
||
|
||
var studentEntitys = new List<S_Student>();
|
||
foreach (var fileInfo in files)
|
||
{
|
||
try
|
||
{
|
||
using (var stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read))
|
||
{
|
||
var formFile = new FormFile(stream, 0, stream.Length, fileInfo.FullName, fileInfo.Name);
|
||
|
||
var stuNo = Path.GetFileNameWithoutExtension(fileInfo.Name);
|
||
var student = students.FirstOrDefault(x => x.StudentNo.Equals(stuNo, StringComparison.OrdinalIgnoreCase));
|
||
|
||
if (student != null)
|
||
{
|
||
var cla = classList.FirstOrDefault(x => x.Id == student.ClassId);
|
||
|
||
var url = await UploadPhoto(formFile, cla == null ? 0 : cla.GradeId, student.ClassId, stuNo, student.StudentName);
|
||
student.Photo = url;
|
||
studentEntitys.Add(student);
|
||
}
|
||
else
|
||
{
|
||
//throw new Exception($"未找到学号:{stuNo}");
|
||
continue;
|
||
}
|
||
}
|
||
|
||
}
|
||
catch (Exception)
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
|
||
_studentRepository.UpdateRange(studentEntitys);
|
||
await _studentRepository.SaveChangesAsync();
|
||
|
||
// 删除临时文件和目录
|
||
Directory.Delete(extractPath, true);
|
||
File.Delete(zipFilePath);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 学生数据统计
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<StudentDataStatsModel> StudentWholeDataStats(StudentDataStatsParam paramDto)
|
||
{
|
||
var res = new StudentDataStatsModel();
|
||
var tenantId = UserContext.Current.TenantId;
|
||
|
||
if (string.IsNullOrEmpty(paramDto.StudentNo))
|
||
{
|
||
paramDto.StudentNo = _studentRepository.DbContext.Set<S_Student>().First().StudentNo;
|
||
}
|
||
|
||
var student = await (from s in _studentRepository.DbContext.Set<S_Student>()
|
||
join c in _studentRepository.DbContext.Set<S_Class>() on s.ClassId equals c.Id
|
||
where s.StudentNo == paramDto.StudentNo && s.SchoolCode.Equals(UserContext.Current.TenantId)
|
||
select new StudentPageListModel()
|
||
{
|
||
StudentName = s.StudentName,
|
||
GradeId = c.GradeId,
|
||
ClassId = s.ClassId,
|
||
ClassName = c.ClassName,
|
||
GradeName = c.GradeName,
|
||
Photo = s.Photo,
|
||
Age = s.Age,
|
||
Sex = s.Sex
|
||
}).FirstOrDefaultAsync();
|
||
|
||
if (student == null)
|
||
throw new ArgumentNullException("未找到学生数据");
|
||
|
||
res.StudentName = student.StudentName;
|
||
res.ClassName = student.ClassName;
|
||
res.GradeName = student.GradeName;
|
||
res.Photo = student.Photo;
|
||
res.Sex = student.Sex.Description();
|
||
res.Age = student.Age;
|
||
|
||
var heartRateData = await (from t in _studentRepository.DbContext.Set<I_TrainingData>()
|
||
join s in _studentRepository.DbContext.Set<I_TrainRanking>() on t.Id equals s.TrainingDataId
|
||
where
|
||
t.SchoolCode.Equals(UserContext.Current.TenantId)
|
||
&& t.ItemType == (int)TrainingItemType.HeartRate
|
||
&& s.StudentNo == paramDto.StudentNo
|
||
select new
|
||
{
|
||
t.Id,
|
||
s.HighHeartRate
|
||
})
|
||
.OrderByDescending(x => x.Id)
|
||
.Take(5)
|
||
.ToListAsync();
|
||
|
||
var keys = new[] { "一", "二", "三", "四", "五" };
|
||
|
||
if (heartRateData.Count == 0)
|
||
{
|
||
res.HeartRateData = keys.ToDictionary(key => key, key => 0);
|
||
}
|
||
else
|
||
{
|
||
res.HeartRateData = heartRateData
|
||
.Select((x, index) => new { Key = keys[index], Value = x.HighHeartRate ?? 0 })
|
||
.ToDictionary(x => x.Key, x => x.Value);
|
||
}
|
||
|
||
// 从缓存中获取数据
|
||
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.SchoolCode.Equals(tenantId) && x.StudentNo == paramDto.StudentNo, paramDto.Mode);
|
||
|
||
var categoryList = await (from s in _sportsTestResultRepository.DbContext.Set<S_GradeAssocCategory>()
|
||
join n in _sportsTestResultRepository.DbContext.Set<N_SportsTestCategory>()
|
||
on s.CategoryValue equals n.CategoryValue
|
||
where s.GradeId == student.GradeId
|
||
select new
|
||
{
|
||
n.CategoryValue,
|
||
n.CategoryName
|
||
}).ToListAsync();
|
||
|
||
foreach (var category in categoryList)
|
||
{
|
||
var categoryResults = sportsTestResults.Where(x => x.CategoryValue == category.CategoryValue).ToList();
|
||
|
||
var maxValue = categoryResults.Any() ? categoryResults.Max(x => x.Score + x.AdditionalScore) : 0f;
|
||
var lastValue = categoryResults.OrderByDescending(x => x.ScoreTime).Select(x => x.Score + x.AdditionalScore).FirstOrDefault();
|
||
|
||
var resultContrast = new ResultContrast
|
||
{
|
||
MaxValue = maxValue,
|
||
LastValue = lastValue
|
||
};
|
||
|
||
res.TestResultCompare.AxisX.Add(category.CategoryName);
|
||
res.TestResultCompare.AxisY.Add(resultContrast);
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 各项目平均成绩
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<Dictionary<string, float>> TestResultAvg(StudentCategoryParam paramDto)
|
||
{
|
||
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x =>
|
||
x.StudentNo == paramDto.StudentNo &&
|
||
x.SchoolCode.Equals(UserContext.Current.TenantId) &&
|
||
x.CategoryValue == paramDto.CategoryValue
|
||
, paramDto.Mode);
|
||
|
||
var now = DateTime.Now;
|
||
var currentQuarter = (now.Month - 1) / 3 + 1;
|
||
var currentYear = now.Year;
|
||
|
||
// 处理跨年情况
|
||
var quarters = new[]
|
||
{
|
||
new { Label = "本季度", Quarter = currentQuarter, Year = currentYear },
|
||
new { Label = "上季度", Quarter = currentQuarter - 1 == 0 ? 4 : currentQuarter - 1, Year = currentQuarter == 1 ? currentYear - 1 : currentYear },
|
||
new { Label = "前季度", Quarter = currentQuarter - 2 == 0 ? 4 : currentQuarter - 2 == -1 ? 3 : currentQuarter - 2, Year = currentQuarter <= 2 ? currentYear - 1 : currentYear }
|
||
};
|
||
|
||
return quarters.ToDictionary(
|
||
q => q.Label,
|
||
q =>
|
||
{
|
||
var filteredResults = sportsTestResults
|
||
.Where(x => x.ScoreTime >= Tool.GetQuarterStartDate(q.Quarter, q.Year) && x.ScoreTime <= Tool.GetQuarterEndDate(q.Quarter, q.Year))
|
||
.Select(x => x.Score + x.AdditionalScore)
|
||
.ToList();
|
||
return filteredResults.Any() ? (float)Math.Round(filteredResults.Average(), 2) : 0;
|
||
}
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 各项目成绩对比
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<Dictionary<string, float>> TestResultContrast(StudentCategoryParam paramDto)
|
||
{
|
||
// 获取指定班级和类别的测试结果
|
||
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x =>
|
||
x.ClassId == paramDto.ClassId &&
|
||
x.SchoolCode.Equals(UserContext.Current.TenantId) &&
|
||
x.CategoryValue == paramDto.CategoryValue
|
||
, paramDto.Mode);
|
||
|
||
// 提取班级所有成绩
|
||
var filteredResults = sportsTestResults
|
||
.Select(x => x.Score + x.AdditionalScore)
|
||
.ToList();
|
||
|
||
// 提取个人成绩
|
||
var personalScore = sportsTestResults
|
||
.Where(x => x.StudentNo == paramDto.StudentNo)
|
||
.Select(x => x.Score + x.AdditionalScore)
|
||
.FirstOrDefault();
|
||
|
||
var quarters = new[]
|
||
{
|
||
new { Label = "个人成绩", Value = personalScore },
|
||
new { Label = "班级平均分", Value = filteredResults.Any() ? (float)Math.Round(filteredResults.Average(),2) : 0f },
|
||
new { Label = "班级中位数", Value = filteredResults.Any() ? (float)Math.Round(filteredResults.Median(),2) : 0f },
|
||
new { Label = "班级最高分", Value = filteredResults.Any() ? (float)Math.Round(filteredResults.Max(),2) : 0f }
|
||
};
|
||
|
||
return quarters.ToDictionary(q => q.Label, q => q.Value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 成绩趋势
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
|
||
public async Task<VariousSportsProportion> ResultTrends(StudentResultTrendsParam paramDto)
|
||
{
|
||
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x =>
|
||
x.StudentNo == paramDto.StudentNo &&
|
||
x.SchoolCode.Equals(UserContext.Current.TenantId) &&
|
||
x.CategoryValue == paramDto.CategoryValue
|
||
, paramDto.Mode);
|
||
|
||
var result = new VariousSportsProportion();
|
||
|
||
DateTime currentDate = DateTime.Now;
|
||
|
||
switch (paramDto.CycleTime)
|
||
{
|
||
case CycleTimeEnum.InThePastWeek:
|
||
// 近一周:按天展示
|
||
var pastWeekResults = sportsTestResults
|
||
.Where(x => x.ScoreTime >= currentDate.AddDays(-7))
|
||
.GroupBy(x => x.ScoreTime.Date);
|
||
|
||
foreach (var group in pastWeekResults)
|
||
{
|
||
result.AxisX.Add(group.Key.ToString("yyyy-MM-dd"));
|
||
var score = (group.Sum(x => x.Score) + group.Sum(x => x.AdditionalScore)) / (group.Select(x => x.StudentNo).Distinct().Count());
|
||
result.AxisY.Add((float)Math.Round(score));
|
||
}
|
||
break;
|
||
|
||
case CycleTimeEnum.InThePastTwoWeeks:
|
||
// 近两周:按天展示
|
||
var pastTwoWeeksResults = sportsTestResults
|
||
.Where(x => x.ScoreTime >= currentDate.AddDays(-14))
|
||
.GroupBy(x => x.ScoreTime.Date);
|
||
|
||
foreach (var group in pastTwoWeeksResults)
|
||
{
|
||
result.AxisX.Add(group.Key.ToString("yyyy-MM-dd"));
|
||
var score = (group.Sum(x => x.Score) + group.Sum(x => x.AdditionalScore)) / (group.Select(x => x.StudentNo).Distinct().Count());
|
||
result.AxisY.Add((float)Math.Round(score));
|
||
}
|
||
break;
|
||
|
||
case CycleTimeEnum.InThePastMonth:
|
||
// 近一月:每5天一个阶段展示
|
||
var pastMonthResults = sportsTestResults
|
||
.Where(x => x.ScoreTime >= currentDate.AddDays(-30))
|
||
.GroupBy(x => (currentDate - x.ScoreTime).Days / 5);
|
||
|
||
foreach (var group in pastMonthResults)
|
||
{
|
||
var minDate = group.Min(r => r.ScoreTime).ToString("yyyy-MM-dd");
|
||
var maxDate = group.Max(r => r.ScoreTime).ToString("yyyy-MM-dd");
|
||
result.AxisX.Add($"{minDate} - {maxDate}");
|
||
var score = (group.Sum(x => x.Score) + group.Sum(x => x.AdditionalScore)) / (group.Select(x => x.StudentNo).Distinct().Count());
|
||
result.AxisY.Add((float)Math.Round(score));
|
||
}
|
||
break;
|
||
|
||
case CycleTimeEnum.InThePastYear:
|
||
// 近一年:按月展示
|
||
var pastYearResults = sportsTestResults
|
||
.Where(x => x.ScoreTime >= currentDate.AddYears(-1))
|
||
.GroupBy(x => new { x.ScoreTime.Year, x.ScoreTime.Month });
|
||
|
||
foreach (var group in pastYearResults)
|
||
{
|
||
result.AxisX.Add($"{group.Key.Year}-{group.Key.Month:D2}");
|
||
var score = (group.Sum(x => x.Score) + group.Sum(x => x.AdditionalScore)) / (group.Select(x => x.StudentNo).Distinct().Count());
|
||
result.AxisY.Add((float)Math.Round(score));
|
||
}
|
||
break;
|
||
|
||
default:
|
||
// 默认处理,如果没有匹配的情况
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 训练记录
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<PageDataDto<StudentTrainingRecordsModel>> TrainingRecords(StudentTrainingRecordsParam paramDto)
|
||
{
|
||
var res = new PageDataDto<StudentTrainingRecordsModel>();
|
||
var tenantId = UserContext.Current.TenantId;
|
||
|
||
if (string.IsNullOrEmpty(paramDto.StudentNo))
|
||
{
|
||
paramDto.StudentNo = _studentRepository.DbContext.Set<S_Student>().First(s => s.SchoolCode == tenantId).StudentNo;
|
||
}
|
||
|
||
// 查询 I_TrainingData 表
|
||
var iotQuery = from student in _studentRepository.DbContext.Set<I_TrainRanking>()
|
||
join trainingData in _studentRepository.DbContext.Set<I_TrainingData>()
|
||
on student.TrainingDataId equals trainingData.Id
|
||
where trainingData.IsDisplay && trainingData.SchoolCode == tenantId
|
||
select new StudentTrainingRecordsModel
|
||
{
|
||
StudentNo = student.StudentNo,
|
||
// 训练模式
|
||
TrainType = trainingData.ModelType ?? 0,
|
||
//项目模式
|
||
ModelName = trainingData.ModelName,
|
||
CategoryValue = (TrainingItemType)trainingData.ItemType,
|
||
// 成绩
|
||
Result = (float?)trainingData.ClassNumAvg,
|
||
ResultLevel = trainingData.ClassScore,
|
||
// 训练时间
|
||
ScoreTime = trainingData.InsertTime,
|
||
};
|
||
|
||
// 查询 Ai_SportsTestData 表
|
||
var aiQuery = from trainingData in _studentRepository.DbContext.Set<Ai_SportsTestData>()
|
||
where trainingData.IsDisplay && trainingData.SchoolCode == tenantId
|
||
select new StudentTrainingRecordsModel
|
||
{
|
||
StudentNo = trainingData.StudentNo,
|
||
TrainType = (int)trainingData.ModeType,
|
||
ModelName = trainingData.ModelName,
|
||
CategoryValue = (TrainingItemType)trainingData.CategoryValue,
|
||
Result = (float?)trainingData.Value,
|
||
ResultLevel = (int?)trainingData.RankEnum,
|
||
ScoreTime = trainingData.ScoreTime
|
||
};
|
||
|
||
// 合并两个查询结果
|
||
var combinedQuery = iotQuery.Concat(aiQuery);
|
||
|
||
// 根据学号过滤
|
||
if (!string.IsNullOrEmpty(paramDto.StudentNo))
|
||
{
|
||
combinedQuery = combinedQuery.Where(x => x.StudentNo == paramDto.StudentNo);
|
||
}
|
||
|
||
// 根据开始时间过滤
|
||
if (paramDto.StartTime.HasValue)
|
||
{
|
||
combinedQuery = combinedQuery.Where(x => x.ScoreTime >= paramDto.StartTime);
|
||
}
|
||
|
||
// 根据结束时间过滤
|
||
if (paramDto.EndTime.HasValue)
|
||
{
|
||
combinedQuery = combinedQuery.Where(x => x.ScoreTime <= paramDto.EndTime);
|
||
}
|
||
|
||
// 根据项目类型过滤
|
||
if (paramDto.CategoryValue > 0)
|
||
{
|
||
combinedQuery = combinedQuery.Where(x => x.CategoryValue == (TrainingItemType)paramDto.CategoryValue);
|
||
}
|
||
|
||
// 根据成绩等级过滤
|
||
if (paramDto.Rank > 0)
|
||
{
|
||
combinedQuery = combinedQuery.Where(x => x.ResultLevel == (int)paramDto.Rank);
|
||
}
|
||
|
||
// 获取总数
|
||
res.Total = await combinedQuery.CountAsync();
|
||
|
||
// 分页和排序
|
||
var list = await combinedQuery
|
||
.OrderBy(c => c.ScoreTime) // 按训练时间排序
|
||
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
|
||
.Take(paramDto.PageSize)
|
||
.ToListAsync();
|
||
|
||
foreach (var item in list)
|
||
{
|
||
// 项目
|
||
item.CategoryName = item.CategoryValue.GetDisplayName();
|
||
var grade = ((AchievementRank)(item.ResultLevel.HasValue && item.ResultLevel.Value > 0 ? item.ResultLevel.Value : 4));
|
||
var gradeName = grade.GetDescription();
|
||
// 等级
|
||
item.Grade = gradeName;
|
||
var trainName = ((Ai_ModeEnum)(item.TrainType)).GetDescription();
|
||
// 训练模式
|
||
item.TrainName = trainName;
|
||
}
|
||
res.Datas = list;
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 体测记录
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<PageDataDto<StudentTestRecordsModel>> TestRecords(StudentTrainingRecordsParam paramDto)
|
||
{
|
||
var res = new PageDataDto<StudentTestRecordsModel>();
|
||
|
||
var tenantId = UserContext.Current.TenantId;
|
||
|
||
if (string.IsNullOrEmpty(paramDto.StudentNo))
|
||
{
|
||
paramDto.StudentNo = this._studentRepository.DbContext.Set<S_Student>().First().StudentNo;
|
||
}
|
||
|
||
// 初始化基础查询条件
|
||
Expression<Func<SportsTestValueModel, bool>> query = (x => x.SchoolCode == tenantId);
|
||
|
||
if (!string.IsNullOrEmpty(paramDto.StudentNo))
|
||
{
|
||
query = query.And(x => x.StudentNo == paramDto.StudentNo);
|
||
}
|
||
|
||
if (paramDto.StartTime.HasValue)
|
||
{
|
||
query = query.And(x => x.ScoreTime >= paramDto.StartTime);
|
||
}
|
||
|
||
if (paramDto.EndTime.HasValue)
|
||
{
|
||
query = query.And(x => x.ScoreTime <= paramDto.StartTime);
|
||
}
|
||
|
||
if (paramDto.CategoryValue > 0)
|
||
{
|
||
query = query.And(x => x.CategoryValue == paramDto.CategoryValue);
|
||
}
|
||
|
||
if (paramDto.Rank > 0)
|
||
{
|
||
query = query.And(x => x.RankEnum == paramDto.Rank);
|
||
}
|
||
|
||
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(query.Compile(), paramDto.TrainType);
|
||
|
||
// 获取总数
|
||
res.Total = sportsTestResults.Count();
|
||
|
||
// 分页和排序
|
||
res.Datas = sportsTestResults
|
||
.OrderBy(c => c.ScoreTime) // 按训练时间排序
|
||
.Select(c => new StudentTestRecordsModel
|
||
{
|
||
TrainName = c.ModeType.GetDescription(),
|
||
CategoryValue = (SportsTestItemType)c.CategoryValue,
|
||
CategoryName = ((SportsTestItemType)c.CategoryValue).GetDisplayName(),
|
||
Result = c.Value,
|
||
Score = (c.Score + c.AdditionalScore),
|
||
Rank = c.Rank,
|
||
ScoreTime = c.ScoreTime
|
||
})
|
||
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
|
||
.Take(paramDto.PageSize)
|
||
.ToList();
|
||
|
||
return res;
|
||
}
|
||
|
||
// 构建课堂模式查询
|
||
private IQueryable<StudentTrainingRecordsModel> BuildClassRoomModeQuery(string tenantId, string studentNo, StudentTrainingRecordsParam paramDto)
|
||
{
|
||
var query = from td in _studentRepository.DbContext.Set<I_TrainingData>()
|
||
join tr in _studentRepository.DbContext.Set<I_TrainRanking>() on td.Id equals tr.TrainingDataId into ranking
|
||
from r in ranking.DefaultIfEmpty()
|
||
where td.SchoolCode == tenantId && r.StudentNo == studentNo
|
||
select new StudentTrainingRecordsModel
|
||
{
|
||
TrainName = "课堂模式",
|
||
ModelName = td.ModelName,
|
||
CategoryValue = (TrainingItemType)td.ItemType,
|
||
CategoryName = ((TrainingItemType)td.ItemType).GetDescription(),
|
||
Result = r.JumpValue,
|
||
ResultLevel = r.ResultLevel,
|
||
ScoreTime = td.InsertTime
|
||
};
|
||
|
||
return ApplyFilters(query, paramDto);
|
||
}
|
||
// 构建自由模式查询
|
||
private IQueryable<StudentTrainingRecordsModel> BuildFreeModeQuery(string tenantId, string studentNo, StudentTrainingRecordsParam paramDto)
|
||
{
|
||
var query = from a in _studentRepository.DbContext.Set<Ai_TrainingData>()
|
||
join n in _studentRepository.DbContext.Set<N_SportsTestValue>() on a.StartTime equals n.ScoreTime
|
||
where a.SchoolCode == tenantId && a.StudentNo == studentNo
|
||
select new StudentTrainingRecordsModel
|
||
{
|
||
TrainName = "自由模式",
|
||
ScoreTime = a.StartTime,
|
||
CategoryValue = a.CategoryValue,
|
||
CategoryName = ((TrainingItemType)Convert.ToInt32(a.CategoryValue)).GetDescription(),
|
||
ModelName = "/",
|
||
Grade = n.Rank
|
||
};
|
||
|
||
return ApplyFilters(query, paramDto);
|
||
}
|
||
|
||
// 通用过滤逻辑
|
||
private IQueryable<StudentTrainingRecordsModel> ApplyFilters(IQueryable<StudentTrainingRecordsModel> query, StudentTrainingRecordsParam paramDto)
|
||
{
|
||
return query
|
||
.WhereIF(paramDto.StartTime.HasValue, x => x.ScoreTime >= paramDto.StartTime)
|
||
.WhereIF(paramDto.EndTime.HasValue, x => x.ScoreTime <= paramDto.EndTime)
|
||
.WhereIF(paramDto.CategoryValue > 0, x => x.CategoryValue == (TrainingItemType)paramDto.CategoryValue)
|
||
.WhereIF(paramDto.Rank > 0, x => x.ResultLevel == (int)paramDto.Rank);
|
||
}
|
||
|
||
|
||
// 构建体测课堂模式查询
|
||
private IQueryable<StudentTestRecordsModel> BuildTestRoomModeQuery(string tenantId, string studentNo, StudentTrainingRecordsParam paramDto)
|
||
{
|
||
var query = from a in _studentRepository.DbContext.Set<I_SportsTestData>()
|
||
join r in _studentRepository.DbContext.Set<N_SportsTestValue>() on a.ScoreTime equals r.ScoreTime
|
||
where a.SchoolCode == tenantId && r.StudentNo == studentNo
|
||
select new StudentTestRecordsModel
|
||
{
|
||
TrainName = "课堂模式",
|
||
CategoryValue = (SportsTestItemType)r.CategoryValue,
|
||
CategoryName = ((SportsTestItemType)r.CategoryValue).GetDescription(),
|
||
Result = r.Value,
|
||
Rank = r.Rank,
|
||
Score = r.Score,
|
||
ScoreTime = r.ScoreTime
|
||
};
|
||
|
||
return TestApplyFilters(query, paramDto);
|
||
}
|
||
private IQueryable<StudentTestRecordsModel> BuildTestFreeModeQuery(string tenantId, string studentNo, StudentTrainingRecordsParam paramDto)
|
||
{
|
||
var query = from a in _studentRepository.DbContext.Set<Ai_TrainingData>()
|
||
join n in _studentRepository.DbContext.Set<N_SportsTestValue>() on a.StartTime equals n.ScoreTime
|
||
where a.SchoolCode == tenantId && a.StudentNo == studentNo
|
||
select new StudentTestRecordsModel
|
||
{
|
||
TrainName = "自由模式",
|
||
ScoreTime = a.StartTime,
|
||
CategoryValue = (SportsTestItemType)a.CategoryValue,
|
||
CategoryName = ((TrainingItemType)Convert.ToInt32(a.CategoryValue)).GetDescription(),
|
||
Rank = n.Rank,
|
||
Score = n.Score,
|
||
Result = n.Value
|
||
};
|
||
|
||
return TestApplyFilters(query, paramDto);
|
||
}
|
||
|
||
|
||
// 通用过滤逻辑
|
||
private IQueryable<StudentTestRecordsModel> TestApplyFilters(IQueryable<StudentTestRecordsModel> query, StudentTrainingRecordsParam paramDto)
|
||
{
|
||
return query
|
||
.WhereIF(paramDto.StartTime.HasValue, x => x.ScoreTime >= paramDto.StartTime)
|
||
.WhereIF(paramDto.EndTime.HasValue, x => x.ScoreTime <= paramDto.EndTime)
|
||
.WhereIF(paramDto.CategoryValue > 0, x => x.CategoryValue == (SportsTestItemType)paramDto.CategoryValue)
|
||
.WhereIF(paramDto.Rank > 0, x => x.Rank == paramDto.RankStr);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 学生名单列表
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<List<StudentNamePageListModel>> GetStudentNamePageList(StudentNamePageListParam paramDto)
|
||
{
|
||
// 查询学生信息
|
||
var students = await _studentRepository.FindAsIQueryable(x => x.ClassId == paramDto.ClassId)
|
||
.Select(x => new StudentNamePageListModel()
|
||
{
|
||
StudentNo = x.StudentNo,
|
||
StudentName = x.StudentName,
|
||
Photo = x.Photo
|
||
})
|
||
.ToListAsync();
|
||
|
||
// 查询两个数据源的成绩并合并
|
||
var combinedResults = await _sportsTestResultRepository.FindAsIQueryable(x =>
|
||
x.ClassId == paramDto.ClassId &&
|
||
x.SchoolCode.Equals(UserContext.Current.TenantId)
|
||
)
|
||
.Select(x => new { x.StudentNo, x.Score })
|
||
.Concat(
|
||
_sportsTestResultRepository.DbContext.Set<Ai_SportsTestData>().Where(x =>
|
||
x.ClassId == paramDto.ClassId &&
|
||
x.SchoolCode.Equals(UserContext.Current.TenantId)
|
||
)
|
||
.Select(x => new { x.StudentNo, x.Score })
|
||
)
|
||
.ToListAsync();
|
||
|
||
// 使用字典来存储平均成绩,便于后续查找
|
||
var averageScoresDict = combinedResults
|
||
.GroupBy(x => x.StudentNo)
|
||
.ToDictionary(g => g.Key, g => g.Average(x => x.Score));
|
||
|
||
// 遍历学生信息,为每个学生分配 Rank
|
||
students.ForEach(student =>
|
||
{
|
||
if (averageScoresDict.TryGetValue(student.StudentNo, out var averageScore))
|
||
{
|
||
student.Rank = averageScore.GetRank(); // 有平均成绩的情况
|
||
}
|
||
else
|
||
{
|
||
student.Rank = 0.GetRank(); // 没有成绩时默认处理
|
||
}
|
||
});
|
||
|
||
return students;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更换班级
|
||
/// </summary>
|
||
/// <param name="studentNoList"></param>
|
||
/// <param name="classId"></param>
|
||
/// <returns></returns>
|
||
public async Task ReplaceClasses(List<string> studentNoList, int classId)
|
||
{
|
||
var students = await _studentRepository.FindAsync(x => studentNoList.Contains(x.StudentNo));
|
||
|
||
if (students == null || students.Count == 0)
|
||
throw new ArgumentNullException("未找到更新的数据");
|
||
|
||
foreach (var student in students)
|
||
{
|
||
student.ClassId = classId;
|
||
student.Modifier = UserContext.Current.UserId;
|
||
student.ModifyDate = DateTime.Now;
|
||
}
|
||
|
||
_studentRepository.UpdateRange(students);
|
||
|
||
await _studentRepository.SaveChangesAsync();
|
||
}
|
||
}
|
||
} |