252 lines
9.3 KiB
C#
252 lines
9.3 KiB
C#
|
||
using AutoMapper;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
|
||
using System.Drawing;
|
||
using System.Reflection.PortableExecutable;
|
||
using YD_AllHeartRates.Api.Context;
|
||
using YD_AllHeartRates.Api.Entitys;
|
||
using YD_AllHeartRates.Api.Services.Interface;
|
||
using YD_AllHeartRates.Api.SmartSportsEntitys;
|
||
using YD_AllHeartRates.Api.Utilities;
|
||
using YD_AllHeartRates.Commons.Dto.LargeScreen;
|
||
using YD_AllHeartRates.Commons.MemoryCaches;
|
||
|
||
namespace YD_AllHeartRates.Api.Services.Impl
|
||
{
|
||
/// <summary>
|
||
/// 服务实现
|
||
/// </summary>
|
||
public class LargeScreenService : ILargeScreenService
|
||
{
|
||
public SmartSportsContext _sportsContext;
|
||
public UserContext _userContext;
|
||
private readonly LoginContext _loginContext;
|
||
private string schoolCode;
|
||
private readonly ICaching _caching;
|
||
|
||
/// <summary>
|
||
/// 构造
|
||
/// </summary>
|
||
public LargeScreenService(SmartSportsContext sportsContext, UserContext userContext, LoginContext loginContext, ICaching caching)
|
||
{
|
||
_sportsContext = sportsContext;
|
||
_userContext = userContext;
|
||
_loginContext = loginContext;
|
||
_caching = caching;
|
||
|
||
|
||
schoolCode = _loginContext.SchoolCode;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取学校数据
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public async Task<SchoolDto> SchoolInfo()
|
||
{
|
||
var res = new SchoolDto();
|
||
|
||
res.SchoolCode = schoolCode;
|
||
res.Name = _loginContext.UserName;
|
||
res.FlushTime = Convert.ToInt32(AppSettings.FlushTime);
|
||
|
||
var gIds = await _sportsContext.SchoolAssocGrade.Where(x => x.SchoolCode == schoolCode).Select(x => x.GradeId).ToListAsync();
|
||
|
||
var grades = await (
|
||
from g in _sportsContext.Grade
|
||
join c in _sportsContext.Class on g.Id equals c.GradeId into classGroup
|
||
from c in classGroup.DefaultIfEmpty()
|
||
where gIds.Contains(g.Id) && c.SchoolCode == schoolCode
|
||
group c by new { g.Id, g.GradeName } into gradeGroup
|
||
select new Grades()
|
||
{
|
||
Id = gradeGroup.Key.Id,
|
||
Name = gradeGroup.Key.GradeName,
|
||
Class = gradeGroup.Where(c => c != null).Select(c => new Classes
|
||
{
|
||
Id = c.Id,
|
||
Name = c.ClassName
|
||
}).ToList()
|
||
}).ToListAsync();
|
||
|
||
res.Grade = grades;
|
||
|
||
var devices = await _sportsContext.Device.Where(x => x.SchoolCode == schoolCode).ToListAsync();
|
||
|
||
var heartRateDevices = devices.Where(x => x.DeviceType == 1).ToList();
|
||
var jumpingRopeDevices = devices.Where(x => x.DeviceType == 2).ToList();
|
||
|
||
res.HeartRateAllCount = heartRateDevices.Count();
|
||
res.JumpingRopeAllCount = jumpingRopeDevices.Count();
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据班级Id获取学生列表
|
||
/// </summary>
|
||
/// <param name="classId"></param>
|
||
/// <returns></returns>
|
||
public async Task<List<StudentDto>> StudentList(int classId)
|
||
{
|
||
var res = await _sportsContext.Student.Where(x => x.SchoolCode == schoolCode && x.ClassId == classId && x.StudentStatus == 1).Select(x => new StudentDto
|
||
{
|
||
StudentNo = x.StudentNo,
|
||
StudentName = x.StudentName,
|
||
Photo = x.Photo ?? "",
|
||
Sex = x.Sex
|
||
}).ToListAsync();
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 心率数据
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public async Task<HeartRateDataDto> HeartRateData(int classId)
|
||
{
|
||
var res = new HeartRateDataDto();
|
||
|
||
var now = DateTime.Now;
|
||
var tenMinutesAgo = now.AddMinutes(-1);
|
||
|
||
// 在线心率设备
|
||
int onlineHeartRateCount = RedisHelper.Keys("heartRate:*").Length;
|
||
res.HeartRateOnlineCount = onlineHeartRateCount;
|
||
|
||
// 在线跳绳设备
|
||
int onlineJumpRopeCount = RedisHelper.Keys("jumpRope:raw:*").Length;
|
||
res.JumpingRopeOnLineCount = onlineJumpRopeCount;
|
||
|
||
// 1. 构建缓存 key
|
||
string studentListKey = $"students:{schoolCode}:{classId}";
|
||
|
||
// 2. 尝试从缓存获取
|
||
var studentList = _caching.Get<List<StudentDto>>(studentListKey);
|
||
|
||
// 3. 如果缓存没有 → 查询数据库 + 写入缓存
|
||
if (studentList == null || studentList.Count == 0)
|
||
{
|
||
studentList = await _sportsContext.Student
|
||
.Where(x => x.ClassId == classId && x.SchoolCode == schoolCode && x.StudentStatus == 1)
|
||
.Select(x => new StudentDto
|
||
{
|
||
StudentNo = x.StudentNo,
|
||
StudentName = x.StudentName,
|
||
Sex = x.Sex,
|
||
Photo = x.Photo ?? ""
|
||
})
|
||
.ToListAsync();
|
||
|
||
_caching.AddObject(studentListKey, studentList, 60); // 缓存 8 小时
|
||
}
|
||
|
||
int warmUp = 0, low = 0, medium = 0, high = 0, warning = 0;
|
||
|
||
|
||
DateTime today = DateTime.Today;
|
||
|
||
// 获取所有学号
|
||
var studentNos = studentList.Select(s => s.StudentNo).ToList();
|
||
|
||
// 一次性获取 JumpRopeData(当天数据)
|
||
var jumpRopeDict = await _userContext.JumpRopeData
|
||
.Where(x => studentNos.Contains(x.StudentNo) && x.ScoreTime.Date == today)
|
||
.GroupBy(x => x.StudentNo)
|
||
.Select(g => g.OrderByDescending(x => x.JumpValue).FirstOrDefault())
|
||
.ToDictionaryAsync(x => x.StudentNo, x => x);
|
||
|
||
foreach (var student in studentList)
|
||
{
|
||
var heartRateKey = $"heartRate:{student.StudentNo}";
|
||
//var jumpRopeKey = $"jumpRope:{student.StudentNo}";
|
||
//string jumpRopeKey = $"{student.StudentNo}_{DateTime.Now:yyyyMMdd}";
|
||
|
||
var jumpRopeKey = $"jumpRope:active:{student.StudentNo}:{DateTime.Now:yyyyMMdd}";
|
||
|
||
// 先从缓存拿
|
||
var heartRate = _caching.Get<HeartRateData>(heartRateKey);
|
||
|
||
var jumpRope = _caching.Get<JumpRopeData>(jumpRopeKey);
|
||
|
||
if (jumpRope == null && jumpRopeDict.TryGetValue(student.StudentNo, out var jr))
|
||
jumpRope = jr;
|
||
|
||
// ❗心率缓存未命中 → 单独查数据库
|
||
//if (heartRate == null)
|
||
//{
|
||
// heartRate = await _userContext.HeartRateData
|
||
// .Where(x => x.StudentNo == student.StudentNo && x.ScoreTime >= tenMinutesAgo)
|
||
// .OrderByDescending(x => x.ScoreTime)
|
||
// .FirstOrDefaultAsync();
|
||
|
||
// //if (heartRate != null)
|
||
// // _caching.AddObject(heartRateKey, heartRate, 60);
|
||
//}
|
||
|
||
// ❗跳绳缓存未命中 → 单独查数据库
|
||
//if (jumpRope == null)
|
||
//{
|
||
// jumpRope = await _userContext.JumpRopeData
|
||
// .Where(x => x.StudentNo == student.StudentNo && x.ScoreTime.Date == now.Date)
|
||
// .OrderByDescending(x => x.ScoreTime)
|
||
// .FirstOrDefaultAsync();
|
||
|
||
// if (jumpRope != null)
|
||
// _caching.AddObject(jumpRopeKey, jumpRope, 60);
|
||
//}
|
||
|
||
// 心率强度判断
|
||
int strength = heartRate?.Strength ?? 0;
|
||
|
||
switch (strength)
|
||
{
|
||
case > 0 and < 50:
|
||
warmUp++;
|
||
break;
|
||
case >= 50 and < 60:
|
||
low++;
|
||
break;
|
||
case >= 60 and < 70:
|
||
medium++;
|
||
break;
|
||
case >= 70 and < 85:
|
||
high++;
|
||
break;
|
||
case >= 85:
|
||
warning++;
|
||
break;
|
||
}
|
||
|
||
res.StudentList.Add(new StudentDto
|
||
{
|
||
StudentName = student.StudentName,
|
||
StudentNo = student.StudentNo,
|
||
Photo = student.Photo ?? "",
|
||
Sex = student.Sex,
|
||
HeartRate = heartRate?.Value ?? 0,
|
||
JumpingRope = jumpRope?.JumpValue ?? 0,
|
||
Strength = strength,
|
||
HeartRateQuantityOfElectricity = heartRate?.QuantityOfElectricity ?? 0,
|
||
JumpingRopeQuantityOfElectricity = jumpRope?.QuantityOfElectricity ?? 0
|
||
});
|
||
}
|
||
|
||
int total = RedisHelper.Keys("heartRate:*").Length;
|
||
|
||
int CalcPercentage(int count) =>
|
||
total == 0 ? 0 : (int)Math.Round(count * 100.0 / total);
|
||
|
||
res.WarmUp = CalcPercentage(warmUp);
|
||
res.Low = CalcPercentage(low);
|
||
res.Medium = CalcPercentage(medium);
|
||
res.High = CalcPercentage(high);
|
||
res.Warning = CalcPercentage(warning);
|
||
|
||
return res;
|
||
}
|
||
}
|
||
}
|