552 lines
21 KiB
C#
Raw Normal View History

2025-06-06 14:57:20 +08:00

using System;
using System.Threading.Tasks;
using AutoMapper;
2025-06-11 11:45:53 +08:00
using CSRedis;
2025-06-06 14:57:20 +08:00
using Microsoft.EntityFrameworkCore;
using YD_WeChatApplet.Api.SmartSportsEntitys;
using YD_WeChatApplet.Api.Utilities;
2025-06-11 11:45:53 +08:00
using YD_WeChatApplet.Commons.Dto;
using YD_WeChatApplet.Commons.Dto.ClassRoomRecord;
2025-06-06 14:57:20 +08:00
using YD_WeChatApplet.Commons.Dto.HomeWork;
using YD_WeChatApplet.Commons.Dto.SportsTest;
using YD_WeChatApplet.Commons.Dto.Teacher;
using YD_WeChatApplet.Context;
namespace YD_WeChatApplet.Services
{
public class TeacherService : ITeacherService
{
public UserContext _userContext;
public SmartSportsContext _sportsContext;
private readonly IMapper _mapper;
public TeacherService(UserContext userContext, SmartSportsContext sportsContext, IMapper mapper)
{
_userContext = userContext;
_sportsContext = sportsContext;
_mapper = mapper;
}
/// <summary>
/// 老师个人信息
/// </summary>
/// <returns></returns>
public async Task<TeacherProfileDto> TeacherProfile()
{
var userId = UserLoginContext.Current.UserId;
var res = await _userContext.Users.Where(x => x.User_Id == userId).Select(x => new TeacherProfileDto()
{
UserTrueName = x.UserTrueName,
BirthDate = x.BirthDate,
Gender = x.Gender,
HeadImageUrl = x.HeadImageUrl,
Height = x.Height,
Weight = x.Weight
}).FirstOrDefaultAsync();
return res;
}
/// <summary>
/// 修改个人信息
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
public async Task ModifyTeacherProfile(TeacherProfileDto paramDto)
{
var userId = UserLoginContext.Current.UserId;
var model = await _userContext.Users.FirstOrDefaultAsync(x => x.User_Id == userId);
if (model == null)
throw new Exception("更新数据为空");
model.UserTrueName = !string.IsNullOrWhiteSpace(paramDto.UserTrueName) ? paramDto.UserTrueName : model.UserTrueName;
model.HeadImageUrl = !string.IsNullOrWhiteSpace(paramDto.HeadImageUrl) ? paramDto.HeadImageUrl : model.HeadImageUrl;
model.BirthDate = paramDto.BirthDate ?? model.BirthDate;
model.Gender = paramDto.Gender ?? model.Gender;
model.Height = paramDto.Height ?? model.Height;
model.Weight = paramDto.Weight ?? model.Weight;
if (_userContext.Entry(model).State == EntityState.Modified)
{
await _userContext.SaveChangesAsync();
}
}
/// <summary>
/// 修改密码
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
public async Task ModifyTeacherPwd(ModifyTeacherPwdDto paramDto)
{
if (paramDto.NewPwd != paramDto.ConfirmPwd)
throw new Exception("确认密码与新密码不一致");
var userId = UserLoginContext.Current.UserId;
var model = await _userContext.Users.FirstOrDefaultAsync(x => x.User_Id == userId && x.UserPwd == paramDto.OldPwd);
if (model == null)
throw new Exception("旧密码输入有误");
model.UserPwd = paramDto.NewPwd;
if (_userContext.Entry(model).State == EntityState.Modified)
{
_userContext.Update(model);
await _userContext.SaveChangesAsync();
}
}
/// <summary>
/// 项目列表
/// </summary>
/// <returns></returns>
public async Task<List<ComboBoxDto>> CategoryList(int gradeId)
{
var res = await (
from g in _sportsContext.GradeAssocCategory
join s in _sportsContext.SportsTestCategory on g.CategoryValue equals s.CategoryValue
where g.GradeId == gradeId
select new ComboBoxDto
{
Id = s.CategoryValue,
Name = s.CategoryName
}).ToListAsync();
return res;
}
/// <summary>
/// 数据统计接口
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<DataStatisticsDto> DataStatistics(DataStatisticsFilterDto dto)
{
var res = new DataStatisticsDto();
var schoolCode = UserLoginContext.Current.SchoolCode;
var teacherId = await _sportsContext.Teacher.Where(x => x.TeacherPhoneNo == UserLoginContext.Current.PhoneNo).Select(x => x.Id).FirstOrDefaultAsync();
if (teacherId == 0)
return res;
var students = await (from a in _sportsContext.ClassAssocTeacher
join s in _sportsContext.Student on a.ClassId equals s.ClassId
where a.TeacherId == teacherId
&& s.SchoolCode == schoolCode
select new { s.StudentNo, s.Photo }).Distinct().ToListAsync();
res.HeadTotal = students.Count;
var currentDate = DateTime.Now;
var startOfMonth = new DateTime(currentDate.Year, currentDate.Month, 6);
var endOfMonth = startOfMonth.AddMonths(1).AddDays(-1);
// 构建基础查询
//IQueryable<N_SportsTestValue> iotQuery = _sportsContext.SportsTestValue
// .Where(x => x.IsDisplay && x.SchoolCode == schoolCode && x.ScoreTime >= startOfMonth && x.ScoreTime <= endOfMonth);
//IQueryable<Ai_SportsTestData> aiQuery = _sportsContext.SportsTestData
// .Where(x => x.IsDisplay && x.SchoolCode == schoolCode && x.ScoreTime >= startOfMonth && x.ScoreTime <= endOfMonth);
IQueryable<N_SportsTestValue> iotQuery = _sportsContext.SportsTestValue.Where(x => x.IsDisplay && x.SchoolCode == schoolCode);
//IQueryable<Ai_SportsTestData> aiQuery = _sportsContext.SportsTestData.Where(x => x.IsDisplay && x.SchoolCode == schoolCode);
// 动态追加筛选条件
if (dto.ClassId > 0)
{
iotQuery = iotQuery.Where(x => x.ClassId == dto.ClassId);
//aiQuery = aiQuery.Where(x => x.ClassId == dto.ClassId);
}
if (dto.CategoryValue > 0)
{
iotQuery = iotQuery.Where(x => x.CategoryValue == dto.CategoryValue);
//aiQuery = aiQuery.Where(x => x.CategoryValue == dto.CategoryValue);
}
//if (!string.IsNullOrWhiteSpace(dto.Rank))
//{
// iotQuery = iotQuery.Where(x => x.Rank == dto.Rank);
// aiQuery = aiQuery.Where(x => x.Rank == dto.Rank);
//}
// 并行执行查询
var iotTask = await iotQuery.ToListAsync();
//var aiTask = await aiQuery.ToListAsync();
// 映射并合并结果
//var sportsTestResults = _mapper.Map<List<SportsTestValueModel>>(iotTask)
// .Concat(_mapper.Map<List<SportsTestValueModel>>(aiTask))
// .ToList();
var sportsTestResults = _mapper.Map<List<SportsTestValueModel>>(iotTask);
sportsTestResults = sportsTestResults
.GroupBy(x => new { x.StudentNo })
.Select(g =>
{
var latestRecord = g.OrderByDescending(x => x.Score).First();
//var latestRecord = g.Where(x => x.ScoreTime >= startOfMonth && x.ScoreTime <= endOfMonth).OrderByDescending(x => x.Score).First();
//latestRecord.Score = g.Max(x => x.Score);
//latestRecord.Value = g.Max(x => x.Value);
return latestRecord;
}).ToList();
if (!string.IsNullOrWhiteSpace(dto.Rank))
{
sportsTestResults = sportsTestResults.Where(x => x.Rank == dto.Rank).ToList();
}
res.RankDic.Add("优秀", sportsTestResults.Count(x => x.Rank == "优秀"));
res.RankDic.Add("良好", sportsTestResults.Count(x => x.Rank == "良好"));
res.RankDic.Add("及格", sportsTestResults.Count(x => x.Rank == "及格"));
res.RankDic.Add("不及格", sportsTestResults.Count(x => x.Rank == "不及格"));
res.Studentlist = new Commons.Dto.PageDataDto<StatisticsStudent>()
{
Total = sportsTestResults.Count,
Datas = sportsTestResults.Skip((dto.PageIndex - 1) * dto.PageSize).Take(dto.PageSize).Select(x => new StatisticsStudent()
{
StudentNo = x.StudentNo,
StudentName = x.StudentName,
Sex = x.Sex,
Photo = students.FirstOrDefault(x => x.StudentNo == x.StudentNo)?.Photo ?? "",
}).ToList()
};
return res;
}
/// <summary>
/// 统计数据详情
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<DataStatisticsDetailsDto> DataStatisticsDetails(DataStatisticsDetailsFilterDto dto)
{
var res = new DataStatisticsDetailsDto();
var student = await _sportsContext.Student.Where(x => x.StudentNo == dto.StudentNo).FirstOrDefaultAsync();
var classInfo = await _sportsContext.Class.FirstOrDefaultAsync(x => x.Id == dto.ClassId);
var categorys = await (
from g in _sportsContext.GradeAssocCategory
join s in _sportsContext.SportsTestCategory on g.CategoryValue equals s.CategoryValue
where g.GradeId == classInfo.GradeId
select new
{
s.Id,
s.CategoryValue,
s.CategoryName,
g.Weight
}).ToListAsync();
if (student == null || categorys == null)
return res;
var iotQuery = await _sportsContext.SportsTestValue.Where(x => x.IsDisplay && x.SchoolCode == student.SchoolCode && x.StudentNo == dto.StudentNo).Select(x => new SportsTestValueModel()
{
StudentNo = x.StudentNo,
Value = x.Value,
Score = x.Score,
AdditionalScore = x.AdditionalScore,
CategoryValue = x.CategoryValue,
Rank = x.Rank
}).ToListAsync();
var aiQuery = await _sportsContext.SportsTestData.Where(x => x.IsDisplay && x.SchoolCode == student.SchoolCode && x.StudentNo == dto.StudentNo).Select(x => new SportsTestValueModel()
{
StudentNo = x.StudentNo,
Value = (float)x.Value,
Score = x.Score,
AdditionalScore = x.AdditionalScore,
CategoryValue = x.CategoryValue,
Rank = x.Rank
}).ToListAsync();
var sportsTestResults = iotQuery.Concat(aiQuery).ToList();
res.StudentNo = student.StudentNo;
res.StudentName = student.StudentName;
res.Sex = student.Sex == 1 ? "男" : "女";
res.Age = student.Age;
res.Photo = student.Photo;
res.CategoryScoreList = new List<CategoryScore>();
double totalScore = 0;
foreach (var item in categorys)
{
var maxResult = sportsTestResults.Where(x => x.CategoryValue == item.Id).OrderByDescending(x => x.Value).FirstOrDefault();
res.CategoryScoreList.Add(new CategoryScore()
{
CategoryName = item.CategoryName,
Value = maxResult != null ? Math.Round((double)maxResult.Value, 0) : 0,
Score = maxResult?.Score ?? 0,
Rank = maxResult?.Rank ?? ""
});
double currentScore = maxResult?.Score ?? 0;
double currentAdditionalScore = maxResult?.AdditionalScore ?? 0;
// 累积分数
totalScore += ((currentScore + currentAdditionalScore) * item.Weight);
}
res.ComprehensiveScore = totalScore.ToString("F0");
return res;
}
2025-06-11 11:45:53 +08:00
/// <summary>
/// 课堂记录
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
public async Task<PageDataDto<ClassRoomRecordPageDto>> ClassRoomRecord(ClassRoomRecordDto dto)
{
var res = new PageDataDto<ClassRoomRecordPageDto>();
if (string.IsNullOrWhiteSpace(dto.StudentNo))
{
var phoneNo = UserLoginContext.Current.PhoneNo;
var teacherId = await _sportsContext.Teacher.Where(x => x.TeacherPhoneNo == phoneNo).Select(x => x.Id).FirstOrDefaultAsync();
var query = from td in _sportsContext.Ai_ClassRoomRecord
where td.TeacherId == teacherId
select new ClassRoomRecordPageDto()
{
Id = td.Id,
ClassId = td.ClassId,
Name = td.Name,
StartingEndingTime = $"{(td.StartTime.HasValue ? td.StartTime.Value.ToString("yyyy-MM-dd HH:mm") : string.Empty)}{(td.EndTime.HasValue ? " - " + td.EndTime.Value.ToString("yyyy-MM-dd HH:mm") : string.Empty)}"
};
res.Total = await query.CountAsync();
var list = await query
.OrderByDescending(c => c.Id)
.Skip((dto.PageIndex - 1) * dto.PageSize)
.Take(dto.PageSize)
.ToListAsync();
res.Datas = list;
}
else
{
var query = from s in _sportsContext.Ai_ClassroomStudentRecord
join c in _sportsContext.Ai_ClassRoomRecord on s.ClassRoomRecordId equals c.Id
where s.StudentName == dto.StudentNo
select new ClassRoomRecordPageDto()
{
Id = c.Id,
ClassId = c.ClassId,
Name = c.Name,
StartingEndingTime = $"{(c.StartTime.HasValue ? c.StartTime.Value.ToString("yyyy-MM-dd HH:mm") : string.Empty)}{(c.EndTime.HasValue ? " - " + c.EndTime.Value.ToString("yyyy-MM-dd HH:mm") : string.Empty)}"
};
res.Total = await query.CountAsync();
var list = await query
.OrderByDescending(c => c.Id)
.Skip((dto.PageIndex - 1) * dto.PageSize)
.Take(dto.PageSize)
.ToListAsync();
res.Datas = list;
}
return res;
}
/// <summary>
/// 课堂详情
/// </summary>
/// <param name="classRoomId"></param>
/// <returns></returns>
public async Task<ClassReportDetailsDto> ClassRoomReportDetails(int classRoomId)
{
var res = new ClassReportDetailsDto();
var query = from hrd in _sportsContext.Ai_HeartRateData
where hrd.ClassRoomRecordId == classRoomId
select hrd;
var heartRateDataList = await query.ToListAsync();
if (heartRateDataList.Count == 0)
return res;
var classRoom = await _sportsContext.Ai_ClassRoomRecord.Include(x => x.ClassroomStudentRecord)
.Where(x => x.Id == classRoomId)
.FirstAsync();
var classRoomStudent = await _sportsContext.Ai_ClassroomStudentRecord
.Where(x => x.ClassRoomRecordId == classRoomId)
.ToListAsync();
res.MaxHR = (int)heartRateDataList.Max(x => x.Value);
res.MinHR = (int)heartRateDataList.Min(x => x.Value);
res.AvgHR = (int)heartRateDataList.Average(x => x.Value);
res.HighIntensity = heartRateDataList.Where(x => x.Strength > 50).Sum(x => x.MotionDuration);
var studentTrainingRecordList = classRoom.ClassroomStudentRecord.ToList();
List<StudentTrainingRecordDto> studentList = new List<StudentTrainingRecordDto>();
2025-06-11 16:56:51 +08:00
var studentIds = studentTrainingRecordList.Select(x => x.StudentNo).ToList();
var students = await _sportsContext.Student.Where(x => studentIds.Contains(x.StudentNo)).Select(x => new
{
x.StudentNo,
x.StudentName,
x.Age,
x.Sex,
x.Photo
}).ToListAsync();
2025-06-11 11:45:53 +08:00
foreach (var item in studentTrainingRecordList)
{
2025-06-11 16:56:51 +08:00
//var studentTrainingData = heartRateDataList.Where(x => x.StudentNo == item.StudentNo).ToList();
var stu = students.FirstOrDefault(x => x.StudentNo == item.StudentNo);
2025-06-11 11:45:53 +08:00
2025-06-11 16:56:51 +08:00
var student = new StudentTrainingRecordDto()
2025-06-11 11:45:53 +08:00
{
2025-06-11 16:56:51 +08:00
StudentNo = stu?.StudentNo,
Age = stu?.Age ?? item.Age,
Sex = stu?.Sex ?? item.Sex
};
2025-06-11 11:45:53 +08:00
2025-06-11 16:56:51 +08:00
student.StudentName = stu?.StudentName;
student.Photo = stu?.Photo ?? "";
2025-06-11 11:45:53 +08:00
2025-06-11 16:56:51 +08:00
studentList.Add(student);
2025-06-11 11:45:53 +08:00
}
res.HeartRateTrend = GetHeartRateTrend(heartRateDataList);
res.StudentTrainingRecordList = studentList;
return res;
}
/// <summary>
/// 学员报告
/// </summary>
2025-06-11 13:29:26 +08:00
/// <param name="classRoomId"></param>
2025-06-11 11:45:53 +08:00
/// <param name="studentNo"></param>
/// <returns></returns>
public async Task<StudentClassRoomReportDto> StudentClassRoomReport(int classRoomId, string studentNo)
{
var res = new StudentClassRoomReportDto();
var query = from hrd in _sportsContext.Ai_HeartRateData
where hrd.ClassRoomRecordId == classRoomId &&
hrd.StudentNo == studentNo
select hrd;
var heartRateDataList = await query.ToListAsync();
if (heartRateDataList.Count == 0)
return res;
var student = heartRateDataList[0];
res.MaxHR = (int)heartRateDataList.Max(x => x.Value);
res.MinHR = (int)heartRateDataList.Min(x => x.Value);
res.AvgHR = (int)heartRateDataList.Average(x => x.Value);
res.HighIntensity = heartRateDataList.Where(x => x.Strength > 50).Sum(x => x.MotionDuration);
var baseTime = await _sportsContext.Ai_HeartRateData.Where(x => x.ClassRoomRecordId == classRoomId).MinAsync(x => x.ScoreTime);
var heartRateWithMinutes = heartRateDataList
.Select(data => new
{
Data = data,
MinuteBucket = (int)(data.ScoreTime - baseTime).TotalMinutes
})
.ToList();
var maxMinute = heartRateWithMinutes.Max(x => x.MinuteBucket);
for (int minute = 0; minute <= maxMinute; minute++)
{
var minuteData = heartRateWithMinutes
.Where(x => x.MinuteBucket == minute)
.Select(x => x.Data)
.ToList();
if (minuteData.Any())
{
res.HeartRateTrend.AxisX.Add($"{minute + 1} 分钟");
res.HeartRateTrend.AxisY.Add((int)minuteData.Average(x => x.Value));
}
}
return res;
}
/// <summary>
/// 心率变化趋势
/// </summary>
/// <param name="heartRateDataList"></param>
/// <returns></returns>
public ChartDataDto GetHeartRateTrend(List<Ai_HeartRateData> heartRateDataList)
{
var result = new ChartDataDto();
if (heartRateDataList == null || !heartRateDataList.Any())
return result;
var baseTime = heartRateDataList.Min(x => x.ScoreTime);
var heartRateWithMinutes = heartRateDataList
.Select(data => new
{
Data = data,
MinuteBucket = (int)(data.ScoreTime - baseTime).TotalMinutes
})
.ToList();
var maxMinute = heartRateWithMinutes.Max(x => x.MinuteBucket);
for (int minute = 0; minute <= maxMinute; minute++)
{
var minuteData = heartRateWithMinutes
.Where(x => x.MinuteBucket == minute)
.Select(x => x.Data)
.ToList();
if (minuteData.Any())
{
result.AxisX.Add($"{minute + 1} 分钟");
result.AxisY.Add((int)minuteData.Average(x => x.Value));
}
}
return result;
}
2025-06-06 14:57:20 +08:00
}
}