1002 lines
42 KiB
C#
1002 lines
42 KiB
C#
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;
|
||
teacherEntity.AppletPwd = "000000";
|
||
|
||
var roleId = UserContext.Current.RoleId;
|
||
|
||
|
||
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 = roleId == 2 ? 3 : 5,
|
||
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;
|
||
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;
|
||
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();
|
||
|
||
res.ExcellentRate = totalCount > 0 ? Math.Round((monitorList.Count(x => x.Rank == "优秀") / totalCount) * 100) : 0;
|
||
res.FineRate = totalCount > 0 ? Math.Round((monitorList.Count(x => x.Rank == "良好") / totalCount) * 100) : 0;
|
||
res.PassRate = totalCount > 0 ? Math.Round((monitorList.Count(x => x.Rank == "及格") / totalCount) * 100) : 0;
|
||
res.FailRate = totalCount > 0 ? Math.Round((monitorList.Count(x => x.Rank == "不及格") / totalCount) * 100) : 0;
|
||
|
||
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;
|
||
|
||
// 获取所有班级的学生人数
|
||
var classStudentCounts = await (
|
||
from s in _classRepository.DbContext.Set<S_Student>()
|
||
where teacherModel.ClassIds.Contains(s.ClassId)
|
||
group s by s.ClassId into g
|
||
select new
|
||
{
|
||
ClassId = g.Key,
|
||
StudentCount = g.Count()
|
||
}
|
||
).ToDictionaryAsync(x => x.ClassId, x => x.StudentCount);
|
||
|
||
// 获取所有班级的教学次数
|
||
var classTeachingTimes = await (
|
||
from r in _classRepository.DbContext.Set<Ai_ClassRoomRecord>()
|
||
where r.TeacherId == paramDto.TeacherId && teacherModel.ClassIds.Contains(r.ClassId)
|
||
group r by r.ClassId into g
|
||
select new
|
||
{
|
||
ClassId = g.Key,
|
||
TeachingTimes = g.Count()
|
||
}
|
||
).ToDictionaryAsync(x => x.ClassId, x => x.TeachingTimes);
|
||
|
||
foreach (var c in grades)
|
||
{
|
||
if (!c.ClassId.HasValue)
|
||
continue;
|
||
|
||
// 从字典中获取当前班级的学生人数
|
||
var totalStudentsInClass = classStudentCounts.TryGetValue(c.ClassId.Value, out var count) ? count : 0;
|
||
|
||
// 从字典中获取当前班级的教学次数
|
||
var accumulatedTeachingTimes = classTeachingTimes.TryGetValue(c.ClassId.Value, out var teachingTimes) ? teachingTimes : 0;
|
||
|
||
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 sexAndOverall = new SexAndOverall
|
||
{
|
||
FemaleValue = CalculatePassRate(totalPassedFemale, totalFemale),
|
||
MaleValue = CalculatePassRate(totalPassedMale, totalMale),
|
||
OverallValue = CalculatePassRate(totalPassedOverall, totalStudentsInClass)
|
||
};
|
||
|
||
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 = totalStudentsInClass,
|
||
TeacherName = teacherModel.TeacherName,
|
||
AccumulatedTeachingTimes = accumulatedTeachingTimes,
|
||
PassRate = CalculatePassRate(totalPassedOverall, totalStudentsInClass)
|
||
});
|
||
}
|
||
|
||
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
|
||
};
|
||
|
||
// 计算目标季度和年份
|
||
var targetQuarter = currentQuarter - quarterOffset;
|
||
var targetYear = currentYear;
|
||
|
||
// 处理跨年情况
|
||
if (targetQuarter < 1)
|
||
{
|
||
targetQuarter += 4; // 调整季度
|
||
targetYear--; // 调整年份
|
||
}
|
||
else if (targetQuarter > 4)
|
||
{
|
||
targetQuarter -= 4; // 调整季度
|
||
targetYear++; // 调整年份
|
||
}
|
||
|
||
var startDate = Tool.GetQuarterStartDate(targetQuarter, targetYear);
|
||
var endDate = Tool.GetQuarterEndDate(targetQuarter, targetYear);
|
||
|
||
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;
|
||
}
|
||
}
|
||
}
|