541 lines
21 KiB
C#
541 lines
21 KiB
C#
|
|
using System;
|
|
using System.Threading.Tasks;
|
|
using AutoMapper;
|
|
using CSRedis;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using YD_WeChatApplet.Api.SmartSportsEntitys;
|
|
using YD_WeChatApplet.Api.Utilities;
|
|
using YD_WeChatApplet.Commons.Dto;
|
|
using YD_WeChatApplet.Commons.Dto.ClassRoomRecord;
|
|
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;
|
|
}
|
|
|
|
/// <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>();
|
|
|
|
foreach (var item in studentTrainingRecordList)
|
|
{
|
|
var studentTrainingData = heartRateDataList.Where(x => x.StudentNo == item.StudentNo).ToList();
|
|
|
|
if (studentTrainingData.Count > 0)
|
|
{
|
|
var student = new StudentTrainingRecordDto()
|
|
{
|
|
StudentNo = item.StudentNo,
|
|
Age = item.Age,
|
|
Sex = item.Sex
|
|
};
|
|
|
|
student.StudentName = studentTrainingData[0].StudentName;
|
|
|
|
studentList.Add(student);
|
|
}
|
|
}
|
|
|
|
res.HeartRateTrend = GetHeartRateTrend(heartRateDataList);
|
|
res.StudentTrainingRecordList = studentList;
|
|
|
|
return res;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 学员报告
|
|
/// </summary>
|
|
/// <param name="classRoomId"></param>
|
|
/// <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;
|
|
}
|
|
}
|
|
}
|