2025-07-29 17:07:55 +08:00

252 lines
9.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}
}