让人
This commit is contained in:
parent
42d5d0aa64
commit
c527820dc7
@ -22,6 +22,12 @@ namespace VOL.Business.IServices
|
||||
Task<LargeScreenDataStatModel> LargeScreenDataStat(LargeScreenDataStatParam paramDto);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 智慧操场
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<SmartPlaygroundModel> SmartPlayground();
|
||||
|
||||
/// <summary>
|
||||
/// 学期数据
|
||||
/// </summary>
|
||||
|
@ -33,6 +33,7 @@ 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.Norm.Request;
|
||||
using VOL.Model.Norm.Response;
|
||||
using VOL.Model.School.Response;
|
||||
@ -506,6 +507,343 @@ namespace VOL.Business.Services
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#region 智慧操场数据
|
||||
/// <summary>
|
||||
/// 智慧操场
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<SmartPlaygroundModel> SmartPlayground()
|
||||
{
|
||||
var res = new SmartPlaygroundModel();
|
||||
var tenantId = UserContext.Current.TenantId;
|
||||
|
||||
//学校信息
|
||||
var smartPlaygroundSchoolInfoKey = $"SmartPlaygroundSchoolInfo_{tenantId}";
|
||||
var schoolInfo = _cacheService.Get<SchoolInfoModel>(smartPlaygroundSchoolInfoKey);
|
||||
if (schoolInfo == null)
|
||||
{
|
||||
schoolInfo = await SmartPlaygroundSchoolInfo(tenantId);
|
||||
_cacheService.AddObject(smartPlaygroundSchoolInfoKey, schoolInfo, 600);
|
||||
}
|
||||
res.SchoolInfo = schoolInfo;
|
||||
|
||||
var today = DateTime.Today;
|
||||
|
||||
// 先确定当前学期的时间范围
|
||||
DateTime startDate, endDate;
|
||||
|
||||
// 规则:上学期 9月1日 – 次年2月1日;下学期 2月1日 – 9月1日
|
||||
if (today.Month >= 9 || today.Month < 2) // 上学期
|
||||
{
|
||||
startDate = new DateTime(today.Month >= 9 ? today.Year : today.Year - 1, 1, 1);
|
||||
endDate = new DateTime(today.Month >= 9 ? today.Year + 1 : today.Year, 2, 1);
|
||||
}
|
||||
else // 下学期
|
||||
{
|
||||
startDate = new DateTime(today.Year, 2, 1);
|
||||
endDate = new DateTime(today.Year, 10, 1);
|
||||
}
|
||||
|
||||
var SmartPlaygroundKey = $"SmartPlayground_{tenantId}";
|
||||
|
||||
// 从缓存中获取数据
|
||||
var sportsTestResults = _cacheService.Get<List<SportsTestValueModel>>(SmartPlaygroundKey);
|
||||
|
||||
if (sportsTestResults == null)
|
||||
{
|
||||
// 查询条件加上 ScoreTime 范围
|
||||
var testResults = await _sportsTestResultRepository
|
||||
.FindAsIQueryable(x => x.SchoolCode == tenantId
|
||||
&& x.IsDisplay
|
||||
&& x.DataSource == DataSource.XW
|
||||
&& x.ScoreTime >= startDate
|
||||
&& x.ScoreTime < endDate)
|
||||
.ToListAsync();
|
||||
|
||||
sportsTestResults = _mapper.Map<List<SportsTestValueModel>>(testResults);
|
||||
_cacheService.AddObject(smartPlaygroundSchoolInfoKey, schoolInfo, 600);
|
||||
}
|
||||
|
||||
var classListKey = $"ClassList_{tenantId}";
|
||||
|
||||
var classList = _cacheService.Get<List<S_Class>>(classListKey);
|
||||
|
||||
if (classList == null || classList.Count == 0)
|
||||
{
|
||||
classList = await _classRepository.FindAsIQueryable(x => x.SchoolCode == tenantId).ToListAsync();
|
||||
_cacheService.AddObject(classListKey, classList, 3600);
|
||||
}
|
||||
|
||||
|
||||
// 统计逻辑
|
||||
var rankValues = new List<string> { "优秀", "良好", "及格", "不及格" };
|
||||
|
||||
var totalCount = sportsTestResults.Count;
|
||||
var totalMale = sportsTestResults.Count(x => x.Sex == SexType.Male);
|
||||
var totalFemale = sportsTestResults.Count(x => x.Sex == SexType.Female);
|
||||
|
||||
var tempStats = new List<RankStatsDto>();
|
||||
|
||||
for (int i = 0; i < rankValues.Count; i++)
|
||||
{
|
||||
var rank = rankValues[i];
|
||||
var count = sportsTestResults.Count(x => x.Score.GetRank() == rank);
|
||||
var maleCount = sportsTestResults.Count(x => x.Sex == SexType.Male && x.Score.GetRank() == rank);
|
||||
var femaleCount = sportsTestResults.Count(x => x.Sex == SexType.Female && x.Score.GetRank() == rank);
|
||||
|
||||
int rate = totalCount == 0 ? 0 : (i < rankValues.Count - 1 ? (int)Math.Round((double)count / totalCount * 100) : 100 - tempStats.Sum(s => s.Rate));
|
||||
int maleRate = totalMale == 0 ? 0 : (i < rankValues.Count - 1 ? (int)Math.Round((double)maleCount / totalMale * 100) : 100 - tempStats.Sum(s => s.MaleRate));
|
||||
int femaleRate = totalFemale == 0 ? 0 : (i < rankValues.Count - 1 ? (int)Math.Round((double)femaleCount / totalFemale * 100) : 100 - tempStats.Sum(s => s.FemaleRate));
|
||||
|
||||
tempStats.Add(new RankStatsDto
|
||||
{
|
||||
Rank = rank,
|
||||
Count = count,
|
||||
MaleCount = maleCount,
|
||||
FemaleCount = femaleCount,
|
||||
Rate = rate,
|
||||
MaleRate = maleRate,
|
||||
FemaleRate = femaleRate
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
res.RankStatsList = tempStats;
|
||||
|
||||
res.ResultSituationDic = sportsTestResults
|
||||
.GroupBy(x => x.CategoryValue)
|
||||
.ToDictionary(
|
||||
g => ((SportsTestItemType)g.Key).GetDisplayName(),
|
||||
g =>
|
||||
{
|
||||
var result = new ResultSituation();
|
||||
|
||||
var categoryTotal = g.Count();
|
||||
var categoryMaleTotal = g.Count(x => x.Sex == SexType.Male);
|
||||
var categoryFemaleTotal = g.Count(x => x.Sex == SexType.Female);
|
||||
|
||||
int sumRate = 0, sumMaleRate = 0, sumFemaleRate = 0;
|
||||
|
||||
var tempStats = new List<TestSituationsModel>();
|
||||
|
||||
for (int i = 0; i < rankValues.Count; i++)
|
||||
{
|
||||
var rank = rankValues[i];
|
||||
var count = g.Count(x => x.Score.GetRank() == rank);
|
||||
var maleCount = g.Count(x => x.Sex == SexType.Male && x.Score.GetRank() == rank);
|
||||
var femaleCount = g.Count(x => x.Sex == SexType.Female && x.Score.GetRank() == rank);
|
||||
|
||||
int rate = categoryTotal == 0 ? 0 : (i < rankValues.Count - 1
|
||||
? (int)Math.Round((double)count / categoryTotal * 100)
|
||||
: 100 - sumRate);
|
||||
|
||||
int activityLevel = categoryTotal == 0 ? 0 : (int)Math.Round((double)categoryTotal / sportsTestResults.Count * 100);
|
||||
|
||||
tempStats.Add(new TestSituationsModel
|
||||
{
|
||||
Rank = rank,
|
||||
Count = count,
|
||||
MaleCount = maleCount,
|
||||
FemaleCount = femaleCount,
|
||||
Rate = rate,
|
||||
ActivityLevel = activityLevel
|
||||
});
|
||||
}
|
||||
|
||||
result.TestSituationsList = tempStats;
|
||||
|
||||
var maleData = g.Where(x => x.Sex == SexType.Male).ToList();
|
||||
var femaleData = g.Where(x => x.Sex == SexType.Female).ToList();
|
||||
|
||||
var maleProportion = GetMonthlyAverageScore(maleData);
|
||||
var femaleProportion = GetMonthlyAverageScore(femaleData);
|
||||
|
||||
result.AvgTestResultDic.Add("男生", maleProportion);
|
||||
result.AvgTestResultDic.Add("女生", femaleProportion);
|
||||
|
||||
result.Vitality = (int)Math.Round((double)g.Count() / sportsTestResults.Count() * 100);
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
|
||||
res.ClassSportsRankList = sportsTestResults
|
||||
.GroupBy(x => new { x.ClassId })
|
||||
.Select(g => new ClassSportsRankingDto
|
||||
{
|
||||
ClassId = g.Key.ClassId,
|
||||
ClassName = classList.Where(c => c.Id == g.Key.ClassId).Select(x => $"{x.GradeName}-{x.ClassName}").FirstOrDefault() ?? "",
|
||||
Count = g.Count()
|
||||
})
|
||||
.OrderByDescending(x => x.Count)
|
||||
.Take(10)
|
||||
.Select((x, index) =>
|
||||
{
|
||||
x.Rank = index + 1;
|
||||
return x;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
res.GradeExcellentRateDic = classList
|
||||
.GroupBy(x => x.GradeId)
|
||||
.ToDictionary(
|
||||
g => g.First().GradeName,
|
||||
g =>
|
||||
{
|
||||
var gradeStudents = sportsTestResults.Where(x => x.GradeId == g.Key).ToList();
|
||||
int total = gradeStudents.Count;
|
||||
|
||||
var goodRanks = new[] { "优秀", "良好" };
|
||||
|
||||
int femaleTotal = gradeStudents.Count(x => x.Sex == SexType.Female);
|
||||
int maleTotal = gradeStudents.Count(x => x.Sex == SexType.Male);
|
||||
|
||||
var result = new GradeExcellentRate()
|
||||
{
|
||||
// 优良率(全体)
|
||||
Rate = total == 0 ? 0 :
|
||||
(int)Math.Round((double)gradeStudents.Count(x => goodRanks.Contains(x.Score.GetRank())) / total * 100),
|
||||
|
||||
// 女生优良率
|
||||
FemaleRate = femaleTotal == 0 ? 0 :
|
||||
(int)Math.Round((double)gradeStudents.Count(x => x.Sex == SexType.Female && goodRanks.Contains(x.Score.GetRank())) / femaleTotal * 100),
|
||||
|
||||
// 男生优良率
|
||||
MaleRate = maleTotal == 0 ? 0 :
|
||||
(int)Math.Round((double)gradeStudents.Count(x => x.Sex == SexType.Male && goodRanks.Contains(x.Score.GetRank())) / maleTotal * 100)
|
||||
};
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 智慧操场学校信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<SchoolInfoModel> SmartPlaygroundSchoolInfo(string tenantId)
|
||||
{
|
||||
var schoolInfo = new SchoolInfoModel();
|
||||
|
||||
// 使用单个查询获取年级、班级和教师信息
|
||||
var gradeModels = await (
|
||||
from g in _gradeRepository.DbContext.Set<S_Grade>()
|
||||
join a in _gradeRepository.DbContext.Set<S_SchoolAssocGrade>() on g.Id equals a.GradeId
|
||||
where a.SchoolCode == tenantId
|
||||
select new
|
||||
{
|
||||
g.Id,
|
||||
g.GradeName,
|
||||
Classes = _gradeRepository.DbContext.Set<S_Class>()
|
||||
.Where(c => c.GradeId == g.Id && c.SchoolCode == tenantId)
|
||||
.Select(c => new { c.Id })
|
||||
.ToList()
|
||||
})
|
||||
.Select(x => new
|
||||
{
|
||||
x.Id,
|
||||
x.GradeName,
|
||||
ClassCount = x.Classes.Count,
|
||||
ClassIds = x.Classes.Select(c => c.Id).ToList()
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
// 获取教师总数(简化查询)
|
||||
var tCount = await _gradeRepository.DbContext.Set<S_Teacher>()
|
||||
.Where(t => t.SchoolCode == tenantId && t.TeacherStatus != TeacherStatus.Depart)
|
||||
.CountAsync();
|
||||
|
||||
// 获取班级与教师的关联信息
|
||||
var classTeacherMap = await (
|
||||
from a in _gradeRepository.DbContext.Set<S_ClassAssocTeacher>()
|
||||
join t in _gradeRepository.DbContext.Set<S_Teacher>() on a.TeacherId equals t.Id
|
||||
where t.SchoolCode == tenantId && t.TeacherStatus != TeacherStatus.Depart
|
||||
group a.TeacherId by a.ClassId into g
|
||||
select new { ClassId = g.Key, TeacherIds = g.Distinct().ToList() })
|
||||
.ToDictionaryAsync(x => x.ClassId, x => x.TeacherIds);
|
||||
|
||||
// 获取学生信息(简化查询)
|
||||
var studentCounts = await _studentRepository.DbContext.Set<S_Student>()
|
||||
.Where(s => s.SchoolCode == tenantId && s.StudentStatus == StudentStatus.Normal)
|
||||
.GroupBy(s => s.Sex)
|
||||
.Select(g => new { Sex = g.Key, Count = g.Count() })
|
||||
.ToListAsync();
|
||||
|
||||
// 处理数据
|
||||
var allClassIds = gradeModels.SelectMany(x => x.ClassIds).ToList();
|
||||
var gradeTeacherCounts = new Dictionary<Guid, int>(); // 假设年级ID类型为Guid
|
||||
|
||||
foreach (var grade in gradeModels)
|
||||
{
|
||||
schoolInfo.ClassData.Add(new ClassModel
|
||||
{
|
||||
GradeName = grade.GradeName,
|
||||
ClassCount = grade.ClassCount
|
||||
});
|
||||
|
||||
// 计算该年级的教师数量
|
||||
var teacherIds = new HashSet<int>(); // 假设教师ID类型为Guid
|
||||
foreach (var classId in grade.ClassIds)
|
||||
{
|
||||
if (classTeacherMap.TryGetValue(classId, out var classTeacherIds))
|
||||
{
|
||||
foreach (var teacherId in classTeacherIds)
|
||||
{
|
||||
teacherIds.Add(teacherId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schoolInfo.TeacherData.Add(new TeacherModel
|
||||
{
|
||||
GradeName = grade.GradeName,
|
||||
TeacherCount = teacherIds.Count
|
||||
});
|
||||
}
|
||||
|
||||
// 设置学生数据
|
||||
schoolInfo.StudentData.MaleCount = studentCounts.FirstOrDefault(x => x.Sex == SexType.Male)?.Count ?? 0;
|
||||
schoolInfo.StudentData.FemaleCount = studentCounts.FirstOrDefault(x => x.Sex == SexType.Female)?.Count ?? 0;
|
||||
|
||||
// 设置总计数据
|
||||
schoolInfo.TotalClassCount = gradeModels.Sum(x => x.ClassCount);
|
||||
schoolInfo.TotalTeacherCount = tCount;
|
||||
|
||||
return schoolInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 月份分组
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public VariousSportsProportion GetMonthlyAverageScore(List<SportsTestValueModel> data)
|
||||
{
|
||||
var result = new VariousSportsProportion();
|
||||
|
||||
// 按月份分组
|
||||
var monthGroups = data
|
||||
.GroupBy(x => x.ScoreTime.Month)
|
||||
.OrderBy(g => g.Key); // 按月份排序
|
||||
|
||||
foreach (var g in monthGroups)
|
||||
{
|
||||
result.AxisX.Add($"{g.Key}月"); // 1月、2月...
|
||||
// 计算平均值,如果没有数据就填 0
|
||||
var avg = g.Any() ? (float)Math.Round(g.Average(x => x.Score), 2) : 0;
|
||||
result.AxisY.Add(avg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 大屏信息
|
||||
|
||||
/// <summary>
|
||||
@ -618,16 +956,16 @@ namespace VOL.Business.Services
|
||||
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.ScoreTime >= paramDto.StartTime && x.ScoreTime <= paramDto.EndTime);
|
||||
|
||||
// 运动时长
|
||||
schoolInfo.AccumulatedTrainDuration = sportsTestResults.Select(x => x.MotionDuration).Sum();
|
||||
//schoolInfo.AccumulatedTrainDuration = sportsTestResults.Select(x => x.MotionDuration).Sum();
|
||||
|
||||
var largeScreenTrainingDataModel = new List<LargeScreenTrainingDataModel>
|
||||
{
|
||||
await GeLargeScreenTrainingInfo(1, paramDto),
|
||||
await GeLargeScreenTrainingInfo(2, paramDto),
|
||||
await GeLargeScreenTrainingInfo(3, paramDto)
|
||||
};
|
||||
//var largeScreenTrainingDataModel = new List<LargeScreenTrainingDataModel>
|
||||
//{
|
||||
// await GeLargeScreenTrainingInfo(1, paramDto),
|
||||
// await GeLargeScreenTrainingInfo(2, paramDto),
|
||||
// await GeLargeScreenTrainingInfo(3, paramDto)
|
||||
//};
|
||||
|
||||
schoolInfo.LargeScreenTrainingDataModel = largeScreenTrainingDataModel;
|
||||
//schoolInfo.LargeScreenTrainingDataModel = largeScreenTrainingDataModel;
|
||||
|
||||
return schoolInfo;
|
||||
}
|
||||
|
@ -40,12 +40,12 @@ namespace VOL.Model.Norm.Response
|
||||
/// <summary>
|
||||
/// 累计训练时长
|
||||
/// </summary>
|
||||
public int AccumulatedTrainDuration { get; set; }
|
||||
//public int AccumulatedTrainDuration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 大屏训练数据
|
||||
/// </summary>
|
||||
public List<LargeScreenTrainingDataModel> LargeScreenTrainingDataModel { get; set; } = new List<LargeScreenTrainingDataModel> { };
|
||||
//public List<LargeScreenTrainingDataModel> LargeScreenTrainingDataModel { get; set; } = new List<LargeScreenTrainingDataModel> { };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
94
VOL.Model/Norm/Response/SmartPlaygroundModel.cs
Normal file
94
VOL.Model/Norm/Response/SmartPlaygroundModel.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VOL.Model.Norm.Response
|
||||
{
|
||||
/// <summary>
|
||||
/// 智慧操场
|
||||
/// </summary>
|
||||
public class SmartPlaygroundModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 学校信息
|
||||
/// </summary>
|
||||
public SchoolInfoModel SchoolInfo { get; set; } = new SchoolInfoModel();
|
||||
|
||||
/// <summary>
|
||||
/// 等级占比
|
||||
/// </summary>
|
||||
public List<RankStatsDto> RankStatsList { get; set; } = new List<RankStatsDto>();
|
||||
|
||||
/// <summary>
|
||||
/// 各项目成绩情况
|
||||
/// </summary>
|
||||
public Dictionary<string, ResultSituation> ResultSituationDic { get; set; } = new Dictionary<string, ResultSituation>();
|
||||
|
||||
/// <summary>
|
||||
/// 班级运动榜
|
||||
/// </summary>
|
||||
public List<ClassSportsRankingDto> ClassSportsRankList { get; set; } = new List<ClassSportsRankingDto>();
|
||||
|
||||
/// <summary>
|
||||
/// 年级优良率
|
||||
/// </summary>
|
||||
public Dictionary<string, GradeExcellentRate> GradeExcellentRateDic { get; set; } = new Dictionary<string, GradeExcellentRate>();
|
||||
}
|
||||
|
||||
public class ResultSituation
|
||||
{
|
||||
public int Vitality { get; set; }
|
||||
public List<TestSituationsModel> TestSituationsList { get; set; } = new List<TestSituationsModel>();
|
||||
|
||||
public Dictionary<string, VariousSportsProportion> AvgTestResultDic { get; set; } = new Dictionary<string, VariousSportsProportion>();
|
||||
|
||||
}
|
||||
|
||||
public class RankStatsDto : TestSituationsModel
|
||||
{
|
||||
public int MaleRate { get; set; }
|
||||
public int FemaleRate { get; set; }
|
||||
}
|
||||
|
||||
public class TestSituationsModel
|
||||
{
|
||||
public string Rank { get; set; }
|
||||
public int Count { get; set; }
|
||||
public int Rate { get; set; }
|
||||
public int MaleCount { get; set; }
|
||||
public int FemaleCount { get; set; }
|
||||
|
||||
public int ActivityLevel { get; set; }
|
||||
}
|
||||
public class ClassSportsRankingDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 排名
|
||||
/// </summary>
|
||||
public int Rank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 班级Id
|
||||
/// </summary>
|
||||
public int ClassId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 班级名称
|
||||
/// </summary>
|
||||
public string ClassName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 运动次数
|
||||
/// </summary>
|
||||
public int Count { get; set; }
|
||||
}
|
||||
|
||||
public class GradeExcellentRate
|
||||
{
|
||||
public int Rate { get; set; }
|
||||
public int MaleRate { get; set; }
|
||||
public int FemaleRate { get; set; }
|
||||
}
|
||||
}
|
@ -68,6 +68,7 @@ namespace VOL.Model.School.Response
|
||||
/// <summary>
|
||||
///类别枚举值
|
||||
/// </summary>
|
||||
//public SportsTestItemType CategoryValue { get; set; }
|
||||
public int CategoryValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -66,5 +66,15 @@ namespace VOL.WebApi.Controllers.Business
|
||||
{
|
||||
return await _sportsTestResultService.LargeScreenAverageClassExerciseIntensity(paramDto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 智慧操场
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet(nameof(SmartPlayground))]
|
||||
public async Task<SmartPlaygroundModel> SmartPlayground()
|
||||
{
|
||||
return await _sportsTestResultService.SmartPlayground();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user