using AutoMapper;
using Castle.DynamicProxy.Generators;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.ML;
using OfficeOpenXml.ConditionalFormatting;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using SkiaSharp;
using StackExchange.Redis;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VOL.Business.IServices;
using VOL.Business.IServices.Norm;
using VOL.Core.CacheManager;
using VOL.Core.Configuration;
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.Norm.Request;
using VOL.Model.Norm.Response;
using VOL.Model.School.Response;
using VOL.System.IRepositories;
using VOL.System.Repositories;
using static Dapper.SqlMapper;
using static System.Formats.Asn1.AsnWriter;
namespace VOL.Business.Services
{
public class N_SportsTestResultService : IN_SportsTestResultService, IDependency
{
#region 初始化
private readonly IMapper _mapper;
private readonly ICacheService _cacheService;
private readonly ICacheQueryService _cacheQueryService;
private readonly IN_SportsTestResultRepository _sportsTestResultRepository;
private readonly IS_GradeRepository _gradeRepository;
private readonly IS_ClassRepository _classRepository;
private readonly IS_StudentRepository _studentRepository;
private readonly IN_HealthStandardsRepository _healthStandardsRepository;
private readonly IN_SportsTestCategoryRepository _sportsTestCategoryRepository;
//private readonly IG_ActivitiesRepository _activitiesRepository;
[ActivatorUtilitiesConstructor]
public N_SportsTestResultService(IMapper mapper,
ICacheService cacheService,
ICacheQueryService cacheQueryService,
IN_SportsTestResultRepository sportsTestResultRepository,
IS_GradeRepository gradeRepository,
IS_ClassRepository classRepository,
IS_StudentRepository studentRepository,
IN_HealthStandardsRepository healthStandardsRepository,
IN_SportsTestCategoryRepository sportsTestCategoryRepository
//IG_ActivitiesRepository activitiesRepository
)
{
_mapper = mapper;
_cacheService = cacheService;
_cacheQueryService = cacheQueryService;
_sportsTestResultRepository = sportsTestResultRepository;
_gradeRepository = gradeRepository;
_classRepository = classRepository;
_studentRepository = studentRepository;
_healthStandardsRepository = healthStandardsRepository;
_sportsTestCategoryRepository = sportsTestCategoryRepository;
//_activitiesRepository = activitiesRepository;
}
#endregion
///
/// 导入学生体测成绩
///
///
///
///
public async Task ImportStudentsTestData(IFormFile file)
{
if (file == null || file.Length <= 0)
throw new Exception("操作失败");
List dataObjects;
using (var fileStream = file.OpenReadStream())
{
dataObjects = Tool.ConvertExcelToList(fileStream);
}
var studentNos = dataObjects.Select(x => x.StudentNo).Distinct().ToList();
// 用一个查询一次性获取所有学生信息
var students = await (from s in _studentRepository.DbContext.Set()
join c in _studentRepository.DbContext.Set() on s.ClassId equals c.Id
join g in _studentRepository.DbContext.Set() on c.GradeId equals g.Id
where c.SchoolCode.Equals(UserContext.Current.TenantId)
select new
{
s.Id,
s.Age,
s.ClassId,
c.ClassName,
s.StudentName,
GradeId = g.Id,
g.GradeName,
s.Sex,
s.StudentNo
}).ToListAsync();
// 将学生信息存入字典,快速查找
var studentsDict = students.ToDictionary(x => x.StudentNo);
var entityList = new List();
// 将时间变量移到外部,避免重复赋值
var timeNow = DateTime.Now;
foreach (var data in dataObjects)
{
if (!studentsDict.TryGetValue(data.StudentNo, out var student))
{
throw new Exception($"未找到此编号为{data.StudentNo}的学生");
}
// 为每个学生添加多条体测数据
if (data.BMIValue > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.BMI, student, timeNow));
if (data.Sit_And_ReachValue > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.Sit_And_Reach, student, timeNow));
if (data.VitalCapacityValue > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.VitalCapacity, student, timeNow));
if (data.MeterRun_50Value > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.MeterRun_50, student, timeNow));
if (data.OneMinuteJumpRopeValue > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.OneMinuteJumpRope, student, timeNow));
if (data.One_Minute_Sit_UpValue > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.One_Minute_Sit_Up, student, timeNow));
if (data.ShuttleRun_50x8Value > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.ShuttleRun_50x8, student, timeNow));
if (data.StandingLongJumpValue > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.StandingLongJump, student, timeNow));
if (data.MeterRun_800Value > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.MeterRun_800, student, timeNow));
if (data.MeterRun_1000Value > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.MeterRun_1000, student, timeNow));
if (data.Pull_UpValue > 0)
entityList.Add(await AddEnumStudentsTestData(data, SportsTestItemType.Pull_Up, student, timeNow));
}
// 批量添加数据
await _sportsTestResultRepository.AddRangeAsync(entityList);
// 一次性保存所有修改
await _sportsTestResultRepository.SaveChangesAsync();
}
public async Task AddEnumStudentsTestData(ImportStudentsTestDataParam data, SportsTestItemType type, dynamic student, DateTime timeNow)
{
var entity = new N_SportsTestValue
{
TeacherId = 1,
DataSource = DataSource.IOT,
ScoreTime = timeNow,
GradeId = student.GradeId,
ClassId = student.ClassId,
GradeName = student.GradeName,
ClassName = student.ClassName,
SchoolCode = UserContext.Current.TenantId,
Sex = student.Sex,
StudentNo = data.StudentNo,
StudentName = student.StudentName,
Creator = UserContext.Current.UserId,
CreateDate = timeNow
};
int gradeId = student.GradeId;
SexType sexType = student.Sex;
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 LargeScreenDataStat(LargeScreenDataStatParam paramDto)
{
if (paramDto.StartTime == DateTime.MinValue || paramDto.EndTime == DateTime.MinValue)
{
throw new Exception($"请求参数不可为空");
}
var res = new LargeScreenDataStatModel();
//学校信息
res.SchoolInfo = await GetLargeScreenSchoolInfo(paramDto);
//体测情况(体质健康监控)
res.TestSituations = await GetLargeScreenTestSituations(paramDto);
//体质监测排行榜
res.PhysicalMonitoringRanking = await GetLargeScreenPhysicalMonitoringRanking(paramDto);
//赛事活动情况
res.ActivitiesSituation = await GetLargeScreenActivitiesSituation(paramDto);
//肥胖情况
res.ObesitySituation = await GetLargeScreenObesitySituation(paramDto);
//视力情况
res.DicVisionSituation = await GetLargeScreenDicVisionSituation(paramDto);
//年级体测项目成绩监控
res.GradeSportsTestTranscript = await GetLargeScreenGradeSportsTestTranscript(paramDto);
return res;
}
#region 大屏信息
///
/// 大屏学校信息
///
///
///
public async Task GetLargeScreenSchoolInfo(LargeScreenDataStatParam paramDto)
{
var schoolInfo = new SchoolInfoModel();
var tenantId = UserContext.Current.TenantId;
//年级信息
var gradeModels = await (
from g in _gradeRepository.DbContext.Set()
join a in _gradeRepository.DbContext.Set() on g.Id equals a.GradeId
join c in _gradeRepository.DbContext.Set() on g.Id equals c.GradeId into classGroup
from c in classGroup.DefaultIfEmpty()
where a.SchoolCode.Equals(tenantId) && c.SchoolCode.Equals(tenantId)
group new { c } by new { g.Id, g.GradeName } into groupedData
select new
{
groupedData.Key.Id,
groupedData.Key.GradeName,
ClassCount = groupedData.Select(x => x.c.Id).Distinct().Count(),
ClassIds = groupedData.Select(x => x.c.Id).Distinct().ToList()
}).ToListAsync();
//老师信息
var teacherCountModels = await (
from t in _gradeRepository.DbContext.Set()
join a in _gradeRepository.DbContext.Set() on t.Id equals a.TeacherId into assocTeachers
from at in assocTeachers.DefaultIfEmpty()
where t.SchoolCode.Equals(UserContext.Current.TenantId) && t.TeacherStatus != TeacherStatus.Depart
group new { t, at } by new { t.Id } into groupedData
select new TeacherPageListModel()
{
Id = groupedData.Key.Id
}).ToListAsync();
var tCount = teacherCountModels.Count;
//老师信息
var teacherDetailsModels = from a in _gradeRepository.DbContext.Set()
join t in _gradeRepository.DbContext.Set() on a.TeacherId equals t.Id into teacher
from tea in teacher.DefaultIfEmpty()
where tea.SchoolCode.Equals(UserContext.Current.TenantId) && tea.TeacherStatus != TeacherStatus.Depart
group new { a } by new { a.ClassId } into groupedData
select new
{
ClassId = groupedData.Key.ClassId,
TeacherIds = groupedData
.Where(x => x.a.ClassId == groupedData.Key.ClassId)
.Select(x => x.a.TeacherId)
};
var teacherModels = await teacherDetailsModels.ToListAsync();
///班级信息
gradeModels.ForEach(x =>
{
schoolInfo.ClassData.Add(new ClassModel() { GradeName = x.GradeName, ClassCount = x.ClassCount });
var teachers = teacherModels.Where(t => x.ClassIds.Contains(t.ClassId)).ToList();
schoolInfo.TeacherData.Add(new TeacherModel()
{
GradeName = x.GradeName,
TeacherCount = teachers
.SelectMany(c => c.TeacherIds)
.Distinct()
.Count()
});
});
var classIds = gradeModels.SelectMany(x => x.ClassIds).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 s.SchoolCode.Equals(tenantId) && s.StudentStatus == StudentStatus.Normal
select s
).ToListAsync();
schoolInfo.StudentData.MaleCount = students.Where(x => x.Sex == SexType.Male).Count();
schoolInfo.StudentData.FemaleCount = students.Where(x => x.Sex == SexType.Female).Count();
schoolInfo.TotalClassCount = gradeModels.Select(x => x.ClassCount).Sum();
schoolInfo.TotalTeacherCount = tCount;
// 从缓存中获取数据
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.ScoreTime >= paramDto.StartTime && x.ScoreTime <= paramDto.EndTime);
// 运动时长
schoolInfo.AccumulatedTrainDuration = sportsTestResults.Select(x => x.MotionDuration).Sum();
var largeScreenTrainingDataModel = new List();
largeScreenTrainingDataModel.Add(await GeLargeScreenTrainingInfo(1, paramDto));
largeScreenTrainingDataModel.Add(await GeLargeScreenTrainingInfo(2, paramDto));
largeScreenTrainingDataModel.Add(await GeLargeScreenTrainingInfo(3, paramDto));
schoolInfo.LargeScreenTrainingDataModel = largeScreenTrainingDataModel;
return schoolInfo;
}
///
/// 大屏训练数据
///
/// 时间类型(1:今日,2:本周,3:本月)
///
///
public async Task GeLargeScreenTrainingInfo(int dateType, LargeScreenDataStatParam paramDto)
{
var largeScreenTrainingDataModel = new LargeScreenTrainingDataModel();
var tenantId = UserContext.Current.TenantId;
DateTime startTime;
DateTime endTime;
if (dateType == 1)
{
startTime = DateTime.Today;
endTime = DateTime.Today.AddDays(1).AddSeconds(-1);
largeScreenTrainingDataModel.DataType = "今日";
}
else if (dateType == 2)
{
// 获取本周的开始和结束时间
int diff = (7 + (DateTime.Now.DayOfWeek - DayOfWeek.Monday)) % 7;
startTime = DateTime.Now.AddDays(-1 * diff).Date;
endTime = startTime.AddDays(7).AddSeconds(-1);
largeScreenTrainingDataModel.DataType = "本周";
}
else if (dateType == 3)
{
// 获取本月的开始和结束时间
startTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
endTime = startTime.AddMonths(1).AddSeconds(-1);
largeScreenTrainingDataModel.DataType = "本月";
}
else
{
return largeScreenTrainingDataModel;
}
// 从缓存中获取数据
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.ScoreTime >= startTime && x.ScoreTime <= endTime);
var testCategorys = sportsTestResults.Select(x => x.CategoryEnum).Distinct().ToList();
#region 总数据
// 训练次数
largeScreenTrainingDataModel.TrainingCount = sportsTestResults.Count();
// 上课节数
largeScreenTrainingDataModel.AttendClassCount = sportsTestResults.GroupBy(x => x.ClassRoomRecordId).Count();
// 上课时长
largeScreenTrainingDataModel.AttendClassDuration = sportsTestResults.Select(x => x.MotionDuration).Sum();
// 赛事参与人数
var activitiestDatas = await (from ad in _gradeRepository.DbContext.Set()
join a in _gradeRepository.DbContext.Set() on ad.ActivitiesId equals a.Id into activitiesDto
from a in activitiesDto.DefaultIfEmpty()
where a.SchoolCode == tenantId && a.StartDate >= startTime &&
a.EndDate <= endTime && a.ActivitiesStatus == ActivitiesStatus.Completed
select ad).ToListAsync();
largeScreenTrainingDataModel.EventParticipationBodCount = activitiestDatas.GroupBy(x => x.StudentNo).Count();
// 项目测试人数
largeScreenTrainingDataModel.ProjectTestingBodCount = sportsTestResults.GroupBy(x => x.StudentNo).Count();
#endregion
#region 平均数据 (全校学生不区分训练/体测/AI赛事/考级测评/作业)
// 运动人数
largeScreenTrainingDataModel.AccumulatedTrainCount = sportsTestResults.GroupBy(x => x.StudentNo).Count();
// 平均跳绳次数(跳绳个数少于10个不计算在内)
var sportsTestCategorys = await _sportsTestCategoryRepository
.FindAsIQueryable(x => x.StatisticType >= 0 && testCategorys.Contains(x.CategoryEnum))
.Select(x => new SportsTestCategoryModel()
{
Id = x.Id,
CategoryEnum = x.CategoryEnum,
CategoryName = x.CategoryName,
StatisticType = x.StatisticType,
IsRopeSkip = x.IsRopeSkip
}).ToListAsync();
var ropeSkipCategorys = sportsTestCategorys.Where(x => x.IsRopeSkip).Select(x => x.CategoryEnum).ToList();
var avgRopeSkips = sportsTestResults.Where(x => x.CategoryValue.Equals((int)SportsTestItemType.OneMinuteJumpRope) && ropeSkipCategorys.Contains(x.CategoryEnum)).ToList();
largeScreenTrainingDataModel.AvgRopeSkipCount = avgRopeSkips.Count > 0 ? (int)avgRopeSkips.Where(x => x.Value > 10).Average(x => x.Value) : 0;
// 平均运动强度
largeScreenTrainingDataModel.AvgStrength = sportsTestResults.Count > 0 ? (int)sportsTestResults.Average(x => x.Strength) : 0;
// 运动时长
largeScreenTrainingDataModel.MotionDuration = sportsTestResults.Select(x => x.MotionDuration).Sum();
// 平均心率
//var avgHeartRates = sportsTestResults.Where(x => x.CategoryEnum.Equals("HeartRate")).ToList();
largeScreenTrainingDataModel.AvgHeartRate = sportsTestResults.Count > 0 ? (int)sportsTestResults.Average(x => x.Value) : 0;
// 平均消耗
largeScreenTrainingDataModel.AvgConsume = sportsTestResults.Count > 0 ? (int)sportsTestResults.Average(x => x.Consumption) : 0;
#endregion
return largeScreenTrainingDataModel;
}
///
/// 大屏体测情况(体质健康监控)
///
///
///
public async Task GetLargeScreenTestSituations(LargeScreenDataStatParam paramDto)
{
var testSituations = new TestSituations();
var tenantId = UserContext.Current.TenantId;
// 从缓存中获取数据
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.ScoreTime >= paramDto.StartTime && x.ScoreTime <= paramDto.EndTime);
var monitorList = sportsTestResults
.GroupBy(x => new { x.StudentNo })
.Select(g => new
{
g.Key.StudentNo,
g.First().Sex,
Score = (g.Sum(x => x.Score) + g.Sum(x => x.AdditionalScore)) / (g.Select(x => x.CategoryEnum).Distinct().Count())
})
.Select(x => new
{
x.StudentNo,
x.Sex,
x.Score,
Rank = x.Score.GetRank()
}).ToList();
var rankValues = new List { "优秀", "良好", "及格", "不及格" };
// 计算每个 Rank 的百分比和性别统计
var rankStats = rankValues.ToDictionary(rank => rank, rank => new
{
Count = monitorList.Count(x => x.Rank == rank),
MaleCount = monitorList.Count(x => x.Sex == SexType.Male && x.Rank == rank),
FemaleCount = monitorList.Count(x => x.Sex == SexType.Female && x.Rank == rank)
});
// 计算总人数
float totalCount = monitorList.Count(x => rankValues.Contains(x.Rank));
// 计算各个 Rank 的百分比
var rankPercentages = rankStats.ToDictionary(
rank => rank.Key,
rank => (float)Math.Round((rank.Value.Count / totalCount) * 100)
);
// 计算并调整最后一个百分比(确保总和为100%)
float sum = rankPercentages.Values.Sum();
float adjustment = 100 - sum;
rankPercentages["不及格"] += adjustment;
// 更新 TestSituation,保留男女人数和百分比
var dicMonitorList = rankValues.Select(rank => new TestSituation()
{
Title = $"{rank}率",
Value = rankPercentages[rank],
MaleCount = rankStats[rank].MaleCount,
FemaleCount = rankStats[rank].FemaleCount
}).ToList();
// 计算 "优秀率" 和 "良好率" 的总和
var goodValues = dicMonitorList.Where(x => x.Title == "优秀率" || x.Title == "良好率").ToList();
testSituations.ExcellentRate = goodValues.Sum(x => x.Value);
testSituations.ExcellentCount = goodValues.Sum(x => x.MaleCount) + goodValues.Sum(x => x.FemaleCount);
// 填充 TestSituationsData
testSituations.TestSituationsData = dicMonitorList;
return testSituations;
}
///
/// 获取视力统计数据
///
/// 查询参数
/// 左右眼统计数据
public async Task> GetLargeScreenDicVisionSituation(LargeScreenDataStatParam paramDto)
{
var sportsProportionDataList = new List();
// 获取指定时间范围内的视力记录
var visionData = await _sportsTestCategoryRepository.DbContext.Set()
.Where(v => v.SchoolCode == UserContext.Current.TenantId)
.ToListAsync();
// 定义维度范围
var visionCategories = new List<(string Title, float Min, float Max)>
{
("正常", float.MinValue, 50), // 正常 (<50°)
("轻度", 50, 300), // 轻度 (50-300°)
("中度", 300, 600), // 中度 (300-600°)
("高度", 600, float.MaxValue) // 高度 (>600°)
};
// 左右眼统计
var leftEyeStats = new List();
var rightEyeStats = new List();
foreach (var category in visionCategories)
{
// 左眼统计
var leftCount = visionData
.Count(v => v.VisionLeft >= category.Min && v.VisionLeft < category.Max);
leftEyeStats.Add(new StudentSportsProportionData
{
Title = category.Title,
Value = leftCount
});
// 右眼统计
var rightCount = visionData
.Count(v => v.VisionReight >= category.Min && v.VisionReight < category.Max);
rightEyeStats.Add(new StudentSportsProportionData
{
Title = category.Title,
Value = rightCount
});
}
// 组装结果
sportsProportionDataList.Add(new SportsProportionData
{
Name = "右眼",
Datas = rightEyeStats
});
sportsProportionDataList.Add(new SportsProportionData
{
Name = "左眼",
Datas = leftEyeStats
});
return sportsProportionDataList;
}
///
/// 大屏肥胖情况
///
///
///
public async Task> GetLargeScreenObesitySituation(LargeScreenDataStatParam paramDto)
{
var sportsProportionDataList = new List();
var tenantId = UserContext.Current.TenantId;
// 从缓存中获取数据
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.CategoryEnum != null && x.Rank != null && x.ScoreTime >= paramDto.StartTime && x.ScoreTime <= paramDto.EndTime);
var obesityTitles = new List() { "偏瘦", "正常", "超重", "肥胖" };
var m_Obesity = new List();
var f_Obesity = new List();
foreach (var title in obesityTitles)
{
var maleCount = sportsTestResults.Where(x => x.Sex == SexType.Male && x.CategoryEnum.Equals("BMI") && x.Rank.Equals(title)).Count();
var femaleCount = sportsTestResults.Where(x => x.Sex == SexType.Female && x.CategoryEnum.Equals("BMI") && x.Rank.Equals(title)).Count();
if (m_Obesity.Any(c => c.Title == title) || f_Obesity.Any(c => c.Title == title))
{
m_Obesity.First().Value += maleCount;
f_Obesity.First().Value += femaleCount;
}
else
{
m_Obesity.Add(new StudentSportsProportionData()
{
Title = title,
Value = maleCount,
});
f_Obesity.Add(new StudentSportsProportionData()
{
Title = title,
Value = femaleCount,
});
}
}
sportsProportionDataList.Add(new SportsProportionData() { Name = "男", Datas = m_Obesity });
sportsProportionDataList.Add(new SportsProportionData() { Name = "女", Datas = f_Obesity });
return sportsProportionDataList;
}
///
/// 大屏赛事活动情况
///
///
///
public async Task GetLargeScreenActivitiesSituation(LargeScreenDataStatParam paramDto)
{
var activitiesSituation = new ActivitiesSituation();
var tenantId = UserContext.Current.TenantId;
// 从缓存中获取数据
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.ScoreTime >= paramDto.StartTime && x.ScoreTime <= paramDto.EndTime);
var activities = await _gradeRepository.DbContext.Set().Where(x => x.SchoolCode == tenantId).ToListAsync();
activitiesSituation.ActivitiesTotalCount = activities.Count();
activitiesSituation.CompletedCount = activities.Where(x => x.ActivitiesStatus == ActivitiesStatus.Completed).Count();
activitiesSituation.AfootCount = activities.Where(x => x.ActivitiesStatus == ActivitiesStatus.Afoot).Count();
activitiesSituation.NotStartedCount = activities.Where(x => x.ActivitiesStatus == ActivitiesStatus.NotStarted).Count();
activitiesSituation.ParticipationRate = activitiesSituation.ActivitiesTotalCount > 0 ? activitiesSituation.CompletedCount / activitiesSituation.ActivitiesTotalCount * 100 : 0;
return activitiesSituation;
}
///
/// 大屏体质监测排行榜
///
///
///
public async Task> GetLargeScreenPhysicalMonitoringRanking(LargeScreenDataStatParam paramDto)
{
var physicalMonitoringList = new List();
var tenantId = UserContext.Current.TenantId;
// 从缓存中获取数据
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.ScoreTime >= paramDto.StartTime && x.ScoreTime <= paramDto.EndTime);
// 年级-班级信息
var gradeClassQuery = from c in _classRepository.DbContext.Set()
join g in _classRepository.DbContext.Set() on c.GradeId equals g.Id
join a in _classRepository.DbContext.Set() on g.Id equals a.GradeId
where a.SchoolCode == tenantId && c.SchoolCode.Equals(tenantId)
select new
{
GradeAndClassName = $"{g.GradeName}-{c.ClassName}",
};
var gradeClassModels = await gradeClassQuery.ToListAsync();
var monitorList = sportsTestResults
.GroupBy(x => new { x.StudentNo })
.Select(g => new
{
g.Key.StudentNo,
g.First().Sex,
g.First().ClassId,
g.First().GradeId,
g.First().ClassName,
g.First().GradeName,
Score = (g.Sum(x => x.Score) + g.Sum(x => x.AdditionalScore)) / (g.Select(x => x.CategoryEnum).Distinct().Count())
})
.Select(x => new
{
x.StudentNo,
x.Sex,
x.ClassId,
x.GradeId,
x.ClassName,
x.GradeName,
x.Score,
Rank = x.Score.GetRank()
}).ToList();
physicalMonitoringList = monitorList
.GroupBy(x => new { x.ClassId, x.GradeId, x.ClassName, x.GradeName })
.Select(g => new
{
GradeAndClassName = $"{g.Key.GradeName}-{g.Key.ClassName}",
MaleValue = (float)g.Count(x => x.Sex == SexType.Male && x.Score >= 80) / g.Count() * 100,
FemaleValue = (float)g.Count(x => x.Sex == SexType.Female && x.Score >= 80) / g.Count() * 100,
OverallValue = (float)g.Where(x => x.Rank == "优秀" || x.Rank == "良好").Count(x => x.Score >= 80) / g.Count() * 100,
})
.OrderByDescending(g => g.OverallValue)
.Select((g, index) => new PhysicalMonitoring
{
GradeAndClassName = g.GradeAndClassName,
ExcellentRate = Math.Round(g.OverallValue),
Ranking = index + 1
})
.ToList();
var ranking = physicalMonitoringList.Count + 1;
foreach (var gradeClass in gradeClassModels)
{
var physicalMonitoring = physicalMonitoringList.FirstOrDefault(c => c.GradeAndClassName == gradeClass.GradeAndClassName);
if (physicalMonitoring == null)
{
physicalMonitoringList.Add(new PhysicalMonitoring()
{
GradeAndClassName = gradeClass.GradeAndClassName,
ExcellentRate = 0,
Ranking = ranking++
});
}
}
return physicalMonitoringList;
}
///
/// 大屏 年级体测项目成绩监控
///
///
///
public async Task> GetLargeScreenGradeSportsTestTranscript(LargeScreenDataStatParam paramDto)
{
var gradeSportsTestTranscriptList = new List();
var tenantId = UserContext.Current.TenantId;
// 从缓存中获取数据
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.ScoreTime >= paramDto.StartTime && x.ScoreTime <= paramDto.EndTime);
// 年级-班级信息
var gradeClassQuery = from g in _classRepository.DbContext.Set()
join a in _classRepository.DbContext.Set() on g.Id equals a.GradeId
where a.SchoolCode == tenantId
select new
{
GradeId = g.Id,
GradeAndClassName = $"{g.GradeName}",
};
var gradeCategory = await (
from g in _gradeRepository.DbContext.Set()
join s in _gradeRepository.DbContext.Set() on g.CategoryValue equals s.CategoryValue
select new
{
GradeId = g.GradeId,
CategoryId = g.CategoryValue,
CategoryName = s.CategoryName,
}).ToListAsync();
var gradeClassModels = await gradeClassQuery.ToListAsync();
var sportsTestList = sportsTestResults.GroupBy(x => new { x.GradeId, x.GradeName }).OrderBy(g => g.Key.GradeId).ToList();
foreach (var gradeClass in gradeClassModels)
{
var sportsProportionDataList = new List();
var sportsTest = sportsTestList.FirstOrDefault(s => s.Key.GradeId == gradeClass.GradeId);
foreach (var type in gradeCategory.Where(c => c.GradeId == gradeClass.GradeId).OrderBy(c => c.CategoryId))
{
var typeSportsTestResults = sportsTest != null ? sportsTest.Where(x => x.CategoryValue == type.CategoryId).ToList() : new List();
// 计算平均值
var maleAverage = typeSportsTestResults.Where(x => x.Sex == SexType.Male).Any()
? typeSportsTestResults.Where(x => x.Sex == SexType.Male).Average(x => x.Score)
: 0;
var femaleAverage = typeSportsTestResults.Where(x => x.Sex == SexType.Female).Any()
? typeSportsTestResults.Where(x => x.Sex == SexType.Female).Average(x => x.Score)
: 0;
var sumAverage = typeSportsTestResults.Any() ? typeSportsTestResults.Average(x => x.Score) : 0;
var studentSportsProportionData = new List
{
new StudentSportsProportionData { Title = "总分数", Value = (int)sumAverage },
new StudentSportsProportionData { Title = "男生", Value = (int)maleAverage },
new StudentSportsProportionData { Title = "女生", Value = (int)femaleAverage }
};
sportsProportionDataList.Add(new SportsProportionData
{
Name = type.CategoryName,
Datas = studentSportsProportionData
});
}
gradeSportsTestTranscriptList.Add(new GradeSportsTestTranscript()
{
GradeAndClassName = gradeClass.GradeAndClassName,
Datas = sportsProportionDataList
});
}
return gradeSportsTestTranscriptList;
}
///
/// 大屏 班级平均运动强度监控
///
///
///
public async Task> LargeScreenAverageClassExerciseIntensity(LargeScreenAverageClassExerciseIntensityParam paramDto)
{
if (paramDto.GradeId < 0 || paramDto.StartTime == DateTime.MinValue || paramDto.EndTime == DateTime.MinValue)
{
throw new Exception($"请求参数不可为空");
}
var sportsProportionDataList = new List();
var tenantId = UserContext.Current.TenantId;
// 从缓存中获取数据
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.GradeId == paramDto.GradeId && x.ScoreTime >= paramDto.StartTime && x.ScoreTime <= paramDto.EndTime);
// 班级信息
var classQuery = from c in _classRepository.DbContext.Set()
join g in _classRepository.DbContext.Set() on c.GradeId equals g.Id
join a in _classRepository.DbContext.Set() on g.Id equals a.GradeId
where a.SchoolCode == tenantId && c.SchoolCode == tenantId && g.Id == paramDto.GradeId
select c;
var classModels = await classQuery.ToListAsync();
if (classModels == null || classModels.Count == 0)
throw new ArgumentNullException("未找到班级数据");
var totalStrength = sportsTestResults.Any() ? sportsTestResults.Select(x => x.Strength).Average(x => x) : 0;
var classGroups = sportsTestResults.Any() ? sportsTestResults.GroupBy(c => new { c.ClassId, c.ClassName }).ToList() : null;
foreach (var classModel in classModels)
{
var classGroup = classGroups?.FirstOrDefault(c => c.Key.ClassId == classModel.Id && c.Key.ClassName == classModel.ClassName);
if (classGroup != null)
{
// 计算该班级的平均强度
var averageStrength = classGroup.Select(x => x.Strength).Average(x => x);
var percentage = averageStrength == 0 ? 0 : (averageStrength / totalStrength) * 100;
var studentSportsProportionData = new List
{
new StudentSportsProportionData { Title = "平均强度", Value =((int)Math.Round(percentage) > 100 ? 100 : (int)Math.Round(percentage)) }
};
sportsProportionDataList.Add(new SportsProportionData
{
Name = classGroup.Key.ClassName,
Datas = studentSportsProportionData
});
}
else
{
var studentSportsProportionData = new List
{
new StudentSportsProportionData { Title = "平均强度", Value = 0 }
};
sportsProportionDataList.Add(new SportsProportionData
{
Name = classModel.ClassName,
Datas = studentSportsProportionData
});
}
}
return sportsProportionDataList;
}
#endregion
public async Task> GetSportsTestCategoryPageList(StudentsTestDataListParam paramDto)
{
var res = new PageDataDto();
var query = from r in _healthStandardsRepository.DbContext.Set()
join c in _healthStandardsRepository.DbContext.Set() on r.CategoryEnum equals c.CategoryEnum
where r.SchoolCode.Equals(UserContext.Current.TenantId)
select new StudentsTestDataModel()
{
Id = r.Id,
GradeId = r.Id,
GradeName = r.GradeName,
StudentNo = r.StudentNo,
CategoryName = c.CategoryName,
ClassId = r.ClassId,
ClassName = r.ClassName,
ClassRank = r.ClassRank,
Consumption = r.Consumption,
MotionDuration = r.MotionDuration,
Strength = r.Strength,
TeacherId = r.TeacherId,
Remarks = r.Remarks,
Value = r.Value,
Rank = r.Rank,
CategoryId = c.Id,
Score = r.Score,
Sex = r.Sex == SexType.Male ? "男" : "女"
};
if (!string.IsNullOrWhiteSpace(paramDto.StudentNo))
{
query = query.Where(x => x.StudentNo.Equals(paramDto.StudentNo));
}
if (paramDto.TeacherId > 0)
{
query = query.Where(x => x.TeacherId == paramDto.TeacherId);
}
if (paramDto.GradeId > 0)
{
query = query.Where(x => x.GradeId == paramDto.GradeId);
}
if (paramDto.ClassId > 0)
{
query = query.Where(x => x.ClassId == paramDto.ClassId);
}
if (paramDto.CategoryId > 0)
{
query = query.Where(x => x.CategoryId == paramDto.CategoryId);
}
if (paramDto.Sex > 0)
{
query = query.Where(x => x.Sex.Equals(paramDto.Sex == SexType.Male ? "男" : "女"));
}
res.Total = await query.CountAsync();
var list = await query
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
.Take(paramDto.PageSize)
.ToListAsync();
res.Datas = list;
return res;
}
public async Task> GetStudentsTestDataList(StudentsTestDataListParam paramDto)
{
var query = from r in _healthStandardsRepository.DbContext.Set()
join c in _healthStandardsRepository.DbContext.Set() on r.CategoryEnum equals c.CategoryEnum
where r.SchoolCode.Equals(UserContext.Current.TenantId)
select new StudentsTestDataModel()
{
Id = r.Id,
GradeId = r.Id,
GradeName = r.GradeName,
StudentNo = r.StudentNo,
CategoryName = c.CategoryName,
ClassId = r.ClassId,
ClassName = r.ClassName,
ClassRank = r.ClassRank,
Consumption = r.Consumption,
MotionDuration = r.MotionDuration,
Strength = r.Strength,
TeacherId = r.TeacherId,
Remarks = r.Remarks,
Value = r.Value,
Rank = r.Rank,
CategoryId = c.Id,
Score = r.Score,
Sex = r.Sex == SexType.Male ? "男" : "女"
};
if (!string.IsNullOrWhiteSpace(paramDto.StudentNo))
{
query = query.Where(x => x.StudentNo.Equals(paramDto.StudentNo));
}
if (paramDto.TeacherId > 0)
{
query = query.Where(x => x.TeacherId == paramDto.TeacherId);
}
if (paramDto.GradeId > 0)
{
query = query.Where(x => x.GradeId == paramDto.GradeId);
}
if (paramDto.ClassId > 0)
{
query = query.Where(x => x.ClassId == paramDto.ClassId);
}
if (paramDto.CategoryId > 0)
{
query = query.Where(x => x.CategoryId == paramDto.CategoryId);
}
if (paramDto.Sex > 0)
{
query = query.Where(x => x.Sex.Equals(paramDto.Sex == SexType.Male ? "男" : "女"));
}
var list = await query.ToListAsync();
return list;
}
public async Task AddStudentsTestData(List paramDto)
{
var studentNos = paramDto.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 g.SchoolCode.Equals(UserContext.Current.TenantId)
select new
{
Id = s.Id,
Age = s.Age,
ClassId = s.ClassId,
ClassName = c.ClassName,
GradeId = g.Id,
GradeName = g.GradeName,
Sex = s.Sex,
StudentNo = s.StudentNo,
}).ToListAsync();
var distinctCategoryTypes = paramDto.Select(c => c.CategoryEnum).Distinct().ToList();
var healthStandards = await _healthStandardsRepository.FindAsync(x => distinctCategoryTypes.Contains(x.CategoryEnum));
var entityList = new List();
var timeNow = DateTime.Now;
foreach (var data in paramDto)
{
var entity = _mapper.Map(data);
var student = students.FirstOrDefault(x => x.StudentNo.Equals(data.StudentNo));
if (student == null)
throw new Exception($"未找到此编号为{data.StudentNo}的学生");
var standard = healthStandards.Where(x =>
x.CategoryEnum.Equals(data.CategoryEnum) &&
x.GradeId == student.GradeId &&
x.Sex == student.Sex &&
data.Value >= x.MinValue &&
data.Value < x.MaxValue
).FirstOrDefault();
if (standard != null)
{
entity.Score = standard.Score;
entity.Rank = standard.Rank;
}
entity.GradeId = student.GradeId;
entity.ClassId = student.ClassId;
entity.GradeName = student.GradeName;
entity.ClassName = student.ClassName;
entity.Sex = student.Sex;
entity.Creator = UserContext.Current.UserId;
entity.CreateDate = timeNow;
entityList.Add(entity);
}
await _sportsTestResultRepository.AddRangeAsync(entityList);
await _sportsTestResultRepository.SaveChangesAsync();
var ranks = await _sportsTestResultRepository.FindAsIQueryable(x => distinctCategoryTypes.Contains(x.CategoryEnum))
.Select(x => x.Score)
.Distinct()
.OrderByDescending(value => value)
.ToListAsync();
foreach (var entity in entityList)
{
if (entity.Score > 0)
{
entity.ClassRank = ranks.IndexOf(entity.Score) + 1;
}
}
_sportsTestResultRepository.UpdateRange(entityList);
await _sportsTestResultRepository.SaveChangesAsync();
}
public async Task ModifyStudentsTestData(List paramDto)
{
var studentNos = paramDto.Select(x => x.StudentNo).Distinct().ToList();
var entityList = await _sportsTestResultRepository.FindAsync(x => studentNos.Contains(x.StudentNo));
var distinctCategoryTypes = paramDto.Select(c => c.CategoryEnum).Distinct().ToList();
var healthStandards = await _healthStandardsRepository.FindAsync(x => distinctCategoryTypes.Contains(x.CategoryEnum));
var timeNow = DateTime.Now;
foreach (var data in paramDto)
{
var entity = entityList.FirstOrDefault(x => x.StudentNo.Equals(data.StudentNo));
if (entity == null)
throw new Exception($"未找到要更新的数据");
entity = _mapper.Map(data);
var standard = healthStandards.Where(x =>
x.CategoryEnum.Equals(data.CategoryEnum) &&
x.GradeId == entity.GradeId &&
x.Sex == entity.Sex &&
data.Value >= x.MinValue &&
data.Value < x.MaxValue
).FirstOrDefault();
if (standard != null)
{
entity.Score = standard.Score;
entity.Rank = standard.Rank;
}
entity.Modifier = UserContext.Current.UserId;
entity.ModifyDate = timeNow;
entityList.Add(entity);
}
_sportsTestResultRepository.UpdateRange(entityList);
await _sportsTestResultRepository.SaveChangesAsync();
var ranks = await _sportsTestResultRepository.FindAsIQueryable(x => distinctCategoryTypes.Contains(x.CategoryEnum))
.Select(x => x.Score)
.Distinct()
.OrderByDescending(value => value)
.ToListAsync();
foreach (var entity in entityList)
{
if (entity.Score > 0)
{
entity.ClassRank = ranks.IndexOf(entity.Score) + 1;
}
}
_sportsTestResultRepository.UpdateRange(entityList);
await _sportsTestResultRepository.SaveChangesAsync();
}
public async Task DeleteStudentsTestData(List Ids)
{
var model = await _sportsTestResultRepository.FindAsync(x => Ids.Contains(x.Id));
if (model == null)
throw new ArgumentNullException($"未找到删除的数据");
_sportsTestResultRepository.DbContext.RemoveRange(model);
await _sportsTestResultRepository.SaveChangesAsync();
}
}
}