2025-06-06 16:00:39 +08:00

960 lines
41 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

using AutoMapper;
using Castle.DynamicProxy.Generators;
using Google.Protobuf.Collections;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System.Linq;
using System.Threading;
using VOL.Business.IServices.Norm;
using VOL.Business.IServices.School;
using VOL.Core.CacheManager;
using VOL.Core.Configuration;
using VOL.Core.Extensions;
using VOL.Core.Extensions.AutofacManager;
using VOL.Core.ManageUser;
using VOL.Core.Utilities;
using VOL.Entity.DomainModels;
using VOL.Entity.Enum;
using VOL.Model;
using VOL.Model.Ai;
using VOL.Model.IOT.Request;
using VOL.Model.Norm.Response;
using VOL.Model.School.Response;
using VOL.System.IRepositories;
using VOL.System.Repositories;
using static Dapper.SqlMapper;
namespace VOL.Business.Services.School
{
public class S_TeacherService : IS_TeacherService, IDependency
{
#region
private readonly IMapper _mapper;
private readonly ICacheService _cacheService;
private readonly ICacheQueryService _cacheQueryService;
private readonly IotDataSyncService _iotDataSyncService;
private readonly IS_TeacherRepository _teacherRepository;
private readonly ISys_UserRepository _sys_UserRepository;
private readonly IS_ClassAssocTeacherRepository _classAssocTeacherRepository;
private readonly IS_StudentRepository _studentRepository;
private readonly IN_SportsTestCategoryRepository _sportsTestCategoryRepository;
private readonly IN_SportsTestResultRepository _sportsTestResultRepository;
private readonly IS_ClassRepository _classRepository;
[ActivatorUtilitiesConstructor]
public S_TeacherService(IMapper mapper,
ICacheService cacheService,
ICacheQueryService cacheQueryService,
IS_TeacherRepository teacherRepository,
ISys_UserRepository sys_UserRepository,
IS_ClassAssocTeacherRepository classAssocTeacherRepository,
IS_StudentRepository studentRepository,
IN_SportsTestCategoryRepository sportsTestCategoryRepository,
IN_SportsTestResultRepository sportsTestResultRepository,
IS_ClassRepository classRepository,
IotDataSyncService iotDataSyncService)
{
_mapper = mapper;
_cacheService = cacheService;
_cacheQueryService = cacheQueryService;
_teacherRepository = teacherRepository;
_sys_UserRepository = sys_UserRepository;
_classAssocTeacherRepository = classAssocTeacherRepository;
_studentRepository = studentRepository;
_sportsTestCategoryRepository = sportsTestCategoryRepository;
_sportsTestResultRepository = sportsTestResultRepository;
_classRepository = classRepository;
_iotDataSyncService = iotDataSyncService;
}
#endregion
public async Task<List<TeacherNameModel>> GetTeacherNames()
{
var isTeacher = (UserContext.Current.RoleId == 3);
var list = await _teacherRepository.FindAsIQueryable(x =>
x.SchoolCode.Equals(UserContext.Current.TenantId) &&
x.TeacherStatus != TeacherStatus.Depart &&
(!isTeacher || x.TeacherPhoneNo == UserContext.Current.UserInfo.PhoneNo)
).Select(x => new TeacherNameModel()
{
Id = x.Id,
TeacherPhone = x.TeacherPhoneNo,
TeacherName = x.TeacherName
}).ToListAsync();
return list;
}
public async Task<List<TeacherListByGradeIdModel>> GetTeacherNamesByGradeId(TeacherListByGradeIdParam paramDto)
{
var query = from t in _teacherRepository.DbContext.Set<S_Teacher>()
join a in _teacherRepository.DbContext.Set<S_ClassAssocTeacher>()
on t.Id equals a.TeacherId into assoc
from a in assoc.DefaultIfEmpty()
join c in _teacherRepository.DbContext.Set<S_Class>()
on a.ClassId equals c.Id into classes
from c in classes.DefaultIfEmpty()
where t.SchoolCode.Equals(UserContext.Current.TenantId)
&& t.TeacherStatus != TeacherStatus.Depart
select new TeacherListByGradeIdModel()
{
Id = t.Id,
TeacherName = t.TeacherName,
TeacherPhone = t.TeacherPhoneNo,
GradeId = c != null ? c.GradeId : 0,
ClassId = c != null ? c.Id : 0
};
if (paramDto.GradeId.HasValue)
{
query = query.Where(x => x.GradeId == paramDto.GradeId);
}
if (paramDto.ClassId.HasValue)
{
query = query.Where(x => x.ClassId == paramDto.ClassId);
}
var list = await query
.GroupBy(x => x.Id)
.Select(g => new TeacherListByGradeIdModel
{
Id = g.Key,
TeacherName = g.FirstOrDefault().TeacherName,
TeacherPhone = g.FirstOrDefault().TeacherPhone,
GradeId = g.FirstOrDefault().GradeId,
ClassId = g.FirstOrDefault().ClassId
})
.OrderBy(x => x.Id)
.ToListAsync();
return list;
}
public async Task<List<TeacherPageListModel>> GetTeacherList(TeacherExportParam paramDto)
{
var res = new PageDataDto<TeacherPageListModel>();
// 主查询,仅查询教师表
var query = _teacherRepository.DbContext.Set<S_Teacher>()
.Where(t => t.SchoolCode.Equals(UserContext.Current.TenantId) && t.TeacherStatus != TeacherStatus.Depart)
.Select(t => new TeacherPageListModel()
{
Id = t.Id,
PhoneNo = t.TeacherPhoneNo,
TeacherName = t.TeacherName,
TeacherStatus = t.TeacherStatus,
InductionDate = t.InductionDate,
Sex = t.Sex
});
// 过滤条件
if (!string.IsNullOrWhiteSpace(paramDto.TeacherName))
{
query = query.Where(x => x.TeacherName.Contains(paramDto.TeacherName));
}
if (!string.IsNullOrWhiteSpace(paramDto.PhoneNo))
{
query = query.Where(x => x.PhoneNo.Contains(paramDto.PhoneNo));
}
if (paramDto.Sex > 0)
{
query = query.Where(x => x.Sex == paramDto.Sex);
}
if (paramDto.TeacherStatus > 0)
{
query = query.Where(x => x.TeacherStatus == paramDto.TeacherStatus);
}
var list = await query.OrderBy(x => x.Id).ToListAsync();
// 统计每个教师的班级和学生数量
foreach (var item in list)
{
var assocTeachers = _teacherRepository.DbContext.Set<S_ClassAssocTeacher>()
.Where(at => at.TeacherId == item.Id);
// 学生数量
item.StudentCount = (from at in assocTeachers
join s in _teacherRepository.DbContext.Set<S_Student>() on at.ClassId equals s.ClassId
select s.Id).Distinct().Count();
// 班级数量
item.ClassCount = assocTeachers.Select(at => at.ClassId).Distinct().Count();
// 按年级分组的班级信息
var groupedClassIdsByGrade = (from at in assocTeachers
join c in _teacherRepository.DbContext.Set<S_Class>() on at.ClassId equals c.Id
group at.ClassId by c.GradeId into groupedData
select new
{
GradeId = groupedData.Key,
ClassIds = groupedData.ToList()
}).ToList();
item.GradeAndClassIds = groupedClassIdsByGrade.ToDictionary(x => x.GradeId, x => x.ClassIds);
}
return list;
}
public async Task<PageDataDto<TeacherPageListModel>> GetTeacherPageList(TeacherPageListParam paramDto)
{
var res = new PageDataDto<TeacherPageListModel>();
// 主查询,仅查询教师表
var query = _teacherRepository.DbContext.Set<S_Teacher>()
.Where(t => t.SchoolCode.Equals(UserContext.Current.TenantId) && t.TeacherStatus != TeacherStatus.Depart)
.Select(t => new TeacherPageListModel()
{
Id = t.Id,
PhoneNo = t.TeacherPhoneNo,
TeacherName = t.TeacherName,
TeacherStatus = t.TeacherStatus,
InductionDate = t.InductionDate,
Sex = t.Sex,
TeacherPhoto = t.TeacherPhoto,
});
// 过滤条件
if (!string.IsNullOrWhiteSpace(paramDto.TeacherName))
{
query = query.Where(x => x.TeacherName.Contains(paramDto.TeacherName));
}
if (!string.IsNullOrWhiteSpace(paramDto.PhoneNo))
{
query = query.Where(x => x.PhoneNo.Contains(paramDto.PhoneNo));
}
if (paramDto.Sex > 0)
{
query = query.Where(x => x.Sex == paramDto.Sex);
}
if (paramDto.TeacherStatus > 0)
{
query = query.Where(x => x.TeacherStatus == paramDto.TeacherStatus);
}
// 获取总数用于分页
res.Total = await query.CountAsync();
// 分页数据
var list = await query
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
.Take(paramDto.PageSize)
.OrderBy(x => x.Id)
.ToListAsync();
// 统计每个教师的班级和学生数量
foreach (var item in list)
{
var assocTeachers = _teacherRepository.DbContext.Set<S_ClassAssocTeacher>()
.Where(at => at.TeacherId == item.Id);
// 学生数量
item.StudentCount = (from at in assocTeachers
join s in _teacherRepository.DbContext.Set<S_Student>() on at.ClassId equals s.ClassId
select s.Id).Distinct().Count();
// 班级数量
item.ClassCount = assocTeachers.Select(at => at.ClassId).Distinct().Count();
// 按年级分组的班级信息
var groupedClassIdsByGrade = (from at in assocTeachers
join c in _teacherRepository.DbContext.Set<S_Class>() on at.ClassId equals c.Id
group at.ClassId by c.GradeId into groupedData
select new
{
GradeId = groupedData.Key,
ClassIds = groupedData.ToList()
}).ToList();
item.GradeAndClassIds = groupedClassIdsByGrade.ToDictionary(x => x.GradeId, x => x.ClassIds);
}
res.Datas = list;
return res;
}
public async Task AddTeacher(AddTeacherParam paramDto)
{
var tenantId = UserContext.Current.TenantId;
var teacherExists = await _teacherRepository.ExistsAsync(x => x.SchoolCode == tenantId && x.TeacherPhoneNo == paramDto.TeacherPhoneNo);
if (teacherExists)
throw new Exception($"手机号{paramDto.TeacherPhoneNo}的老师已存在!");
var teacherEntity = _mapper.Map<S_Teacher>(paramDto);
teacherEntity.TeacherStatus = TeacherStatus.Normal;
teacherEntity.SchoolCode = UserContext.Current.TenantId;
teacherEntity.Creator = UserContext.Current.UserId;
teacherEntity.CreateDate = DateTime.Now;
using (var transaction = _teacherRepository.DbContext.Database.BeginTransaction())
{
try
{
await _teacherRepository.AddAsync(teacherEntity);
await _teacherRepository.SaveChangesAsync();
int teacherId = teacherEntity.Id;
var userEntity = new Sys_User()
{
Role_Id = 3,
RoleName = "学校老师",
PhoneNo = paramDto.TeacherPhoneNo,
SchoolName = UserContext.Current.SchoolName,
UserTrueName = paramDto.TeacherName,
Enable = 1,
UserName = paramDto.TeacherPhoneNo,
//UserPwd = paramDto.Password.EncryptDES(AppSetting.Secret.User),
UserPwd = paramDto.Password,
CreateID = teacherId,
SchoolCode = tenantId,
CreateDate = DateTime.Now
};
await _sys_UserRepository.AddAsync(userEntity);
var classAssocTeacherList = new List<S_ClassAssocTeacher>();
if (paramDto.ClassIds != null && paramDto.ClassIds.Count > 0)
{
paramDto.ClassIds.ForEach(x =>
{
classAssocTeacherList.Add(new S_ClassAssocTeacher()
{
ClassId = x,
TeacherId = teacherId,
Creator = UserContext.Current.UserId,
CreateDate = DateTime.Now,
Modifier = UserContext.Current.UserId,
ModifyDate = DateTime.Now,
});
});
await _classAssocTeacherRepository.AddRangeAsync(classAssocTeacherList);
await _sys_UserRepository.SaveChangesAsync();
}
// 提交事务
transaction.Commit();
var teacherJson = new object[]
{
new
{
teacherEntity.Id,
teacherEntity.SchoolCode,
teacherEntity.TeacherName,
teacherEntity.Age,
teacherEntity.Sex,
teacherEntity.TeacherStatus,
teacherEntity.TeacherPhoto,
teacherEntity.InductionDate,
teacherEntity.TeacherPhoneNo,
teacherEntity.Ology,
teacherEntity.AccumulatedTeachingTimes,
teacherEntity.AppletPwd,
teacherEntity.Remarks,
paramDto.ClassIds
}
};
//调用回调函数同步数据到IOT
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
//{
// EventType = EventType.Add.GetDisplayName(),
// DataType = IOTDataSyncType.Teacher.GetDisplayName(),
// Json = JsonConvert.SerializeObject(new List<S_Teacher>() { teacherEntity })
//}));
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
EventType = EventType.Add.GetDisplayName(),
DataType = IOTDataSyncType.Teacher.GetDisplayName(),
//Json = JsonConvert.SerializeObject(new List<S_Teacher>() { teacherJson }),
Json = JsonConvert.SerializeObject(teacherJson)
});
}
catch (Exception ex)
{
transaction.Rollback();
throw new Exception($"新增失败:{ex.Message}");
}
}
}
public async Task ModifyTeacher(AddTeacherParam paramDto)
{
var tenantId = UserContext.Current.TenantId;
var teacherModel = await _teacherRepository.FindAsyncFirst(x => x.Id == paramDto.Id);
if (teacherModel == null)
throw new ArgumentNullException("未找到要更新的数据");
var teacherExists = await _teacherRepository.ExistsAsync(x => x.SchoolCode == tenantId && x.TeacherPhoneNo == paramDto.TeacherPhoneNo && x.Id != teacherModel.Id);
if (teacherExists)
throw new Exception($"手机号{paramDto.TeacherPhoneNo}的老师已存在!");
teacherModel.TeacherName = paramDto.TeacherName;
teacherModel.TeacherPhoneNo = paramDto.TeacherPhoneNo;
teacherModel.TeacherPhoto = paramDto.TeacherPhoto;
teacherModel.InductionDate = paramDto.InductionDate;
teacherModel.Sex = paramDto.Sex;
teacherModel.Modifier = UserContext.Current.UserId;
teacherModel.ModifyDate = DateTime.Now;
//var userModel = await _sys_UserRepository.FindAsyncFirst(x => x.PhoneNo == paramDto.TeacherPhoneNo);
//if (userModel == null)
// throw new ArgumentNullException("未找到要更新的数据");
//userModel.UserPwd = paramDto.Password;
//userModel.PhoneNo = paramDto.TeacherPhoneNo;
var classAssocTeacherList = await _classAssocTeacherRepository.FindAsync(x => x.TeacherId == teacherModel.Id);
using (var transaction = _teacherRepository.DbContext.Database.BeginTransaction())
{
try
{
_teacherRepository.Update(teacherModel);
//_sys_UserRepository.Update(userModel);
if (classAssocTeacherList.Count > 0)
_classAssocTeacherRepository.DbContext.RemoveRange(classAssocTeacherList);
var classAssocTeacherEntitys = new List<S_ClassAssocTeacher>();
paramDto.ClassIds.ForEach(x =>
{
classAssocTeacherEntitys.Add(new S_ClassAssocTeacher()
{
ClassId = x,
TeacherId = teacherModel.Id,
Creator = teacherModel.Id,
CreateDate = DateTime.Now,
Modifier = teacherModel.Id,
ModifyDate = DateTime.Now,
});
});
if (classAssocTeacherEntitys.Count > 0)
await _classAssocTeacherRepository.AddRangeAsync(classAssocTeacherEntitys);
await _teacherRepository.SaveChangesAsync();
// 提交事务
transaction.Commit();
var teacherJson = new
{
teacherModel.Id,
teacherModel.SchoolCode,
teacherModel.TeacherName,
teacherModel.Age,
teacherModel.Sex,
teacherModel.TeacherStatus,
teacherModel.TeacherPhoto,
teacherModel.InductionDate,
teacherModel.TeacherPhoneNo,
teacherModel.Ology,
teacherModel.AccumulatedTeachingTimes,
teacherModel.AppletPwd,
teacherModel.Remarks,
paramDto.ClassIds
};
//调用回调函数同步数据到IOT
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
//{
// EventType = EventType.Update.GetDisplayName(),
// DataType = IOTDataSyncType.Teacher.GetDisplayName(),
// Json = JsonConvert.SerializeObject(teacherJson)
//}));
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
EventType = EventType.Update.GetDisplayName(),
DataType = IOTDataSyncType.Teacher.GetDisplayName(),
Json = JsonConvert.SerializeObject(teacherJson)
});
}
catch (Exception ex)
{
// 发生错误,回滚事务
transaction.Rollback();
throw new Exception("事务回滚:" + ex.Message);
}
}
}
public async Task UpdateTeacherStatus(UpdateTeacherStatusParam paramDto)
{
var teacher = await _teacherRepository.FindAsyncFirst(x => x.TeacherPhoneNo == paramDto.TeacherPhoneNo);
if (teacher == null)
throw new ArgumentNullException("未找到要更新的数据");
teacher.TeacherStatus = paramDto.Status;
_studentRepository.Update(teacher);
await _studentRepository.SaveChangesAsync();
var classIds = await _classAssocTeacherRepository.FindAsIQueryable(x => x.TeacherId == teacher.Id).Select(x => x.ClassId).ToListAsync();
var teacherJson = new
{
teacher.Id,
teacher.SchoolCode,
teacher.TeacherName,
teacher.Age,
teacher.Sex,
teacher.TeacherStatus,
teacher.TeacherPhoto,
teacher.InductionDate,
teacher.TeacherPhoneNo,
teacher.Ology,
teacher.AccumulatedTeachingTimes,
teacher.AppletPwd,
teacher.Remarks,
ClassIds = classIds
};
//调用回调函数同步数据到IOT
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
//{
// EventType = EventType.Update.GetDisplayName(),
// DataType = IOTDataSyncType.Teacher.GetDisplayName(),
// Json = JsonConvert.SerializeObject(teacherJson)
//}));
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
EventType = EventType.Update.GetDisplayName(),
DataType = IOTDataSyncType.Teacher.GetDisplayName(),
Json = JsonConvert.SerializeObject(teacherJson)
});
}
public async Task UpdateTeacherPwd(UpdateTeacherPwdParam paramDto)
{
var teacher = await _teacherRepository.FindAsyncFirst(x => x.TeacherPhoneNo == paramDto.TeacherPhoneNo);
if (teacher == null)
throw new ArgumentNullException("未找到要更新的数据");
teacher.AppletPwd = AppSetting.OriginalPwd;
var user = await _sys_UserRepository.FindAsyncFirst(x => x.UserName == paramDto.TeacherPhoneNo);
if (user == null)
throw new ArgumentNullException("未找到该用户");
user.UserPwd = teacher.AppletPwd.EncryptDES(AppSetting.Secret.User);
user.LastLoginDate = DateTime.Now;
_sys_UserRepository.Update(user);
_studentRepository.Update(teacher);
await _studentRepository.SaveChangesAsync();
await _sys_UserRepository.SaveChangesAsync();
var classIds = await _classAssocTeacherRepository.FindAsIQueryable(x => x.TeacherId == teacher.Id).Select(x => x.ClassId).ToListAsync();
var teacherJson = new
{
teacher.Id,
teacher.SchoolCode,
teacher.TeacherName,
teacher.Age,
teacher.Sex,
teacher.TeacherStatus,
teacher.TeacherPhoto,
teacher.InductionDate,
teacher.TeacherPhoneNo,
teacher.Ology,
teacher.AccumulatedTeachingTimes,
teacher.AppletPwd,
teacher.Remarks,
ClassIds = classIds
};
//调用回调函数同步数据到IOT
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
//{
// EventType = EventType.Update.GetDisplayName(),
// DataType = IOTDataSyncType.Teacher.GetDisplayName(),
// Json = JsonConvert.SerializeObject(teacherJson)
//}));
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
EventType = EventType.Update.GetDisplayName(),
DataType = IOTDataSyncType.Teacher.GetDisplayName(),
Json = JsonConvert.SerializeObject(teacherJson)
});
}
/// <summary>
/// 上传老师头像
/// </summary>
public async Task<string> UploadTeacherPhoto(IFormFile file, string teacherPhoneNo, string teacherName)
{
// 设置照片最大允许大小 (5MB)
const long MaxFileSize = 2 * 1024 * 1024;
// 检查文件大小是否超过限制
if (file.Length > MaxFileSize)
{
throw new Exception("上传的照片文件大小不能超过2MB");
}
var url = ALiYunOss.Upload(file, $"Upload/{UserContext.Current.TenantId}/Photo/Teacher/", teacherPhoneNo);
var faceEntityWithRequest = new FaceEntityWithDto()
{
EntityId = teacherPhoneNo,
SchoolCode = UserContext.Current.TenantId,
IsStudent = false
};
await ALiYunFace.DeleteFaceEntityWith(faceEntityWithRequest);
var faceEntityWithReuslt = await ALiYunFace.FaceEntityWith(faceEntityWithRequest);
if (!faceEntityWithReuslt)
{
throw new Exception("上传失败");
}
var faceWithReuslt = await ALiYunFace.FaceWith(new FaceWithDto()
{
SchoolCode = UserContext.Current.TenantId,
Name = teacherName,
IsStudent = false,
EntityId = teacherPhoneNo,
ImageUrl = url
});
if (!faceWithReuslt)
{
throw new Exception("上传失败");
}
return url;
}
public async Task ResetPassword(int teacherId)
{
var user = await _sys_UserRepository.FindAsyncFirst(x => x.User_Id == teacherId);
if (user == null)
throw new ArgumentNullException("未找到该用户");
user.UserPwd = AppSetting.OriginalPwd.EncryptDES(AppSetting.Secret.User);
user.LastLoginDate = DateTime.Now;
_sys_UserRepository.Update(user);
await _sys_UserRepository.SaveChangesAsync();
var teacher = await _teacherRepository.FindAsyncFirst(x => x.Id == teacherId);
if (teacher == null)
throw new ArgumentNullException("未找到要更新的数据");
var classIds = await _classAssocTeacherRepository.FindAsIQueryable(x => x.TeacherId == teacher.Id).Select(x => x.ClassId).ToListAsync();
var teacherJson = new
{
teacher.Id,
teacher.SchoolCode,
teacher.TeacherName,
teacher.Age,
teacher.Sex,
teacher.TeacherStatus,
teacher.TeacherPhoto,
teacher.InductionDate,
teacher.TeacherPhoneNo,
teacher.Ology,
teacher.AccumulatedTeachingTimes,
AppletPwd = "123456",
teacher.Remarks,
ClassIds = classIds
};
//调用回调函数同步数据到IOT
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
//{
// EventType = EventType.Update.GetDisplayName(),
// DataType = IOTDataSyncType.Teacher.GetDisplayName(),
// Json = JsonConvert.SerializeObject(user)
//}));
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
EventType = EventType.Update.GetDisplayName(),
DataType = IOTDataSyncType.Teacher.GetDisplayName(),
Json = JsonConvert.SerializeObject(user)
});
}
/// <summary>
/// 教师统计
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public async Task<TeacherDataStatsModel> TeacherDataStats(TeacherDataStatsParam paramDto)
{
var res = new TeacherDataStatsModel();
var tenantId = UserContext.Current.TenantId;
if (!paramDto.TeacherId.HasValue || paramDto.TeacherId <= 0)
{
paramDto.TeacherId = this._teacherRepository.DbContext.Set<S_Teacher>().First().Id;
}
var teacherModel = await (from t in _teacherRepository.DbContext.Set<S_Teacher>()
join a in _teacherRepository.DbContext.Set<S_ClassAssocTeacher>() on t.Id equals a.TeacherId
join s in _teacherRepository.DbContext.Set<S_Student>() on a.ClassId equals s.ClassId
where t.Id == paramDto.TeacherId && t.SchoolCode.Equals(UserContext.Current.TenantId)
group new { t, a } by new { t.Id } into groupedData
select new
{
groupedData.Key.Id,
TeacherName = groupedData.Select(x => x.t.TeacherName).FirstOrDefault(),
AccumulatedTeachingTimes = groupedData.Select(x => x.t.AccumulatedTeachingTimes).FirstOrDefault(),
StudentCount = groupedData.Count(),
ClassCount = groupedData.Select(x => x.a.ClassId).Distinct().Count(),
ClassIds = groupedData.Select(x => x.a.ClassId).Distinct().ToList()
}).FirstOrDefaultAsync();
if (teacherModel == null)
throw new ArgumentNullException("未找到老师数据");
res.TeacherName = teacherModel.TeacherName;
res.ClassCount = teacherModel.ClassCount;
res.StudentCount = teacherModel.StudentCount;
var grades = await (
from g in _classRepository.DbContext.Set<S_Grade>()
join c in _classRepository.DbContext.Set<S_Class>() on g.Id equals c.GradeId into classGroup
from c in classGroup.DefaultIfEmpty()
where teacherModel.ClassIds.Contains(c.Id) && c.SchoolCode.Equals(UserContext.Current.TenantId)
select new GradeAndClassNames
{
ClassId = c.Id,
GradeAndClassName = $"{g.GradeName}{c.ClassName}"
}).ToListAsync();
var classIds = grades.Select(x => x.ClassId).ToList();
// 从缓存中获取数据
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.SchoolCode.Equals(tenantId) && x.TeacherId == paramDto.TeacherId && classIds.Contains(x.ClassId), paramDto.Mode);
var monitorList = sportsTestResults
.GroupBy(x => new { x.StudentNo })
.Select(g => new
{
g.Key.StudentNo,
g.First().Sex,
g.First().ClassId,
g.First().ClassName,
g.First().GradeId,
g.First().GradeName,
g.First().TeacherId,
g.First().TeacherName,
g.First().ClassRoomRecordId,
g.First().ScoreTime,
Score = (g.Sum(x => x.Score) + g.Sum(x => x.AdditionalScore)) / (g.Select(x => x.CategoryEnum).Distinct().Count())
})
.Select(x => new
{
x.StudentNo,
x.Sex,
x.ClassId,
x.ClassName,
x.GradeId,
x.GradeName,
x.TeacherId,
x.TeacherName,
x.ClassRoomRecordId,
x.Score,
x.ScoreTime,
Rank = x.Score.GetRank()
}).ToList();
// 计算总人数
double totalCount = monitorList.Count();
//var sportsTestResults = await _sportsTestResultRepository.FindAsIQueryable(x => x.TeacherId == paramDto.TeacherId && x.SchoolCode.Equals(UserContext.Current.TenantId)).ToListAsync();
//var totalCount = sportsTestResults.Count();
//res.ExcellentRate = totalCount == 0 ? 0 : Math.Truncate((double)sportsTestResults.Count(x => x.Rank == "优秀") / totalCount * 100);
//res.FineRate = totalCount == 0 ? 0 : Math.Truncate((double)sportsTestResults.Count(x => x.Rank == "良好") / totalCount * 100);
//res.PassRate = totalCount == 0 ? 0 : Math.Truncate((double)sportsTestResults.Count(x => x.Rank == "及格") / totalCount * 100);
//res.FailRate = totalCount == 0 ? 0 : Math.Truncate((double)sportsTestResults.Count(x => x.Rank == "不及格") / totalCount * 100);
res.ExcellentRate = Math.Round(monitorList.Count(x => x.Rank == "优秀") / totalCount * 100);
res.FineRate = Math.Round(monitorList.Count(x => x.Rank == "良好") / totalCount * 100);
res.PassRate = Math.Round(monitorList.Count(x => x.Rank == "及格") / totalCount * 100);
if (res != null)
{
// 计算并调整最后一个百分比确保总和为100%
double sum = (res.ExcellentRate + res.FineRate + res.PassRate + res.FailRate);
double adjustment = 100 - sum;
res.FailRate += totalCount > 0 ? adjustment : 0;
}
float CalculatePassRate(int passed, int total) => total > 0 ? (float)Math.Truncate((double)passed / total * 100) / 100 : 0;
foreach (var c in grades)
{
var classResults = monitorList.Where(x => x.ClassId == c.ClassId).ToList();
var totalFemale = classResults.Count(x => x.Sex == SexType.Female);
var totalMale = classResults.Count(x => x.Sex == SexType.Male);
var totalPassedFemale = classResults.Count(x => x.Sex == SexType.Female && x.Rank != "不及格");
var totalPassedMale = classResults.Count(x => x.Sex == SexType.Male && x.Rank != "不及格");
var totalPassedOverall = classResults.Count(x => x.Rank != "不及格");
var totalClassResults = classResults.Count();
var sexAndOverall = new SexAndOverall
{
FemaleValue = CalculatePassRate(totalPassedFemale, totalFemale),
MaleValue = CalculatePassRate(totalPassedMale, totalMale),
OverallValue = CalculatePassRate(totalPassedOverall, totalClassResults)
};
res.TestResultPassRate.AxisX.Add(c.GradeAndClassName);
res.TestResultPassRate.AxisY.Add(sexAndOverall);
var classResult = classResults.FirstOrDefault();
var result = classResults
.GroupBy(c => c.ScoreTime)
.Select(g => new
{
ScoreTime = g.Key,
Count = g.Count()
})
.ToList();
res.TeacherDetailsList.Add(new TeacherDetails()
{
ClassId = c.ClassId,
GradeAndClassName = c.GradeAndClassName,
Count = classResults.Count(),
TeacherName = teacherModel.TeacherName,
AccumulatedTeachingTimes = result.Count,
PassRate = CalculatePassRate(totalPassedOverall, totalClassResults)
});
}
return res;
}
/// <summary>
/// 班级体测平均成绩
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
public async Task<Dictionary<string, float>> TestResultAvg(ClassDataStatsParam paramDto)
{
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.ClassId == paramDto.ClassId && x.SchoolCode.Equals(UserContext.Current.TenantId), paramDto.Mode);
var now = DateTime.Now;
var currentQuarter = (now.Month - 1) / 3 + 1;
var currentYear = now.Year;
// 处理跨年情况
var quarters = new[]
{
new { Label = "本季度", Quarter = currentQuarter, Year = currentYear },
new { Label = "上季度", Quarter = currentQuarter - 1 == 0 ? 4 : currentQuarter - 1, Year = currentQuarter == 1 ? currentYear - 1 : currentYear },
new { Label = "前季度", Quarter = currentQuarter - 2 == 0 ? 4 : currentQuarter - 2 == -1 ? 3 : currentQuarter - 2, Year = currentQuarter <= 2 ? currentYear - 1 : currentYear }
};
return quarters.ToDictionary(
q => q.Label,
q =>
{
var filteredResults = sportsTestResults
.Where(x => x.ScoreTime >= Tool.GetQuarterStartDate(q.Quarter, q.Year) && x.ScoreTime <= Tool.GetQuarterEndDate(q.Quarter, q.Year))
.Select(x => x.Score)
.ToList();
return filteredResults.Any() ? filteredResults.Average() : 0;
}
);
}
/// <summary>
/// 各班级授课次数占比
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<Dictionary<string, float>> ClassTeachingCountRatio(QuarterlyParam paramDto)
{
var res = new Dictionary<string, float>();
var now = DateTime.Now;
var currentQuarter = (now.Month - 1) / 3 + 1;
var currentYear = now.Year;
// 定义 sportsTestResults 变量
List<SportsTestValueModel> sportsTestResults = new List<SportsTestValueModel>();
// 根据 QuarterlyCycle 选择不同的查询范围
var quarterOffset = paramDto.QuarterlyCycle switch
{
QuarterlyCycleEnum.ForTheQuarter => 0,
QuarterlyCycleEnum.PreviousQuarter => 1,
QuarterlyCycleEnum.LastQuarter => 2,
_ => 0
};
// 如果 quarterOffset 非 0 时才执行查询
if (quarterOffset >= 0)
{
var startDate = Tool.GetQuarterStartDate(currentQuarter - quarterOffset, currentYear);
var endDate = Tool.GetQuarterEndDate(currentQuarter - quarterOffset, currentYear);
sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x => x.TeacherId == paramDto.TeacherId &&
x.SchoolCode == UserContext.Current.TenantId &&
x.ScoreTime >= startDate &&
x.ScoreTime <= endDate, paramDto.Mode);
}
// 分组并计算每个分组的 Count
var groupResult = sportsTestResults
.GroupBy(c => new { c.ClassId, c.ClassName, c.GradeName })
.Select(g => new
{
g.Key.ClassId,
g.Key.ClassName,
g.Key.GradeName,
Count = g.DistinctBy(x => x.ScoreTime).Count()
})
.ToList();
// 计算总数
var totalCount = groupResult.Sum(gr => gr.Count);
// 生成结果字典
res = groupResult.ToDictionary(
gr => $"{gr.GradeName}{gr.ClassName}",
gr => totalCount > 0 ? (float)gr.Count / totalCount : 0f
);
return res;
}
}
}