2007 lines
83 KiB
C#
2007 lines
83 KiB
C#
using AutoMapper;
|
||
using EFCore.BulkExtensions;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
using Microsoft.Extensions.Logging;
|
||
using Newtonsoft.Json;
|
||
using VOL.Ai.IRepositories;
|
||
using VOL.Ai.IServices;
|
||
using VOL.Core.Configuration;
|
||
using VOL.Core.Extensions;
|
||
using VOL.Core.Extensions.AutofacManager;
|
||
using VOL.Core.Utilities;
|
||
using VOL.Entity.DomainModels;
|
||
using VOL.Entity.Enum;
|
||
using VOL.Model;
|
||
using VOL.Model.Ai;
|
||
using VOL.Model.Ai.Request;
|
||
using VOL.Model.Ai.Response;
|
||
using VOL.Model.JingShiTiJiao;
|
||
using VOL.Model.Norm.Response;
|
||
using VOL.Model.Training.Response;
|
||
using VOL.System.IRepositories;
|
||
using VOL.System.Repositories;
|
||
|
||
namespace VOL.Ai.Services
|
||
{
|
||
public class AiAppService : IAiAppService, IDependency
|
||
{
|
||
private readonly IMapper _mapper;
|
||
private readonly IS_StudentRepository _studentRepository;
|
||
private readonly IS_TeacherRepository _teacherRepository;
|
||
private readonly IS_ClassRepository _classRepository;
|
||
private readonly IN_SportsTestCategoryRepository _sportsTestCategoryRepository;
|
||
private readonly IN_HealthStandardsRepository _healthStandardsRepository;
|
||
private readonly IScanCodeLoginRepository _scanCodeLoginRepository;
|
||
private readonly IAiAppVersionRepository _aiAppVersionRepository;
|
||
private readonly IN_SportsTrainingCategoryRepository _sportsTrainingCategoryRepository;
|
||
private readonly IClassRoomRecordRepository _classRoomRecordRepository;
|
||
private readonly IActivitiestDataRepository _activitiestDataRepository;
|
||
private readonly ILevelExamDataRepository _levelExamDataRepository;
|
||
private readonly ISportsTestDataRepository _sportsTestDataRepository;
|
||
private readonly ITrainingDataRepository _trainingDataRepository;
|
||
private readonly IFastJumpRopeDataRepository _fastJumpRopeDataRepository;
|
||
private readonly IHeartRateDataRepository _heartRateDataRepository;
|
||
private readonly ISys_UserRepository _userRepository;
|
||
private readonly IClassroomStageRepository _classroomStageRepository;
|
||
private readonly IClassroomSettingRepository _classroomSettingRepository;
|
||
|
||
private readonly IJingShiTiJiaoService _jingShiTiJiaoService;
|
||
private readonly ILogger<AiAppService> _logger;
|
||
|
||
[ActivatorUtilitiesConstructor]
|
||
public AiAppService(IMapper mapper,
|
||
IS_StudentRepository studentRepository,
|
||
IS_TeacherRepository teacherRepository,
|
||
IS_ClassRepository classRepository,
|
||
IN_SportsTestCategoryRepository sportsTestCategoryRepository,
|
||
IN_HealthStandardsRepository healthStandardsRepository,
|
||
IScanCodeLoginRepository scanCodeLoginRepository,
|
||
IN_SportsTrainingCategoryRepository sportsTrainingCategoryRepository,
|
||
IClassRoomRecordRepository classRoomRecordRepository,
|
||
IActivitiestDataRepository activitiestDataRepository,
|
||
ILevelExamDataRepository levelExamDataRepository,
|
||
ISportsTestDataRepository sportsTestDataRepository,
|
||
ITrainingDataRepository trainingDataRepository,
|
||
IFastJumpRopeDataRepository fastJumpRopeDataRepository,
|
||
IHeartRateDataRepository heartRateDataRepository,
|
||
ISys_UserRepository userRepository,
|
||
IClassroomStageRepository classroomStageRepository,
|
||
IClassroomSettingRepository classroomSettingRepository,
|
||
IAiAppVersionRepository aiAppVersionRepository,
|
||
IJingShiTiJiaoService jingShiTiJiaoService,
|
||
ILogger<AiAppService> logger
|
||
)
|
||
{
|
||
_mapper = mapper;
|
||
_studentRepository = studentRepository;
|
||
_sportsTestCategoryRepository = sportsTestCategoryRepository;
|
||
_healthStandardsRepository = healthStandardsRepository;
|
||
_scanCodeLoginRepository = scanCodeLoginRepository;
|
||
_teacherRepository = teacherRepository;
|
||
_sportsTrainingCategoryRepository = sportsTrainingCategoryRepository;
|
||
_classRoomRecordRepository = classRoomRecordRepository;
|
||
_activitiestDataRepository = activitiestDataRepository;
|
||
_levelExamDataRepository = levelExamDataRepository;
|
||
_sportsTestDataRepository = sportsTestDataRepository;
|
||
_trainingDataRepository = trainingDataRepository;
|
||
_classRepository = classRepository;
|
||
_fastJumpRopeDataRepository = fastJumpRopeDataRepository;
|
||
_heartRateDataRepository = heartRateDataRepository;
|
||
_userRepository = userRepository;
|
||
_classroomStageRepository = classroomStageRepository;
|
||
_classroomSettingRepository = classroomSettingRepository;
|
||
_aiAppVersionRepository = aiAppVersionRepository;
|
||
_jingShiTiJiaoService = jingShiTiJiaoService;
|
||
_logger = logger;
|
||
}
|
||
|
||
#region New
|
||
public async Task<Ai_DeviceDto> Ai_DeviceInfo(AiRequestDto paramDto)
|
||
{
|
||
var res = await (
|
||
from d in _studentRepository.DbContext.Set<Ai_Device>()
|
||
join a in _studentRepository.DbContext.Set<Ai_DeviceAssocSchool>() on d.Code equals a.Code
|
||
join s in _studentRepository.DbContext.Set<S_School>() on a.SchoolCode equals s.SchoolCode
|
||
where d.Code == paramDto.Code
|
||
select new Ai_DeviceDto()
|
||
{
|
||
Code = d.Code,
|
||
Name = d.Name,
|
||
SchoolName = s.SchoolName,
|
||
Status = d.Status,
|
||
StartTime = d.StartTime,
|
||
EndTime = d.EndTime
|
||
}).FirstOrDefaultAsync();
|
||
|
||
return res;
|
||
}
|
||
|
||
public async Task<Ai_SchoolDto> Ai_SchoolDetail(Ai_SchoolRequest paramDto)
|
||
{
|
||
// =========================
|
||
// 1️⃣ 查询学校信息
|
||
// =========================
|
||
//var res = await (
|
||
// from a in _studentRepository.DbContext.Set<Ai_DeviceAssocSchool>()
|
||
// join s in _studentRepository.DbContext.Set<S_School>()
|
||
// on a.SchoolCode equals s.SchoolCode
|
||
// where a.Code == paramDto.Code
|
||
// select new Ai_SchoolDto
|
||
// {
|
||
// SchoolCode = s.SchoolCode,
|
||
// Name = s.SchoolName,
|
||
// Type = s.SchoolNatureId,
|
||
// Province = s.Province,
|
||
// City = s.City
|
||
// }
|
||
//).FirstOrDefaultAsync();
|
||
|
||
//if (res == null)
|
||
// return new Ai_SchoolDto();
|
||
|
||
if (string.IsNullOrWhiteSpace(paramDto.Code))
|
||
throw new ArgumentException("学校编码不能为空", nameof(paramDto.Code));
|
||
|
||
var schoolCode = paramDto.Code;
|
||
|
||
// =========================
|
||
// 2️⃣ 调用京师接口获取学校年级班级
|
||
// =========================
|
||
var schoolClass = await _jingShiTiJiaoService.GetClassBySchoolAsync(schoolCode);
|
||
|
||
if (schoolClass?.Grades == null || !schoolClass.Grades.Any())
|
||
throw new Exception("获取京师年级班级失败!");
|
||
|
||
var res = new Ai_SchoolDto()
|
||
{
|
||
SchoolCode = schoolCode,
|
||
Name = schoolClass.SchoolName,
|
||
Type = 1,
|
||
Province = "",
|
||
City = ""
|
||
};
|
||
|
||
var gradeDtos = schoolClass.Grades;
|
||
|
||
// =========================
|
||
// 3️⃣ 提取所有 GradeNo / ClassNo
|
||
// =========================
|
||
var allGradeNos = gradeDtos
|
||
.Where(g => !string.IsNullOrWhiteSpace(g.GradeNo))
|
||
.Select(g => g.GradeNo)
|
||
.ToList();
|
||
|
||
var allClassNos = gradeDtos
|
||
.SelectMany(g => g.Classes ?? new List<JingShiClassDto>())
|
||
.Where(c => !string.IsNullOrWhiteSpace(c.ClassNo))
|
||
.Select(c => c.ClassNo)
|
||
.ToList();
|
||
|
||
// =========================
|
||
// 4️⃣ 查询数据库中已存在的数据(幂等)
|
||
// =========================
|
||
var existGrades = await _studentRepository.DbContext.Set<JS_Grade>()
|
||
.Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo))
|
||
.ToListAsync();
|
||
|
||
var existClasses = await _classRepository.DbContext.Set<JS_Class>()
|
||
.Where(x => x.SchoolCode == schoolCode && allClassNos.Contains(x.ClassNo))
|
||
.ToListAsync();
|
||
|
||
var existGradeNoSet = existGrades.Select(x => x.GradeNo).ToHashSet();
|
||
var existClassNoSet = existClasses.Select(x => x.ClassNo).ToHashSet();
|
||
|
||
// =========================
|
||
// 5️⃣ 构造待插入的年级 + 班级
|
||
// =========================
|
||
var newGrades = new List<JS_Grade>();
|
||
|
||
foreach (var g in gradeDtos)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(g.GradeNo) || existGradeNoSet.Contains(g.GradeNo))
|
||
continue;
|
||
|
||
var grade = new JS_Grade
|
||
{
|
||
SchoolCode = schoolCode,
|
||
Code = paramDto.Code,
|
||
GradeNo = g.GradeNo,
|
||
GradeName = g.GradeName,
|
||
Classes = g.Classes?
|
||
.Where(c => !string.IsNullOrWhiteSpace(c.ClassNo) && !existClassNoSet.Contains(c.ClassNo))
|
||
.Select(c => new JS_Class
|
||
{
|
||
SchoolCode = schoolCode,
|
||
Code = paramDto.Code,
|
||
GradeNo = g.GradeNo,
|
||
GradeName = g.GradeName,
|
||
ClassNo = c.ClassNo,
|
||
ClassName = c.ClassName
|
||
}).ToList() ?? new List<JS_Class>()
|
||
};
|
||
|
||
newGrades.Add(grade);
|
||
|
||
existGradeNoSet.Add(g.GradeNo);
|
||
foreach (var c in grade.Classes)
|
||
existClassNoSet.Add(c.ClassNo);
|
||
}
|
||
|
||
if (newGrades.Any())
|
||
await _studentRepository.DbContext.Set<JS_Grade>().AddRangeAsync(newGrades);
|
||
|
||
// =========================
|
||
// 6️⃣ 保存(并发幂等兜底)
|
||
// =========================
|
||
try
|
||
{
|
||
await _studentRepository.DbContext.SaveChangesAsync();
|
||
}
|
||
catch (DbUpdateException ex) when (ex.InnerException?.Message.Contains("UNIQUE") == true)
|
||
{
|
||
// 并发下唯一索引冲突可忽略
|
||
}
|
||
|
||
// =========================
|
||
// 7️⃣ 回查数据库,组装返回 DTO
|
||
// =========================
|
||
var dbGrades = await _studentRepository.DbContext.Set<JS_Grade>()
|
||
.Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo))
|
||
.Include(g => g.Classes)
|
||
.ToListAsync();
|
||
|
||
res.Grade = dbGrades
|
||
.Where(g => g.Classes != null && g.Classes.Any())
|
||
.Select(g => new Grades
|
||
{
|
||
Id = (int)g.Id,
|
||
Name = g.GradeName,
|
||
Class = g.Classes.Select(c => new Classes
|
||
{
|
||
Id = (int)c.Id,
|
||
Name = c.ClassName
|
||
}).ToList()
|
||
})
|
||
.ToList();
|
||
|
||
|
||
return res;
|
||
|
||
//if (string.IsNullOrWhiteSpace(paramDto.Code))
|
||
// throw new ArgumentException("学校编码不能为空", nameof(paramDto.Code));
|
||
|
||
//var schoolCode = paramDto.Code;
|
||
|
||
//// =========================
|
||
//// 1️⃣ 调用京师接口获取学校信息及年级班级
|
||
//// =========================
|
||
//var schoolClass = await _jingShiTiJiaoService.GetClassBySchoolAsync(schoolCode);
|
||
|
||
//if (schoolClass?.Grades == null || !schoolClass.Grades.Any())
|
||
// throw new Exception("获取京师年级班级失败!");
|
||
|
||
//// =========================
|
||
//// 2️⃣ 组装返回 DTO
|
||
//// =========================
|
||
//var res = new Ai_SchoolDto()
|
||
//{
|
||
// SchoolCode = schoolCode,
|
||
// Name = schoolClass.SchoolName,
|
||
// Type = 1, // 可根据业务修改
|
||
// Province = "",
|
||
// City = "",
|
||
// Grade = schoolClass.Grades.Select(g => new Grades
|
||
// {
|
||
// Id = 1, // 京师接口没有数据库 Id,可用占位
|
||
// Name = g.GradeName,
|
||
// Class = g.Classes?.Select(c => new Classes
|
||
// {
|
||
// Id = 1, // 同上
|
||
// Name = c.ClassName
|
||
// }).ToList() ?? new List<Classes>()
|
||
// }).ToList()
|
||
//};
|
||
|
||
//return res;
|
||
}
|
||
|
||
public Ai_OSSInfoDto OSSInfo(Ai_Request paramDto)
|
||
{
|
||
return new Ai_OSSInfoDto()
|
||
{
|
||
Accessid = AppSetting.ALiYunOSS.AccessKeyId,
|
||
AccessKeySecret = AppSetting.ALiYunOSS.SecretAccessKey,
|
||
Endpoint = AppSetting.ALiYunOSS.Endpoint,
|
||
BucketName = AppSetting.YueDongServerOSS.BucketName,
|
||
Prefix = AppSetting.YueDongServerOSS.Prefix
|
||
};
|
||
}
|
||
|
||
//public async Task<List<Ai_ItemTypeModel>> GetAiCategoryType()
|
||
//{
|
||
// return await Task.FromResult(Tool.GetEnumDescriptions<Ai_ItemTypeModel, SportsTestItemType>((code, description)
|
||
// => new Ai_ItemTypeModel { ItemCode = code, ItemTypeName = description }));
|
||
//}
|
||
|
||
public async Task<ResultFilesDto> ResultFiles(ResultFilesRequest paramDto, IFormFile file)
|
||
{
|
||
var path = $"Upload/{paramDto.SchoolCode}/Voide/{paramDto.ClassRoomRecordId}/";
|
||
var name = Path.GetFileNameWithoutExtension(file.FileName);
|
||
var url = ALiYunOss.Upload(file, path, name);
|
||
|
||
var updateModels = await _levelExamDataRepository.FindAsync(x => x.SchoolCode == paramDto.SchoolCode &&
|
||
x.FileName == name);
|
||
|
||
updateModels.ForEach(x =>
|
||
{
|
||
x.FileUrl = url;
|
||
});
|
||
|
||
_levelExamDataRepository.UpdateRange(updateModels);
|
||
await _levelExamDataRepository.SaveChangesAsync();
|
||
|
||
return new ResultFilesDto() { Name = name, Url = url };
|
||
}
|
||
|
||
public async Task<List<Ai_ModeTypeModel>> ItemTypeList()
|
||
{
|
||
var list = await (from t in _sportsTestCategoryRepository.DbContext.Set<N_TrainingAssocCategory>()
|
||
join a in _sportsTrainingCategoryRepository.DbContext.Set<N_SportsTrainingCategory>() on t.CategoryValue equals a.CategoryValue
|
||
where t.DataSource == DataSource.AI
|
||
select new
|
||
{
|
||
Id = a.CategoryValue,
|
||
t.ModeId,
|
||
ItemTypeName = a.CategoryName
|
||
}).ToListAsync();
|
||
|
||
List<Ai_ModeTypeModel> result = Enum.GetValues(typeof(Ai_ModeEnum))
|
||
.Cast<Ai_ModeEnum>()
|
||
.Select(modeEnum => new Ai_ModeTypeModel
|
||
{
|
||
ModeId = (int)modeEnum,
|
||
ModeName = modeEnum.GetDescription(),
|
||
ItemTypeList = list
|
||
.Where(x => x.ModeId == (int)modeEnum)
|
||
.Select(x => new Ai_ItemTypeModel
|
||
{
|
||
ItemCode = x.Id,
|
||
ItemTypeName = x.ItemTypeName
|
||
})
|
||
.ToList()
|
||
})
|
||
.Where(model => model.ItemTypeList.Any())
|
||
.ToList();
|
||
|
||
return result;
|
||
}
|
||
|
||
public async Task<List<Ai_ModeTypeModel>> CategoryList()
|
||
{
|
||
var list = await (from t in _sportsTestCategoryRepository.DbContext.Set<N_TestAssocCategory>()
|
||
join a in _sportsTrainingCategoryRepository.DbContext.Set<N_SportsTestCategory>() on t.CategoryValue equals a.CategoryValue
|
||
where t.DataSource == DataSource.AI
|
||
select new
|
||
{
|
||
Id = a.CategoryValue,
|
||
t.ModeId,
|
||
ItemTypeName = a.CategoryName
|
||
}).ToListAsync();
|
||
|
||
List<Ai_ModeTypeModel> result = Enum.GetValues(typeof(Ai_ModeEnum))
|
||
.Cast<Ai_ModeEnum>()
|
||
.Select(modeEnum => new Ai_ModeTypeModel
|
||
{
|
||
ModeId = (int)modeEnum,
|
||
ModeName = modeEnum.GetDescription(),
|
||
ItemTypeList = list
|
||
.Where(x => x.ModeId == (int)modeEnum)
|
||
.Select(x => new Ai_ItemTypeModel
|
||
{
|
||
ItemCode = x.Id,
|
||
ItemTypeName = x.ItemTypeName
|
||
})
|
||
.ToList()
|
||
})
|
||
.Where(model => model.ItemTypeList.Any())
|
||
.ToList();
|
||
|
||
return result;
|
||
}
|
||
|
||
public async Task<Ai_StudentFaceInfo> StudentFace(GetFaceParam paramDto)
|
||
{
|
||
var faces = await ALiYunFace.SearchFace(paramDto.Base64, true);
|
||
|
||
foreach (var body in faces)
|
||
{
|
||
if (body != null && body.Confidence >= 70)
|
||
{
|
||
var student = await (from s in _studentRepository.FindAsIQueryable(x => x.SchoolCode == paramDto.SchoolCode && x.StudentNo == body.EntityId)
|
||
join c in _studentRepository.DbContext.Set<S_Class>() on s.ClassId equals c.Id
|
||
select new Ai_StudentFaceInfo
|
||
{
|
||
ClassId = c.Id,
|
||
ClassName = c.ClassName,
|
||
Age = s.Age,
|
||
Sex = s.Sex,
|
||
StudentName = s.StudentName,
|
||
StudentCode = s.StudentNo,
|
||
GradeId = c.GradeId,
|
||
GradeName = c.GradeName,
|
||
Photo = s.Photo
|
||
}).FirstOrDefaultAsync();
|
||
|
||
if (student == null)
|
||
continue;
|
||
|
||
return student;
|
||
}
|
||
}
|
||
|
||
throw new Exception("未查询到学生信息");
|
||
}
|
||
|
||
public async Task<Ai_TeacherFaceInfo> TeacherFace(GetFaceParam paramDto)
|
||
{
|
||
var faces = await ALiYunFace.SearchFace(paramDto.Base64, false);
|
||
|
||
foreach (var body in faces)
|
||
{
|
||
if (body != null && body.Confidence >= 72.62)
|
||
{
|
||
var teacher = await _teacherRepository.FindAsIQueryable(x => x.SchoolCode == paramDto.SchoolCode && x.TeacherStatus != TeacherStatus.Depart && x.TeacherPhoneNo == body.EntityId)
|
||
.Select(x =>
|
||
new Ai_TeacherFaceInfo()
|
||
{
|
||
Id = x.Id,
|
||
Age = x.Age,
|
||
//SchoolCode = x.SchoolCode,
|
||
Sex = x.Sex,
|
||
Phone = x.TeacherPhoneNo,
|
||
TeacherName = x.TeacherName,
|
||
Photo = x.TeacherPhoto,
|
||
}).FirstOrDefaultAsync();
|
||
|
||
if (teacher == null)
|
||
continue;
|
||
|
||
var grades = await (
|
||
from t in _studentRepository.DbContext.Set<S_ClassAssocTeacher>()
|
||
join c in _studentRepository.DbContext.Set<S_Class>() on t.ClassId equals c.Id into classGroup
|
||
from c in classGroup.DefaultIfEmpty()
|
||
where t.TeacherId == teacher.Id && c != null
|
||
select new Classes()
|
||
{
|
||
Id = c.Id,
|
||
Name = $"{c.GradeName}-{c.ClassName}",
|
||
}).ToListAsync();
|
||
|
||
teacher.GradeAndClassList = grades;
|
||
|
||
return teacher;
|
||
}
|
||
}
|
||
|
||
throw new Exception("未查询到老师信息");
|
||
}
|
||
|
||
public async Task<List<Ai_StudentListDto>> Ai_StudentList(Ai_StudentListRequest paramDto)
|
||
{
|
||
var classInfo = await _classRepository.DbContext.Set<JS_Class>().Where(x => x.Id == paramDto.Id).FirstOrDefaultAsync();
|
||
|
||
var students = await _jingShiTiJiaoService.GetStuListByClass(classInfo?.ClassNo ?? "");
|
||
|
||
var res = students
|
||
.Select((s, index) => new Ai_StudentListDto
|
||
{
|
||
Code = paramDto.Code,
|
||
StudentNo = s.StuNo,
|
||
StudentName = s.StuName,
|
||
Sex = s.Gender == "男" ? SexType.Male : SexType.Female,
|
||
Age = s.Age,
|
||
Photo = s.Avatar ?? "",
|
||
ClassName = s.ClassName,
|
||
GradeName = s.GradeName,
|
||
OrderNo = index + 1
|
||
})
|
||
.OrderBy(x => x.OrderNo)
|
||
.ToList();
|
||
|
||
return res;
|
||
}
|
||
|
||
public async Task<AiStudentDetailsDto> Ai_StudentDetail(Ai_StudentDetailRequest paramDto)
|
||
{
|
||
// 1️⃣ 调用京师接口获取学生详情
|
||
var student = await _jingShiTiJiaoService.GetStudentInfo(paramDto.StudentNo);
|
||
if (student == null)
|
||
return null;
|
||
|
||
var schoolCode = student.School;
|
||
|
||
// 2️⃣ 查询数据库班级(包含 GradeId)
|
||
var dbClass = await _classRepository.DbContext.Set<JS_Class>()
|
||
.FirstOrDefaultAsync(c => c.SchoolCode == schoolCode && c.ClassNo == student.ClassNo);
|
||
|
||
// 3️⃣ 映射到 DTO
|
||
var res = new AiStudentDetailsDto
|
||
{
|
||
StudentNo = student.StuNo,
|
||
StudentName = student.StuName,
|
||
Age = student.Age,
|
||
IdCard = student.StuNo,
|
||
Sex = student.Gender == "男" ? SexType.Male : SexType.Female,
|
||
Photo = "",
|
||
|
||
ClassId = dbClass?.Id != null ? (int)dbClass.Id : 0,
|
||
ClassName = student.ClassName,
|
||
|
||
// 直接通过班级表关联的年级 Id
|
||
GradeId = dbClass?.Grade?.Id != null ? (int)dbClass.Grade.Id : 0,
|
||
GradeName = student.GradeName
|
||
};
|
||
|
||
return res;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 获取专项教学项目
|
||
/// </summary>
|
||
public async Task<List<Ai_ItemTypeModel>> TeachingItems(Ai_Request paramDto)
|
||
{
|
||
var list = await (
|
||
from s in _studentRepository.DbContext.Set<Ai_Special>()
|
||
select new Ai_ItemTypeModel()
|
||
{
|
||
ItemCode = s.Id,
|
||
ItemTypeName = s.SpecialName
|
||
}).ToListAsync();
|
||
|
||
return list;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取专项教学项目详情
|
||
/// </summary>
|
||
public async Task<Ai_TeachingItemsDetailModel> TeachingItemsDetail(Ai_TeachingItemsRequest paramDto)
|
||
{
|
||
if (paramDto == null || paramDto.ItemCode <= 0)
|
||
{
|
||
Console.WriteLine("参数为空,跳过...");
|
||
return new Ai_TeachingItemsDetailModel();
|
||
}
|
||
|
||
var result = await (
|
||
from s in _studentRepository.DbContext.Set<Ai_Special>()
|
||
where s.Id == paramDto.ItemCode
|
||
select new Ai_TeachingItemsDetailModel
|
||
{
|
||
BasicSkillList = s.SpecialLevelList
|
||
.Select(level => new SpecialLevelBasicSkill
|
||
{
|
||
Id = level.Id,
|
||
Name = level.LevelName,
|
||
StartGrade = level.StartGrade,
|
||
EndGrade = level.EndGrade,
|
||
SpecialActionModes = level.SpecialActionList
|
||
.Where(a => a.ActionType == SpecialActionType.BasicSkill)
|
||
.Select(a => new SpecialActionBasicSkill
|
||
{
|
||
Id = a.Id,
|
||
Name = a.ActionName,
|
||
ActionVideoPath = a.ActionVideoPath,
|
||
ExplainVideoPath = a.ExplainVideoPath,
|
||
ExerciseVideoPath = a.ExerciseVideoPath,
|
||
StandardVideoPath = a.StandardVideoPath
|
||
}).ToList()
|
||
}).ToList(),
|
||
SpecialStaminaList = s.SpecialLevelList
|
||
.Select(level => new SpecialLevelSpecialStamina
|
||
{
|
||
Id = level.Id,
|
||
Name = level.LevelName,
|
||
StartGrade = level.StartGrade,
|
||
EndGrade = level.EndGrade,
|
||
SpecialActionModes = level.SpecialActionList
|
||
.Where(a => a.ActionType == SpecialActionType.SpecialStamina)
|
||
.Select(a => new SpecialActionSpecialStamina
|
||
{
|
||
Id = a.Id,
|
||
Name = a.ActionName,
|
||
ActionVideoPath = a.ActionVideoPath
|
||
}).ToList()
|
||
}).ToList(),
|
||
}).FirstOrDefaultAsync();
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 获取赛事活动列表
|
||
/// </summary>
|
||
public async Task<PageDataDto<Ai_ActivitiesListDto>> ActivitiesList(Ai_ActivitiesListRequest paramDto)
|
||
{
|
||
var res = new PageDataDto<Ai_ActivitiesListDto>();
|
||
|
||
var query = from s in _studentRepository.DbContext.Set<G_Activities>()
|
||
where s.SchoolCode.Equals(paramDto.SchoolCode)
|
||
select new Ai_ActivitiesListDto()
|
||
{
|
||
ActivitiesId = s.Id,
|
||
ItemCode = s.CategoryId,
|
||
ActivitiesName = s.ActivitiesName,
|
||
ItemName = s.CategoryName,
|
||
EndDate = s.EndDate,
|
||
StartDate = s.StartDate,
|
||
ActivitiesStatus = s.ActivitiesStatus,
|
||
ImagePath = s.ImagePath,
|
||
ModeType = s.ModeType,
|
||
DataType = s.DataType
|
||
};
|
||
|
||
if (paramDto.ActivitiesStatus > 0)
|
||
{
|
||
query = query.Where(x => x.ActivitiesStatus == paramDto.ActivitiesStatus);
|
||
}
|
||
|
||
if (paramDto.ModeType > 0)
|
||
{
|
||
query = query.Where(x => x.ModeType == paramDto.ModeType);
|
||
}
|
||
|
||
if (paramDto.DataType > 0)
|
||
{
|
||
query = query.Where(x => x.DataType == paramDto.DataType);
|
||
}
|
||
|
||
res.Total = await query.CountAsync();
|
||
res.PageIndex = paramDto.PageIndex;
|
||
res.PageSize = paramDto.PageSize;
|
||
res.TotalPages = (int)Math.Ceiling((double)res.Total / paramDto.PageSize);
|
||
|
||
var list = await query
|
||
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
|
||
.Take(paramDto.PageSize)
|
||
|
||
.ToListAsync();
|
||
|
||
res.Datas = list;
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取赛事活动排行
|
||
/// </summary>
|
||
public async Task<ActivitiesRankingPageDataDto<Ai_ActivitiesRankingDto>> ActivitiesRanking(Ai_ActivitiesRequest paramDto)
|
||
{
|
||
var res = new ActivitiesRankingPageDataDto<Ai_ActivitiesRankingDto>();
|
||
|
||
var query = from a in _activitiestDataRepository.DbContext.Set<Ai_ActivitiestData>()
|
||
join s in _activitiestDataRepository.DbContext.Set<S_Student>() on a.StudentNo equals s.StudentNo
|
||
join c in _activitiestDataRepository.DbContext.Set<S_School>() on s.SchoolCode equals c.SchoolCode
|
||
where a.ActivitiesId == paramDto.ActivitiesId
|
||
orderby a.Value descending
|
||
select new Ai_ActivitiesRankingDto()
|
||
{
|
||
SchoolName = c.SchoolName,
|
||
Score = a.Value.ToString(),
|
||
GradeAndClass = $"{a.GradeName}-{a.ClassName}",
|
||
Sex = s.Sex,
|
||
StudentName = s.StudentName,
|
||
Photo = s.Photo,
|
||
SportsTestDataType = a.DataType,
|
||
CategoryEnumType = a.CategoryValue,
|
||
};
|
||
|
||
res.Total = await query.CountAsync();
|
||
res.Name = paramDto.ActivitiesName;
|
||
|
||
var pagedDataList = await query
|
||
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
|
||
.Take(paramDto.PageSize)
|
||
.ToListAsync();
|
||
|
||
var rankedList = pagedDataList
|
||
.Select((item, index) => new Ai_ActivitiesRankingDto
|
||
{
|
||
SchoolName = item.SchoolName,
|
||
Score = item.Score,
|
||
GradeAndClass = item.GradeAndClass,
|
||
Sex = item.Sex,
|
||
StudentName = item.StudentName,
|
||
Photo = item.Photo,
|
||
SportsTestDataType = item.SportsTestDataType,
|
||
CategoryEnumType = item.CategoryEnumType,
|
||
Ranking = (paramDto.PageIndex - 1) * paramDto.PageSize + (index + 1)
|
||
})
|
||
.ToList();
|
||
|
||
res.Datas = rankedList;
|
||
|
||
return res;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 获取体测排行
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<PageDataDto<Ai_RankingListDto>> SportsTestRanking(Ai_RankingListRequest paramDto)
|
||
{
|
||
var res = new PageDataDto<Ai_RankingListDto>();
|
||
|
||
// 构建查询
|
||
var query = _sportsTestDataRepository.FindAsIQueryable(x =>
|
||
x.CategoryValue == paramDto.ItemCode &&
|
||
x.SchoolCode == paramDto.SchoolCode && x.DataType == paramDto.DataType);
|
||
|
||
if (paramDto.TodayTime.HasValue)
|
||
{
|
||
var todayStart = paramDto.TodayTime.Value.Date;
|
||
var todayEnd = todayStart.AddDays(1).AddTicks(-1);
|
||
|
||
query = query.Where(x => x.StartTime >= todayStart && x.StartTime <= todayEnd);
|
||
}
|
||
|
||
if (paramDto.GradeId > 0)
|
||
{
|
||
query = query.Where(x => x.GradeId == paramDto.GradeId);
|
||
}
|
||
|
||
if (paramDto.ClassId > 0)
|
||
{
|
||
query = query.Where(x => x.ClassId == paramDto.ClassId);
|
||
}
|
||
|
||
// 异步获取数据列表
|
||
var rawData = await query.ToListAsync().ConfigureAwait(false);
|
||
|
||
// 在内存中分组并获取每个分组中最大的值
|
||
var data = rawData
|
||
.GroupBy(x => x.StudentNo)
|
||
.Select(g => g.OrderByDescending(x => x.Value).FirstOrDefault()) // 获取每个学生 Value 最大的数据
|
||
.OrderByDescending(x => x.Value)
|
||
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
|
||
.Take(paramDto.PageSize)
|
||
.Select(x => new Ai_RankingListDto()
|
||
{
|
||
StudentNo = x.StudentNo,
|
||
StudentName = x.StudentName,
|
||
Value = x.Value,
|
||
})
|
||
.ToList();
|
||
|
||
res.Total = data.Count;
|
||
|
||
// 计算排名
|
||
var list = data
|
||
.Select((item, index) => new Ai_RankingListDto
|
||
{
|
||
StudentNo = item.StudentNo,
|
||
StudentName = item.StudentName,
|
||
Value = item.Value,
|
||
Ranking = (paramDto.PageIndex - 1) * paramDto.PageSize + (index + 1)
|
||
})
|
||
.ToList();
|
||
|
||
res.Datas = list;
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 体测成绩查询
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<PageDataDto<Ai_SportsTestDto>> SportsTestResult(Ai_SportsTestRequest paramDto)
|
||
{
|
||
var res = new PageDataDto<Ai_SportsTestDto>();
|
||
|
||
var query = from a in _sportsTestDataRepository.FindAsIQueryable(x =>
|
||
x.CategoryValue == paramDto.ItemCode &&
|
||
x.SchoolCode == paramDto.SchoolCode)
|
||
//.Include(c => c.FileList)
|
||
orderby a.ScoreTime descending
|
||
select new Ai_SportsTestDto()
|
||
{
|
||
//IfVideo = a.FileList.Count > 0,
|
||
//FileList = _mapper.Map<List<FileList>>(a.FileList),
|
||
Value = a.Value,
|
||
SportsTestDataType = a.DataType,
|
||
CategoryEnumType = a.CategoryValue,
|
||
TestTime = a.ScoreTime,
|
||
StudentNo = a.StudentNo,
|
||
StudentName = a.StudentName
|
||
};
|
||
|
||
res.Total = await query.CountAsync();
|
||
|
||
var list = await query
|
||
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
|
||
.Take(paramDto.PageSize)
|
||
.ToListAsync();
|
||
|
||
res.Datas = list;
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 训练成绩上传
|
||
/// </summary>
|
||
public async Task TrainingDataUpload(Ai_ResultUploadRequest paramDto)
|
||
{
|
||
//var trainingDataIds = paramDto.Select(c => c.TrainingDataId).ToList();
|
||
|
||
//if (paramDto == null)
|
||
// throw new ArgumentNullException($"参数为空");
|
||
|
||
//if (trainingDataIds.Any(c => c < 0))
|
||
// throw new ArgumentNullException($"训练数据Id必传");
|
||
|
||
//var trainingDatas = await _studentRepository.FindAsync<Ai_TrainingData>(s =>
|
||
// s.SchoolCode.Equals(UserContext.Current.TenantId) &&
|
||
// trainingDataIds.Contains(s.Id)
|
||
//);
|
||
|
||
//// 判断是否所有训练详情都有训练数据
|
||
//if (!trainingDataIds.All(c => trainingDatas.Select(x => x.Id).Contains(c)))
|
||
// throw new ArgumentNullException($"存在未找到的训练数据Id");
|
||
|
||
//var students = await _studentRepository.FindAsync<S_Student>(s =>
|
||
// s.SchoolCode.Equals(UserContext.Current.TenantId) &&
|
||
// paramDto.Select(c => c.StudentNo).Contains(s.StudentNo)
|
||
//);
|
||
|
||
//// 判断是否都有学号
|
||
//if (!students.Select(c => c.StudentNo).All(c => students.Select(s => s.StudentNo).Contains(c)))
|
||
// throw new ArgumentNullException($"存在未找到的学号");
|
||
|
||
//var trainingDetailsData = paramDto.Select(c => new Ai_TrainingData
|
||
//{
|
||
// StudentNo = c.StudentNo,
|
||
// StudentName = students.First(d => d.StudentNo == c.StudentNo).StudentName,
|
||
// Sex = students.First(d => d.StudentNo == c.StudentNo).Sex,
|
||
// Value = c.Value,
|
||
// MotionDuration = c.MotionDuration,
|
||
// Consumption = c.Consumption,
|
||
// Strength = c.Strength,
|
||
// Score = c.Score,
|
||
// AdditionalScore = c.AdditionalScore,
|
||
// Rank = c.Rank,
|
||
// RankStr = c.RankStr,
|
||
// ErrorNumber = c.ErrorNumber,
|
||
// CorrectNumber = c.CorrectNumber,
|
||
// MaxValue = c.MaxValue,
|
||
// MinValue = c.MinValue
|
||
//}).ToList();
|
||
|
||
//_studentRepository.AddRange<Ai_TrainingData>(trainingDetailsData);
|
||
//await _studentRepository.SaveChangesAsync();
|
||
|
||
if (paramDto == null)
|
||
{
|
||
Console.WriteLine("参数为空,跳过...");
|
||
return;
|
||
}
|
||
|
||
var entity = _mapper.Map<Ai_TrainingData>(paramDto);
|
||
|
||
await _trainingDataRepository.AddAsync(entity);
|
||
await _trainingDataRepository.SaveChangesAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 体测成绩上传
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task SportsTestResultUpload(SportsTestResultUploadRequest paramDto)
|
||
{
|
||
if (paramDto == null)
|
||
{
|
||
Console.WriteLine("参数为空,跳过...");
|
||
return;
|
||
}
|
||
|
||
var entity = _mapper.Map<Ai_SportsTestData>(paramDto);
|
||
|
||
var student = await (from s in _studentRepository.FindAsIQueryable(x => x.SchoolCode == paramDto.SchoolCode && x.StudentNo == paramDto.StudentNo)
|
||
join c in _studentRepository.DbContext.Set<S_Class>() on s.ClassId equals c.Id
|
||
select new
|
||
{
|
||
s.ClassId,
|
||
s.ClassName,
|
||
s.Sex,
|
||
s.StudentName,
|
||
c.GradeId,
|
||
c.GradeName
|
||
}).FirstOrDefaultAsync();
|
||
|
||
if (student == null)
|
||
{
|
||
Console.WriteLine("未找到学生信息,跳过...");
|
||
return;
|
||
}
|
||
|
||
SemesterDto semesterDto = new SemesterDto();
|
||
entity.Year = semesterDto.Year;
|
||
entity.Semester = semesterDto.Semester;
|
||
|
||
entity.ScoreTime = paramDto.StartTime;
|
||
|
||
|
||
entity.GradeId = student.GradeId;
|
||
entity.ClassId = student.ClassId;
|
||
entity.GradeName = student.GradeName;
|
||
entity.ClassName = student.ClassName;
|
||
entity.StudentName = student.StudentName;
|
||
entity.Sex = student.Sex;
|
||
entity.IsDisplay = true;
|
||
|
||
var categoryEnum = Tool.GetEnumNameByValue(paramDto.CategoryValue);
|
||
var healthStandards = await _healthStandardsRepository.FindAsync(x => x.CategoryEnum == categoryEnum);
|
||
|
||
var standard = healthStandards.Where(x =>
|
||
x.CategoryEnum.Equals(categoryEnum) &&
|
||
x.GradeId == student.GradeId &&
|
||
x.Sex == student.Sex &&
|
||
paramDto.Value >= x.MinValue &&
|
||
paramDto.Value < x.MaxValue
|
||
).FirstOrDefault();
|
||
|
||
if (standard != null)
|
||
{
|
||
entity.Score = standard.Score;
|
||
entity.Rank = standard.Rank;
|
||
entity.RankEnum = Tool.GetEnumByRankName(standard.Rank);
|
||
entity.AdditionalScore = entity.Score == 100 ? 20 : 0;
|
||
}
|
||
|
||
await _sportsTestDataRepository.AddAsync(entity);
|
||
await _sportsTestDataRepository.SaveChangesAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Ai赛场成绩上传
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task ActivitiestResultUpload(Ai_ActivitiestResultUploadRequest paramDto)
|
||
{
|
||
if (paramDto == null)
|
||
{
|
||
Console.WriteLine("参数为空,跳过...");
|
||
return;
|
||
}
|
||
|
||
var entity = _mapper.Map<Ai_ActivitiestData>(paramDto);
|
||
|
||
SemesterDto semesterDto = new SemesterDto();
|
||
entity.Year = semesterDto.Year;
|
||
entity.Semester = semesterDto.Semester;
|
||
|
||
await _activitiestDataRepository.AddAsync(entity);
|
||
await _activitiestDataRepository.SaveChangesAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 考级测评成绩上传
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task LevelExamResultUpload(LevelExamDataUploadRequest paramDto)
|
||
{
|
||
if (paramDto == null)
|
||
{
|
||
Console.WriteLine("参数为空,跳过...");
|
||
return;
|
||
}
|
||
|
||
var entity = _mapper.Map<Ai_LevelExamData>(paramDto);
|
||
|
||
SemesterDto semesterDto = new SemesterDto();
|
||
entity.Year = semesterDto.Year;
|
||
entity.Semester = semesterDto.Semester;
|
||
var student = await (from s in _studentRepository.FindAsIQueryable(x => x.SchoolCode == paramDto.SchoolCode && x.StudentNo == paramDto.StudentNo)
|
||
join c in _classRepository.DbContext.Set<S_Class>() on s.ClassId equals c.Id
|
||
select new
|
||
{
|
||
s.ClassId,
|
||
s.ClassName,
|
||
s.Sex,
|
||
s.StudentName,
|
||
c.GradeId,
|
||
c.GradeName
|
||
}).FirstOrDefaultAsync();
|
||
|
||
if (student == null)
|
||
{
|
||
Console.WriteLine("未找到学生信息,跳过...");
|
||
return;
|
||
}
|
||
|
||
|
||
entity.ScoreTime = paramDto.StartTime;
|
||
entity.StartTime = paramDto.StartTime;
|
||
entity.EndTime = paramDto.EndTime;
|
||
entity.GradeId = student.GradeId;
|
||
entity.ClassId = student.ClassId;
|
||
entity.GradeName = student.GradeName;
|
||
entity.ClassName = student.ClassName;
|
||
entity.StudentName = student.StudentName;
|
||
entity.Sex = student.Sex;
|
||
entity.IsDisplay = true;
|
||
|
||
await _levelExamDataRepository.AddAsync(entity);
|
||
await _levelExamDataRepository.SaveChangesAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 心率数据上传
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task HeartRateResultUpload(AddHeartRateResultUploadRequest paramDto)
|
||
{
|
||
if (paramDto == null || paramDto.Datas == null || paramDto.Datas.Count == 0)
|
||
{
|
||
Console.WriteLine("参数为空或数据为空,跳过处理。");
|
||
return;
|
||
}
|
||
|
||
var heartRateDatas = _mapper.Map<List<Ai_HeartRateData>>(paramDto.Datas);
|
||
|
||
var classIds = paramDto.Datas.Select(x => x.ClassId).Distinct().ToList();
|
||
var classList = await _classRepository.DbContext.Set<JS_Class>().Where(x => x.SchoolCode == paramDto.SchoolCode && classIds.Contains((int)x.Id)).ToListAsync();
|
||
var classDict = classList.ToDictionary(x => x.Id, x => x);
|
||
|
||
var timeNow = DateTime.Now;
|
||
|
||
heartRateDatas.ForEach(heartRateData =>
|
||
{
|
||
if (classDict.TryGetValue(heartRateData.ClassId, out var classInfo))
|
||
{
|
||
heartRateData.Code = paramDto.Code;
|
||
heartRateData.SchoolCode = paramDto.SchoolCode;
|
||
heartRateData.ClassRoomRecordId = paramDto.ClassRoomRecordId;
|
||
heartRateData.ClassroomStageId = paramDto.ClassroomStageId;
|
||
heartRateData.TeacherId = paramDto.TeacherId;
|
||
heartRateData.GradeId = (int)classInfo.GradeId;
|
||
heartRateData.GradeName = classInfo.GradeName;
|
||
heartRateData.ClassName = classInfo.ClassName;
|
||
heartRateData.ScoreTime = timeNow;
|
||
heartRateData.IsDisplay = true;
|
||
}
|
||
});
|
||
|
||
|
||
try
|
||
{
|
||
await _heartRateDataRepository.AddRangeAsync(heartRateDatas);
|
||
await _heartRateDataRepository.SaveChangesAsync();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_logger.LogError(e, "心率数据保存失败");
|
||
throw;
|
||
}
|
||
|
||
// 异步上传心率数据,不阻塞主流程
|
||
_ = Task.Run(async () =>
|
||
{
|
||
try
|
||
{
|
||
var uploadList = heartRateDatas.Select(hr => new SportsDataPushDto
|
||
{
|
||
StudentNo = hr.StudentNo,
|
||
SportsItem = AppSetting.JingShiTiJiao.SportsItem,
|
||
SportsDate = hr.ScoreTime.ToString("yyyy-MM-dd"),
|
||
SportsService = AppSetting.JingShiTiJiao.Channel,
|
||
SportsScene = "HeartRate",
|
||
SportsDetail = JsonConvert.SerializeObject(hr)
|
||
}).ToList();
|
||
|
||
var res = await _jingShiTiJiaoService.PushSportsData(uploadList);
|
||
|
||
if (res)
|
||
|
||
{
|
||
_logger.LogInformation($"心率数据同步成功: {JsonConvert.SerializeObject(uploadList)}");
|
||
}
|
||
else
|
||
{
|
||
_logger.LogError($"心率数据同步失败: {JsonConvert.SerializeObject(uploadList)}");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "心率数据上传异常");
|
||
}
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 速度跳绳成绩上传
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task FastJumpRopeResultUpload(AddFastJumpRopeResultUploadRequest paramDto)
|
||
{
|
||
if (paramDto == null || paramDto.Datas == null || paramDto.Datas.Count == 0)
|
||
{
|
||
Console.WriteLine("参数为空或数据为空,跳过处理。");
|
||
return;
|
||
}
|
||
|
||
var fastJumpRopeDatas = _mapper.Map<List<Ai_FastJumpRopeData>>(paramDto.Datas);
|
||
|
||
var classIds = paramDto.Datas.Select(x => x.ClassId).Distinct().ToList();
|
||
var classList = await _classRepository.DbContext.Set<JS_Class>().Where(x => x.SchoolCode == paramDto.SchoolCode && classIds.Contains((int)x.Id)).ToListAsync();
|
||
var classDict = classList.ToDictionary(x => x.Id, x => x);
|
||
|
||
fastJumpRopeDatas.ForEach(data =>
|
||
{
|
||
if (classDict.TryGetValue(data.ClassId, out var classInfo))
|
||
{
|
||
data.Code = paramDto.Code;
|
||
data.SchoolCode = paramDto.SchoolCode;
|
||
data.ClassRoomRecordId = paramDto.ClassRoomRecordId;
|
||
data.GroupId = paramDto.GroupId;
|
||
data.TeacherId = paramDto.TeacherId;
|
||
data.GradeId = (int)classInfo.GradeId;
|
||
data.GradeName = classInfo.GradeName;
|
||
data.ClassName = classInfo.ClassName;
|
||
data.ScoreTime = paramDto.ScoreTime;
|
||
data.ModeType = paramDto.ModeType;
|
||
data.ModelName = paramDto.ModeType.GetDescription();
|
||
data.UniqueId = paramDto.UniqueId;
|
||
}
|
||
});
|
||
await _fastJumpRopeDataRepository.AddRangeAsync(fastJumpRopeDatas);
|
||
await _fastJumpRopeDataRepository.SaveChangesAsync();
|
||
|
||
// 2️⃣ 异步上传到极智体教平台
|
||
_ = Task.Run(async () =>
|
||
{
|
||
try
|
||
{
|
||
var uploadList = fastJumpRopeDatas.Select(d => new SportsDataPushDto
|
||
{
|
||
StudentNo = d.StudentNo,
|
||
SportsItem = AppSetting.JingShiTiJiao.SportsItem,
|
||
SportsDate = d.ScoreTime.ToString("yyyy-MM-dd"),
|
||
SportsService = AppSetting.JingShiTiJiao.Channel,
|
||
SportsScene = "FastJumpRope",
|
||
SportsDetail = JsonConvert.SerializeObject(d)
|
||
}).ToList();
|
||
|
||
var res = await _jingShiTiJiaoService.PushSportsData(uploadList);
|
||
|
||
if (res)
|
||
{
|
||
_logger.LogInformation($"速度跳绳数据同步成功: {JsonConvert.SerializeObject(uploadList)}");
|
||
}
|
||
else
|
||
{
|
||
_logger.LogError($"速度跳绳数据同步失败: {JsonConvert.SerializeObject(uploadList)}");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "速度跳绳数据上传异常");
|
||
}
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 速度跳绳测试列表
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<PageDataDto<Ai_FastJumpRopeDto>> FastJumpRopeTestList(Ai_FastJumpRopeRequest paramDto)
|
||
{
|
||
var res = new PageDataDto<Ai_FastJumpRopeDto>();
|
||
|
||
var groupedQuery = from a in _fastJumpRopeDataRepository.FindAsIQueryable(x =>
|
||
x.SchoolCode == paramDto.SchoolCode &&
|
||
(paramDto.ClassRoomRecordId == null || paramDto.ClassRoomRecordId <= 0 || x.ClassRoomRecordId == paramDto.ClassRoomRecordId))
|
||
group a by a.GroupId into g
|
||
select new
|
||
{
|
||
GroupId = g.Key,
|
||
g.FirstOrDefault().MotionDuration,
|
||
g.FirstOrDefault().ModeType,
|
||
g.FirstOrDefault().ModelName,
|
||
//MotionDuration = g.FirstOrDefault().MotionDuration,
|
||
ScoreTime = g.Max(x => x.ScoreTime),
|
||
TestItem = Ai_TrainingModuleEnum.FastJumpRope.GetDescription()
|
||
};
|
||
|
||
// 获取总记录数
|
||
res.Total = await groupedQuery.CountAsync();
|
||
|
||
// 分页查询
|
||
var list = await groupedQuery
|
||
.OrderByDescending(x => x.ScoreTime)
|
||
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
|
||
.Take(paramDto.PageSize)
|
||
.Select(x => new Ai_FastJumpRopeDto
|
||
{
|
||
GroupId = x.GroupId,
|
||
ModeType = x.ModeType,
|
||
//ModelName = x.ModeType.GetDescription(),
|
||
ModelName = x.ModelName,
|
||
MotionDuration = x.MotionDuration,
|
||
ScoreTime = x.ScoreTime,
|
||
TestItem = x.TestItem
|
||
})
|
||
.ToListAsync();
|
||
|
||
res.Datas = list;
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 速度跳绳成绩排行
|
||
/// </summary>
|
||
/// <param name="uniqueId"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<PageDataDto<Ai_FastJumpRopeStudentList>> FastJumpRopeRanking(Ai_FastJumpRopeRankingRequest paramDto)
|
||
{
|
||
var res = new PageDataDto<Ai_FastJumpRopeStudentList>();
|
||
|
||
// 构建查询
|
||
//var query = _fastJumpRopeDataRepository.FindAsIQueryable(x =>
|
||
// x.ClassRoomRecordId == paramDto.ClassRoomRecordId &&
|
||
// x.SchoolCode == paramDto.SchoolCode &&
|
||
// (paramDto.ModeType != Ai_FastJumpRopeModeEnum.FollowMode || x.GroupId == paramDto.GroupId)
|
||
// );
|
||
|
||
var query = _fastJumpRopeDataRepository.FindAsIQueryable(x =>
|
||
x.ClassRoomRecordId == paramDto.ClassRoomRecordId &&
|
||
x.SchoolCode == paramDto.SchoolCode && x.GroupId == paramDto.GroupId);
|
||
|
||
// 异步获取数据列表
|
||
var rawData = await query.ToListAsync();
|
||
|
||
// 在内存中分组并获取每个分组中最大的值
|
||
var data = rawData
|
||
.GroupBy(x => x.StudentNo)
|
||
.Select(g => g.OrderByDescending(x => x.JumpValue).FirstOrDefault())
|
||
.OrderByDescending(x => x.JumpValue)
|
||
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
|
||
.Take(paramDto.PageSize)
|
||
.Select(x => new Ai_FastJumpRopeStudentList()
|
||
{
|
||
StudentNo = x.StudentNo,
|
||
StudentName = x.StudentName,
|
||
JumpValue = x.JumpValue,
|
||
ErrorNumber = x.ErrorNumber
|
||
})
|
||
.ToList();
|
||
|
||
res.Total = data.Count;
|
||
|
||
// 计算排名
|
||
var list = data
|
||
.Select((item, index) => new Ai_FastJumpRopeStudentList
|
||
{
|
||
StudentNo = item.StudentNo,
|
||
StudentName = item.StudentName,
|
||
JumpValue = item.JumpValue,
|
||
ErrorNumber = item.ErrorNumber,
|
||
Ranking = (paramDto.PageIndex - 1) * paramDto.PageSize + (index + 1)
|
||
})
|
||
.ToList();
|
||
|
||
res.Datas = list;
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 新增课堂记录
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<Ai_ClassRoomRecordDto> AddClassRoomRecord(Ai_ClassRoomRecordRequest paramDto)
|
||
{
|
||
if (paramDto == null)
|
||
{
|
||
Console.WriteLine("参数为空或数据为空,跳过处理。");
|
||
return new Ai_ClassRoomRecordDto();
|
||
}
|
||
|
||
var entity = _mapper.Map<Ai_ClassRoomRecord>(paramDto);
|
||
|
||
var ids = paramDto.ClassroomStudentRecord.Select(x => x.ClassId).ToList();
|
||
ids.Add(paramDto.ClassId);
|
||
|
||
var classInfos = await _classRepository.DbContext.Set<JS_Class>().Where(x => ids.Contains((int)x.Id)).ToListAsync();
|
||
var classInfo = classInfos.FirstOrDefault(x => x.Id == paramDto.ClassId);
|
||
if (classInfo == null)
|
||
{
|
||
Console.WriteLine("班级信息数据为空,跳过处理。");
|
||
return new Ai_ClassRoomRecordDto();
|
||
}
|
||
|
||
var teacher = await _classRepository.DbContext.Set<JS_Teacher>().Where(x => x.Id == paramDto.TeacherId).FirstOrDefaultAsync();
|
||
|
||
if (teacher == null)
|
||
{
|
||
Console.WriteLine("未找到老师信息");
|
||
return new Ai_ClassRoomRecordDto();
|
||
}
|
||
|
||
entity.TeacherNo = teacher.TeacherNo;
|
||
entity.ClassName = classInfo.ClassName;
|
||
entity.GradeId = (int)classInfo.GradeId;
|
||
entity.GradeName = classInfo.GradeName;
|
||
//entity.Name = $"{paramDto.TrainingModuleEnum.GetDescription()}-{paramDto.StartTime.ToUnixTimeMilliseconds()}";
|
||
entity.Name = paramDto.ClassroomName;
|
||
SemesterDto semesterDto = new SemesterDto();
|
||
entity.Year = semesterDto.Year;
|
||
entity.Semester = semesterDto.Semester;
|
||
|
||
foreach (var student in entity.ClassroomStudentRecord)
|
||
{
|
||
var StuClass = classInfos.First(x => x.Id == student.ClassId);
|
||
if (StuClass == null)
|
||
{
|
||
Console.WriteLine("班级信息数据为空,跳过处理。");
|
||
return new Ai_ClassRoomRecordDto();
|
||
}
|
||
|
||
student.ClassName = StuClass.ClassName;
|
||
student.GradeId = (int)StuClass.GradeId;
|
||
student.GradeName = StuClass.GradeName;
|
||
}
|
||
|
||
await _classRoomRecordRepository.AddAsync(entity);
|
||
await _classRoomRecordRepository.SaveChangesAsync();
|
||
|
||
var classroomSettingList = new List<Ai_ClassroomSetting>();
|
||
|
||
if (entity.Id > 0)
|
||
{
|
||
foreach (var item in paramDto.ClassroomSettingList)
|
||
{
|
||
if (item.Density == 0 || item.Duration == 0)
|
||
continue;
|
||
|
||
classroomSettingList.Add(new Ai_ClassroomSetting()
|
||
{
|
||
ClassRoomRecordId = entity.Id,
|
||
ClassroomStageId = item.ClassroomStageId,
|
||
Density = item.Density,
|
||
Duration = item.Duration
|
||
});
|
||
}
|
||
|
||
if (classroomSettingList.Count > 0)
|
||
{
|
||
await _classroomSettingRepository.AddRangeAsync(classroomSettingList);
|
||
await _classroomSettingRepository.SaveChangesAsync();
|
||
}
|
||
}
|
||
|
||
return new Ai_ClassRoomRecordDto()
|
||
{
|
||
ClassRoomRecordId = entity.Id,
|
||
ClassRoomRecordName = entity.Name
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 结束授课
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task EndTeaching(EndTeachingRequest paramDto)
|
||
{
|
||
if (paramDto == null)
|
||
{
|
||
Console.WriteLine("参数为空,跳过...");
|
||
return;
|
||
}
|
||
|
||
|
||
var entity = await _classRoomRecordRepository.FindAsyncFirst(x => x.Id == paramDto.ClassRoomRecordId && x.SchoolCode == paramDto.SchoolCode);
|
||
|
||
if (entity != null)
|
||
{
|
||
entity.EndTime = paramDto.EndTime;
|
||
|
||
_classRoomRecordRepository.Update(entity);
|
||
await _classRoomRecordRepository.SaveChangesAsync();
|
||
}
|
||
|
||
//if (paramDto.HeartRateResults != null && paramDto.HeartRateResults.Count > 0)
|
||
//{
|
||
// var entitys = _mapper.Map<List<Ai_HeartRateData>>(paramDto);
|
||
|
||
// await _heartRateDataRepository.AddRangeAsync(entitys);
|
||
// await _heartRateDataRepository.SaveChangesAsync();
|
||
//}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取学生当前等级
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<StatusLevelExamDto> StatusLevelExam(StatusLevelExamRequest paramDto)
|
||
{
|
||
var maxRankModel = await _levelExamDataRepository.FindAsIQueryable(x => x.SpecialId == paramDto.SpecialId && x.StudentNo == paramDto.StudentNo && x.AssessmentResults == AssessmentResultsEnum.Pass).OrderByDescending(x => x.Rank).FirstOrDefaultAsync();
|
||
|
||
return new StatusLevelExamDto()
|
||
{
|
||
Rank = maxRankModel?.Rank ?? 0
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证学生是否在报名列表中
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<IsActivityInListDto> IsActivityInList(IsActivityInListRequest paramDto)
|
||
{
|
||
if (paramDto == null)
|
||
throw new ArgumentNullException($"参数为空");
|
||
|
||
var studentCount = await _studentRepository.DbContext.Set<G_EntryStudent>().Where(x =>
|
||
x.SchoolCode == paramDto.SchoolCode &&
|
||
x.ActivitiesId == paramDto.ActivitiesId &&
|
||
x.StudentNo == paramDto.StudentNo
|
||
).CountAsync();
|
||
|
||
var res = new IsActivityInListDto()
|
||
{
|
||
ActivitiesId = paramDto.ActivitiesId,
|
||
StudentNo = paramDto.StudentNo,
|
||
IsExist = studentCount > 0
|
||
};
|
||
|
||
return res;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 2.0 接口
|
||
|
||
/// <summary>
|
||
/// Ai一体机扫描登录轮询
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
[HttpPost(nameof(ScanCodeLogin))]
|
||
[HttpPost(nameof(ScanCodeLogin))]
|
||
public async Task<Ai_TeacherFaceInfo> ScanCodeLogin(Ai_Request paramDto)
|
||
{
|
||
if (paramDto == null || string.IsNullOrWhiteSpace(paramDto.Code) || string.IsNullOrWhiteSpace(paramDto.SchoolCode))
|
||
throw new ArgumentException("参数不能为空!");
|
||
|
||
var schoolCode = paramDto.SchoolCode;
|
||
|
||
// 1️⃣ 查询扫码登录信息
|
||
var loginInfo = await _scanCodeLoginRepository
|
||
.FindAsIQueryable(x => x.Code == paramDto.Code && x.SchoolCode == schoolCode)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (loginInfo == null)
|
||
throw new Exception("未查询到登录信息!");
|
||
|
||
// 2️⃣ 获取京师老师信息
|
||
var teacher = await _jingShiTiJiaoService.GetClassListByTeacher(loginInfo.TeacherPhoneNo);
|
||
if (teacher == null || string.IsNullOrWhiteSpace(teacher.TeacherNo) || string.IsNullOrWhiteSpace(teacher.TeacherName))
|
||
throw new Exception("获取京师老师信息失败!");
|
||
|
||
// 3️⃣ 确保老师存在数据库
|
||
var dbTeacher = await _teacherRepository.DbContext.Set<JS_Teacher>()
|
||
.FirstOrDefaultAsync(t => t.TeacherNo == teacher.TeacherNo);
|
||
|
||
if (dbTeacher == null)
|
||
{
|
||
dbTeacher = new JS_Teacher
|
||
{
|
||
TeacherNo = teacher.TeacherNo,
|
||
TeacherName = teacher.TeacherName,
|
||
SchoolCode = paramDto.SchoolCode,
|
||
Code = paramDto.Code
|
||
};
|
||
|
||
await _teacherRepository.DbContext.Set<JS_Teacher>().AddAsync(dbTeacher);
|
||
await _teacherRepository.DbContext.SaveChangesAsync(); // 保存后 Id 可用
|
||
}
|
||
|
||
var gradeDtos = teacher.GradeList ?? new List<GradeDto>();
|
||
var allGradeNos = gradeDtos
|
||
.Where(g => !string.IsNullOrWhiteSpace(g.GradeNo))
|
||
.Select(g => g.GradeNo)
|
||
.ToList();
|
||
|
||
// 4️⃣ 查询数据库已有年级和班级
|
||
var existGrades = await _studentRepository.DbContext.Set<JS_Grade>()
|
||
.Where(x => x.SchoolCode == schoolCode && x.TeacherNo == teacher.TeacherNo && allGradeNos.Contains(x.GradeNo))
|
||
.Include(g => g.Classes)
|
||
.ToListAsync();
|
||
|
||
var existClasses = existGrades.SelectMany(g => g.Classes).ToList();
|
||
|
||
// 5️⃣ 先删除旧班级,再删除旧年级
|
||
if (existClasses.Any())
|
||
_studentRepository.DbContext.Set<JS_Class>().RemoveRange(existClasses);
|
||
|
||
if (existGrades.Any())
|
||
_studentRepository.DbContext.Set<JS_Grade>().RemoveRange(existGrades);
|
||
|
||
await _studentRepository.DbContext.SaveChangesAsync();
|
||
|
||
// 6️⃣ 构造新增年级和班级
|
||
var newGrades = gradeDtos
|
||
.Where(g => !string.IsNullOrWhiteSpace(g.GradeNo))
|
||
.Select(g => new JS_Grade
|
||
{
|
||
TeacherNo = teacher.TeacherNo,
|
||
TeacherName = teacher.TeacherName,
|
||
SchoolCode = schoolCode,
|
||
Code = paramDto.Code,
|
||
GradeNo = g.GradeNo,
|
||
GradeName = g.GradeName,
|
||
Classes = g.ClassList?
|
||
.Where(c => !string.IsNullOrWhiteSpace(c.ClassNo))
|
||
.Select(c => new JS_Class
|
||
{
|
||
TeacherNo = teacher.TeacherNo,
|
||
TeacherName = teacher.TeacherName,
|
||
SchoolCode = schoolCode,
|
||
Code = paramDto.Code,
|
||
GradeNo = g.GradeNo,
|
||
GradeName = g.GradeName,
|
||
ClassNo = c.ClassNo,
|
||
ClassName = c.ClassName
|
||
}).ToList() ?? new List<JS_Class>()
|
||
}).ToList();
|
||
|
||
if (newGrades.Any())
|
||
await _studentRepository.DbContext.Set<JS_Grade>().AddRangeAsync(newGrades);
|
||
|
||
await _studentRepository.DbContext.SaveChangesAsync();
|
||
|
||
// 7️⃣ 使用 EF 跟踪的实体直接返回,不用再查询数据库
|
||
var dbGrades = newGrades;
|
||
|
||
var res = new Ai_TeacherFaceInfo
|
||
{
|
||
Id = (int)dbTeacher.Id,
|
||
TeacherName = teacher.TeacherName,
|
||
Phone = teacher.TeacherNo,
|
||
GradeAndClassList = dbGrades
|
||
.SelectMany(g => g.Classes)
|
||
.Select(c => new Classes
|
||
{
|
||
Id = (int)c.Id,
|
||
Name = $"{c.GradeName}-{c.ClassName}"
|
||
})
|
||
.ToList()
|
||
};
|
||
|
||
// 8️⃣ 删除扫码记录
|
||
_scanCodeLoginRepository.Delete(loginInfo);
|
||
await _scanCodeLoginRepository.SaveChangesAsync();
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 登录
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
public async Task<Ai_TeacherFaceInfo> Login(Ai_LoginRequest paramDto)
|
||
{
|
||
var userInfo = await _userRepository.FindFirstAsync(x => x.UserName == paramDto.UserName && x.UserPwd == paramDto.Password);
|
||
if (userInfo == null)
|
||
throw new Exception("用户名或密码错误");
|
||
|
||
var res = await _teacherRepository.FindAsIQueryable(x => x.SchoolCode == paramDto.SchoolCode && x.TeacherStatus != TeacherStatus.Depart && x.TeacherPhoneNo == userInfo.UserName)
|
||
.Select(x =>
|
||
new Ai_TeacherFaceInfo()
|
||
{
|
||
Id = x.Id,
|
||
Age = x.Age,
|
||
//SchoolCode = x.SchoolCode,
|
||
Sex = x.Sex,
|
||
Phone = x.TeacherPhoneNo,
|
||
TeacherName = x.TeacherName,
|
||
Photo = x.TeacherPhoto,
|
||
}).FirstOrDefaultAsync();
|
||
|
||
if (res == null)
|
||
throw new Exception("未查询到登陆信息");
|
||
|
||
|
||
var grades = await (
|
||
from t in _studentRepository.DbContext.Set<S_ClassAssocTeacher>()
|
||
join c in _studentRepository.DbContext.Set<S_Class>() on t.ClassId equals c.Id into classGroup
|
||
from c in classGroup.DefaultIfEmpty()
|
||
where t.TeacherId == res.Id && c != null
|
||
select new Classes()
|
||
{
|
||
Id = c.Id,
|
||
Name = $"{c.GradeName}-{c.ClassName}",
|
||
}).ToListAsync();
|
||
|
||
res.GradeAndClassList = grades;
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 退出登录
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
public async Task<bool> LogOut(LoginOutDto paramDto)
|
||
{
|
||
var teacher = await _scanCodeLoginRepository.FindAsIQueryable(x => x.Code == paramDto.Code && x.SchoolCode == paramDto.SchoolCode).FirstOrDefaultAsync();
|
||
|
||
if (teacher == null) return true;
|
||
|
||
_scanCodeLoginRepository.Delete(teacher);
|
||
return await _teacherRepository.SaveChangesAsync() > 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取版本号
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
public async Task<Ai_AppVersionDto> AiAppVersion(Ai_AppVersionRequest paramDto)
|
||
{
|
||
var res = await _aiAppVersionRepository.FindAsIQueryable(x => x.AppType == paramDto.AppType)
|
||
.Select(x => new Ai_AppVersionDto()
|
||
{
|
||
Id = x.Id,
|
||
AppType = x.AppType,
|
||
Remarks = x.Remarks,
|
||
Version = x.Version,
|
||
Url = x.Url,
|
||
CreateDate = x.CreateDate
|
||
}).OrderByDescending(x => x.CreateDate)
|
||
.FirstOrDefaultAsync();
|
||
|
||
return res ?? new Ai_AppVersionDto();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取课堂记录列表
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
public async Task<PageDataDto<Ai_ClassRoomRecordPageListDto>> ClassRoomRecordPageList(ClassRoomRecordPageListRequest paramDto)
|
||
{
|
||
var res = new PageDataDto<Ai_ClassRoomRecordPageListDto>();
|
||
|
||
var query = _classRoomRecordRepository.FindAsIQueryable(x => x.Code == paramDto.Code);
|
||
|
||
// 获取总记录数
|
||
res.Total = await query.CountAsync();
|
||
|
||
// 分页查询
|
||
var list = await query
|
||
.OrderByDescending(x => x.StartTime)
|
||
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
|
||
.Take(paramDto.PageSize)
|
||
.Select(x => new Ai_ClassRoomRecordPageListDto
|
||
{
|
||
ClassRoomRecordId = x.Id,
|
||
GradeAndClassName = $"{x.GradeName}-{x.ClassName}",
|
||
StartEndTime = x.EndTime == null || x.EndTime == DateTime.MinValue ? $"{x.StartTime:yyyy-MM-dd HH:mm}" : $"{x.StartTime:yyyy-MM-dd HH:mm} 至 {x.EndTime:yyyy-MM-dd HH:mm}",
|
||
TeacherName = x.TeacherName
|
||
}).ToListAsync();
|
||
|
||
res.Datas = list;
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取课堂阶段列表
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
public async Task<List<ClassroomStageDto>> ClassroomStagePageList(Ai_Request paramDto)
|
||
{
|
||
var res = await _classroomStageRepository.FindAsIQueryable(x => true).Select(x => new ClassroomStageDto()
|
||
{
|
||
Id = x.Id,
|
||
Name = x.Name
|
||
}).ToListAsync();
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加课堂设置
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
public async Task<bool> AddClassroomSetting(AddClassroomSettingRequest paramDto)
|
||
{
|
||
var classroomSettingList = new List<Ai_ClassroomSetting>();
|
||
|
||
foreach (var item in paramDto.ClassroomSettingList)
|
||
{
|
||
classroomSettingList.Add(new Ai_ClassroomSetting()
|
||
{
|
||
ClassRoomRecordId = paramDto.ClassRoomRecordId,
|
||
ClassroomStageId = item.ClassroomStageId,
|
||
Density = item.Density,
|
||
Duration = item.Duration
|
||
});
|
||
}
|
||
|
||
if (classroomSettingList.Count > 0)
|
||
{
|
||
await _classroomSettingRepository.AddRangeAsync(classroomSettingList);
|
||
return await _classroomSettingRepository.SaveChangesAsync() > 0;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新课堂设置
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
public async Task<bool> UpdateClassroomSetting(UpdateClassroomSettingRequest paramDto)
|
||
{
|
||
var classroomSetting = await _classroomSettingRepository.FindAsyncFirst(x => x.ClassRoomRecordId == paramDto.ClassRoomRecordId && x.ClassroomStageId == paramDto.ClassroomStageId);
|
||
|
||
if (classroomSetting == null)
|
||
return false;
|
||
|
||
classroomSetting.Density = paramDto.Density;
|
||
classroomSetting.Duration = paramDto.Duration;
|
||
|
||
_classroomSettingRepository.Update(classroomSetting);
|
||
return await _classroomSettingRepository.SaveChangesAsync() > 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取课堂心率报告
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
public async Task<Ai_HeartRateReportDto> HeartRateReport(HeartRateReportRequest paramDto)
|
||
{
|
||
var res = new Ai_HeartRateReportDto();
|
||
|
||
var query = from hrd in _teacherRepository.DbContext.Set<Ai_HeartRateData>()
|
||
where hrd.ClassRoomRecordId == paramDto.ClassRoomRecordId
|
||
&& (paramDto.ClassRoomStageId <= 0 || hrd.ClassroomStageId == paramDto.ClassRoomStageId)
|
||
select hrd;
|
||
|
||
var heartRateDataList = await query.ToListAsync();
|
||
|
||
//if (heartRateDataList.Count == 0)
|
||
// return res;
|
||
|
||
var classRoom = await _teacherRepository.DbContext.Set<Ai_ClassRoomRecord>().Include(x => x.ClassroomStudentRecord)
|
||
.Where(x => x.SchoolCode == paramDto.SchoolCode && x.Id == paramDto.ClassRoomRecordId)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (classRoom == null)
|
||
{
|
||
throw new Exception("未找到对应的班级记录");
|
||
}
|
||
|
||
var classroomStageList = await (from s in _classroomSettingRepository.DbContext.Set<Ai_ClassroomSetting>()
|
||
join t in _classroomStageRepository.DbContext.Set<Ai_ClassroomStage>()
|
||
on s.ClassroomStageId equals t.Id
|
||
where s.ClassRoomRecordId == paramDto.ClassRoomRecordId
|
||
select new ClassroomStageInfoDto
|
||
{
|
||
ClassroomStageId = s.ClassroomStageId,
|
||
ClassroomStageName = t.Name,
|
||
Duration = s.Duration,
|
||
Density = s.Density
|
||
}).ToListAsync();
|
||
|
||
res.ClassRoomRecordName = classRoom.Name;
|
||
res.ClassroomStageList = classroomStageList;
|
||
|
||
var classRoomStudent = await _teacherRepository.DbContext.Set<Ai_ClassroomStudentRecord>()
|
||
.Where(x => x.SchoolCode == paramDto.SchoolCode && x.ClassRoomRecordId == paramDto.ClassRoomRecordId)
|
||
.ToListAsync();
|
||
|
||
res.GradeAndClass = $"{classRoom.GradeName}-{classRoom.ClassName}";
|
||
res.TeacherName = classRoom.TeacherName;
|
||
res.StartingEndingTime = $"{(classRoom.StartTime.HasValue ? classRoom.StartTime.Value.ToString("yyyy-MM-dd HH:mm") : string.Empty)}{(classRoom.EndTime.HasValue ? " - " + classRoom.EndTime.Value.ToString("yyyy-MM-dd HH:mm") : string.Empty)}";
|
||
res.PeopleNumber = $"{heartRateDataList.GroupBy(x => x.StudentNo).Count()}/{classRoomStudent.Count}";
|
||
res.PeopleNumberBySex = $"{classRoomStudent.Count(x => x.Sex == SexType.Male)}/{classRoomStudent.Count(x => x.Sex == SexType.Female)}";
|
||
|
||
res.AvgHR = heartRateDataList.Count > 0
|
||
? $"{(int)(heartRateDataList.Sum(x => x.Value) / heartRateDataList.Count)} 次/分"
|
||
: "0 次/分";
|
||
|
||
res.Consumption = heartRateDataList.Count > 0 ? $"{Math.Abs(heartRateDataList.Sum(x => x.Consumption ?? 0) / heartRateDataList.Count)} 千卡" : "";
|
||
//res.Density = $"{(int)(heartRateDataList.Where(x => x.Strength > 50).Sum(x => x.Strength) / heartRateDataList.Count)} %";
|
||
|
||
res.Density = $"{(int)Tool.CalculatePercentage(heartRateDataList.Count(x => x.Strength > 50), heartRateDataList.Count)} %";
|
||
res.HighIntensity = $"{heartRateDataList.Where(x => x.Strength > 50).GroupBy(x => x.StudentNo).Count()} 人";
|
||
|
||
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;
|
||
|
||
student.AvgHR = (int)(studentTrainingData.Sum(x => x.Value) / studentTrainingData.Count);
|
||
student.Density = (int)Tool.CalculatePercentage(studentTrainingData.Count(x => x.Strength > 50), studentTrainingData.Count);
|
||
student.Strength = (int)studentTrainingData.Average(x => x.Strength);
|
||
student.Consumption = Math.Abs((int)studentTrainingData.Average(x => x.Consumption ?? 0));
|
||
|
||
studentList.Add(student);
|
||
}
|
||
}
|
||
|
||
res.HeartRateNumber = Tool.GetHeartRateNumber(heartRateDataList);
|
||
res.HeartRateTrend = Tool.GetHeartRateTrend(heartRateDataList);
|
||
res.StudentTrainingRecordList = studentList;
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取学生心率报告
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
public async Task<GetStudentClassReportDetailsModel> StudentHeartRateReport(GetStudentClassReportDetailsDto paramDto)
|
||
{
|
||
var res = new GetStudentClassReportDetailsModel();
|
||
|
||
var query = from hrd in _teacherRepository.DbContext.Set<Ai_HeartRateData>()
|
||
where hrd.SchoolCode == paramDto.SchoolCode &&
|
||
hrd.ClassRoomRecordId == paramDto.ClassRoomRecordId &&
|
||
hrd.StudentNo == paramDto.StudentNo
|
||
select hrd;
|
||
|
||
var heartRateDataList = await query.Select(x => new { x.GradeName, x.StudentNo, x.StudentName, x.Sex, x.ClassName, x.Value, x.Strength, x.Consumption, x.ScoreTime }).ToListAsync();
|
||
|
||
if (heartRateDataList.Count == 0)
|
||
return res;
|
||
|
||
var student = heartRateDataList[0];
|
||
|
||
res.StudentNo = paramDto.StudentNo;
|
||
res.StudentName = student.StudentName;
|
||
res.Sex = student.Sex;
|
||
res.GradeAndClass = $"{student.GradeName}-{student.ClassName}";
|
||
|
||
res.AvgHR = (int)(heartRateDataList.Sum(x => x.Value) / heartRateDataList.Count);
|
||
res.Density = (int)Tool.CalculatePercentage(heartRateDataList.Count(x => x.Strength > 50), heartRateDataList.Count);
|
||
res.Strength = (int)heartRateDataList.Average(x => x.Strength);
|
||
res.Consumption = Math.Abs((int)heartRateDataList.Average(x => x.Consumption ?? 0));
|
||
|
||
//var baseTime = heartRateDataList.Min(x => x.ScoreTime);
|
||
var baseTime = await _teacherRepository.DbContext.Set<Ai_HeartRateData>().Where(x => x.SchoolCode == paramDto.SchoolCode && x.ClassRoomRecordId == paramDto.ClassRoomRecordId).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.Add(new SportsProportionData()
|
||
{
|
||
Name = $"{minute + 1} 分钟",
|
||
Datas = new List<StudentSportsProportionData>
|
||
{
|
||
new StudentSportsProportionData {
|
||
Title = "心率",
|
||
Value = (int)minuteData.Average(x => x.Value)
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 跳绳报告
|
||
/// </summary>
|
||
/// <param name="paramDto"></param>
|
||
/// <returns></returns>
|
||
public async Task<List<Ai_JumpRopeReportDto>> JumpRopeReport(HeartRateReportRequest paramDto)
|
||
{
|
||
var rawData = await _fastJumpRopeDataRepository
|
||
.FindAsIQueryable(x => x.SchoolCode == paramDto.SchoolCode && x.ClassRoomRecordId == paramDto.ClassRoomRecordId)
|
||
.ToListAsync();
|
||
|
||
var result = rawData
|
||
.GroupBy(x => x.GroupId)
|
||
.Select(group =>
|
||
{
|
||
var rankedStudents = group
|
||
.OrderByDescending(x => x.JumpValue ?? 0)
|
||
.Select((x, index) => new Ai_StudentJumpRopeReportListDto
|
||
{
|
||
StudentNo = x.StudentNo,
|
||
StudentName = x.StudentName,
|
||
Ranking = x.Rank ?? 0,
|
||
JumpValue = x.JumpValue
|
||
}).ToList();
|
||
|
||
return new Ai_JumpRopeReportDto
|
||
{
|
||
ModelType = (int)group.First().ModeType,
|
||
ModelName = group.First().ModelName,
|
||
MotionDuration = group.First().MotionDuration ?? 0,
|
||
StudentCount = rankedStudents.Count,
|
||
StudentList = rankedStudents
|
||
};
|
||
})
|
||
.ToList();
|
||
|
||
return result;
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|