296 lines
9.2 KiB
C#
Raw Normal View History

2026-03-16 10:33:46 +08:00
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
2025-12-08 09:11:05 +08:00
using System;
2025-12-31 14:07:16 +08:00
using YD_AllHeartRates.Api.Context;
using YD_AllHeartRates.Api.Entitys;
2025-11-24 09:11:20 +08:00
using YD_AllHeartRates.Api.Services.Interface;
2025-12-31 14:07:16 +08:00
using YD_AllHeartRates.Api.Utilities;
2025-11-24 09:11:20 +08:00
using YD_AllHeartRates.Commons.Dto.DataPush;
2025-12-08 09:11:05 +08:00
using YD_AllHeartRates.Commons.MemoryCaches;
using YD_AllHeartRates.Commons.Utils;
2025-11-24 09:11:20 +08:00
namespace YD_AllHeartRates.Api.Middlewares
{
public class SportsRoutineReportJob : IHostedService, IDisposable
{
private readonly IDataPushService _dataPushService;
private Timer _timer;
2025-12-08 09:11:05 +08:00
private readonly ICaching _caching;
2025-12-31 14:07:16 +08:00
public UserContext _userContext;
2025-12-08 09:11:05 +08:00
2025-11-24 09:11:20 +08:00
private static string[] ChangXing = new string[]
{
"曹贺淳",
"陈思禹",
"陈朱海",
"代宇若",
"丁淑雅",
"董静思",
"樊玉顺",
"方欣玥",
"宫恩佑",
"郭依诺",
2026-03-16 10:33:46 +08:00
//"黄子熙",
//"计永安",
//"蒋圣煊",
//"李锦娴",
//"李语汐",
//"李梓皓",
//"刘家耀",
//"龙正柏瑀",
//"罗昕",
//"聂新淼",
//"彭禹凡",
//"宋皓晨",
//"孙海翔",
//"唐瀚宇",
//"陶柔紫若",
//"万欣怡",
//"王心语",
//"王梓皓",
//"王梓煜",
//"徐子琪",
//"许穆晨",
//"杨温馨",
//"杨子墨",
//"袁洛霏",
//"张宸溪",
//"张羽曦",
//"赵昊辰",
//"周舒洋"
2025-11-24 09:11:20 +08:00
};
private static string[] ZhengDa = new string[]
{
"沈懿轩",
"周宇飛",
"范昊瑜",
"张翼成",
"卫宇航",
"董书涵",
"吴彦君",
"朱灏辰",
"王叡之",
"施梓俊",
2026-03-16 10:33:46 +08:00
//"龚怡豪",
//"张子赫",
//"仇泽宇",
//"陈歆蕾",
//"朱旖文",
//"郭笑笑",
//"陈瑾萱",
//"蔡乐妮",
//"侯熙琰",
//"龚思涵",
//"朱瑾萱",
//"宋依涵",
//"顾渝尧",
//"张赛文",
//"沈美夕",
//"吴佳凤",
//"蒋添依",
//"茅苹苹",
//"李腾宇",
//"林少熙",
//"史梓晨",
//"丁文洁",
//"董利妍",
//"朱紫芸"
2025-11-24 09:11:20 +08:00
};
2025-12-31 14:07:16 +08:00
private readonly List<StudentCacheInfo> _students = new();
2025-11-24 09:11:20 +08:00
2025-12-31 14:07:16 +08:00
public SportsRoutineReportJob(IDataPushService dataPushService, UserContext userContext, ICaching caching)
2025-11-24 09:11:20 +08:00
{
_dataPushService = dataPushService;
2025-12-31 14:07:16 +08:00
_userContext = userContext;
2025-12-08 09:11:05 +08:00
_caching = caching;
2025-12-31 14:07:16 +08:00
// Redis 中缓存键
const string redisKey = "StudentEduInfos";
// 1. 尝试从 Redis 获取缓存
var cachedList = _caching.Get<List<StudentCacheInfo>>(redisKey);
if (cachedList != null && cachedList.Count > 0)
2025-12-08 09:11:05 +08:00
{
2025-12-31 14:07:16 +08:00
_students = cachedList;
Console.WriteLine("从 Redis 加载学生信息完成。");
return;
2025-12-08 09:11:05 +08:00
}
2025-11-24 09:11:20 +08:00
2025-12-31 14:07:16 +08:00
// 2. 缓存不存在 → 调用接口获取
var result = new List<StudentCacheInfo>();
2025-12-08 09:11:05 +08:00
// 正大中学
2025-11-24 09:11:20 +08:00
foreach (var name in ZhengDa)
{
2025-12-08 09:11:05 +08:00
var student = _dataPushService
.GetStudentEduId("上海市崇明区正大中学", "七年级", "5班", name, "")
2025-12-31 14:07:16 +08:00
.Result?
2025-12-08 09:11:05 +08:00
.FirstOrDefault();
2025-11-24 09:11:20 +08:00
if (student != null)
{
2025-12-31 14:07:16 +08:00
result.Add(new StudentCacheInfo
{
School = "上海市崇明区正大中学",
Grade = "七年级",
ClassName = "5班",
Name = name,
EduId = student.EduId
});
2025-12-08 09:11:05 +08:00
Console.WriteLine($"正大中学:[{DateTime.Now}] {name}: {student.EduId}");
2025-11-24 09:11:20 +08:00
}
}
2025-12-08 09:11:05 +08:00
// 长兴小学
2025-11-24 09:11:20 +08:00
foreach (var name in ChangXing)
{
2025-12-08 09:11:05 +08:00
var student = _dataPushService
.GetStudentEduId("上海市崇明区长兴小学", "二年级", "二年级2班", name, "")
2025-12-31 14:07:16 +08:00
.Result?
2025-12-08 09:11:05 +08:00
.FirstOrDefault();
2025-11-24 09:11:20 +08:00
if (student != null)
{
2025-12-31 14:07:16 +08:00
result.Add(new StudentCacheInfo
{
School = "上海市崇明区长兴小学",
Grade = "二年级",
ClassName = "二年级2班",
Name = name,
EduId = student.EduId
});
2025-12-08 09:11:05 +08:00
Console.WriteLine($"长兴小学:[{DateTime.Now}] {name}: {student.EduId}");
2025-11-24 09:11:20 +08:00
}
}
2025-12-08 09:11:05 +08:00
2025-12-31 14:07:16 +08:00
// 写入 Redis(直接存对象,不再存 json 字符串)
_caching.AddObject(redisKey, result);
_students = result;
Console.WriteLine("学生信息已缓存到 Redis。");
2025-11-24 09:11:20 +08:00
}
public Task StartAsync(CancellationToken cancellationToken)
2026-03-16 10:33:46 +08:00
{
2025-11-24 09:11:20 +08:00
// 每分钟检查一次时间,看是否在8-16点并整点执行
_timer = new Timer(async _ => await DoWork(), null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
return Task.CompletedTask;
}
private async Task DoWork()
{
var now = DateTime.Now;
2026-03-16 10:33:46 +08:00
// 每天 8:30 ~ 18:30 每小时30分执行
if (now.Hour < 8 || now.Hour > 18 || now.Minute != 23)
return;
var startTime = now.AddHours(-1);
var endTime = now;
2025-12-31 14:07:16 +08:00
2026-03-16 10:33:46 +08:00
Console.WriteLine($"[{now}] 开始统计心率数据 {startTime} ~ {endTime}");
try
2025-11-24 09:11:20 +08:00
{
2026-03-16 10:33:46 +08:00
// 1 查询1小时心率数据,并按分钟计算平均值
var list = await _userContext.HeartRateData
.Where(x => x.SchoolCode == AppSettings.SchoolCode && x.ScoreTime >= startTime && x.ScoreTime <= endTime)
.GroupBy(x => new
{
x.StudentNo,
Minute = new DateTime(
x.ScoreTime.Year,
x.ScoreTime.Month,
x.ScoreTime.Day,
x.ScoreTime.Hour,
x.ScoreTime.Minute,
0)
})
.Select(g => new
{
g.Key.StudentNo,
Minute = g.Key.Minute,
AvgValue = g.Average(x => x.Value),
AvgInstant = g.Average(x => x.InstantValue)
})
.ToListAsync();
// 2 按学生分组(提高查找效率)
var groups = list
.GroupBy(x => x.StudentNo)
.ToDictionary(
x => x.Key,
x => x.OrderBy(t => t.Minute).ToList()
);
2025-11-24 09:11:20 +08:00
var data = new List<StudentData>();
2026-03-16 10:33:46 +08:00
// 3 生成推送数据
2025-12-31 14:07:16 +08:00
for (int i = 0; i < _students.Count; i++)
2025-11-24 09:11:20 +08:00
{
2026-03-16 10:33:46 +08:00
var stu = _students[i];
2025-11-24 09:11:20 +08:00
2026-03-16 10:33:46 +08:00
if (!groups.TryGetValue(stu.EduId, out var stuData))
continue;
2025-11-24 09:11:20 +08:00
2026-03-16 10:33:46 +08:00
var hdsjList = stuData.Select(x => new HeartRateRecordDto
2025-11-24 09:11:20 +08:00
{
2026-03-16 10:33:46 +08:00
SJSJ = x.Minute.ToString("yyyy-MM-dd HH:mm:ss"),
XL = (int)Math.Round(x.AvgValue),
JXXL = (int)Math.Round(x.AvgInstant)
}).ToList();
// 保证每个学生60条数据
if (hdsjList.Count == 0)
continue;
2025-11-24 09:11:20 +08:00
var student = new StudentData
{
SBID = (i + 1).ToString("D2"),
2025-12-31 14:07:16 +08:00
XSEDUID = stu.EduId,
2025-11-24 09:11:20 +08:00
HDSJ = hdsjList
};
data.Add(student);
2025-12-31 14:07:16 +08:00
Console.WriteLine(
2026-03-16 10:33:46 +08:00
$"生成数据 → {stu.School}-{stu.Grade}-{stu.ClassName}-{stu.Name} | EduId:{stu.EduId} | {hdsjList.Count}条");
2025-11-24 09:11:20 +08:00
}
2026-03-16 10:33:46 +08:00
// 4 推送数据
if (data.Count > 0)
2025-11-24 09:11:20 +08:00
{
2025-12-08 09:11:05 +08:00
var res = await _dataPushService.SportsRoutineReport(data);
2025-12-31 14:07:16 +08:00
2026-03-16 10:33:46 +08:00
Console.WriteLine(
$"[{DateTime.Now}] HeartRate job code:{res?.code} msg:{res?.msg} 学生数:{data.Count}");
2025-12-31 14:07:16 +08:00
}
2026-03-16 10:33:46 +08:00
else
2025-12-31 14:07:16 +08:00
{
2026-03-16 10:33:46 +08:00
Console.WriteLine($"[{DateTime.Now}] 无心率数据需要推送");
2025-12-31 14:07:16 +08:00
}
2025-11-24 09:11:20 +08:00
}
2026-03-16 10:33:46 +08:00
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now}] HeartRate job error:{ex.Message}");
}
2025-11-24 09:11:20 +08:00
}
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
}