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

884 lines
38 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 Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
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.AutofacManager;
using VOL.Core.ManageUser;
using VOL.Core.Utilities;
using VOL.Entity.DomainModels;
using VOL.Entity.DomainModels.Business.People;
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.Request;
using VOL.Model.School.Response;
using VOL.System.IRepositories;
using VOL.System.Repositories;
using static Dapper.SqlMapper;
using static System.Formats.Asn1.AsnWriter;
namespace VOL.Business.Services.School
{
public class S_ClassService : IS_ClassService, IDependency
{
#region
private readonly IMapper _mapper;
private readonly ICacheService _cacheService;
private readonly ICacheQueryService _cacheQueryService;
private readonly IotDataSyncService _iotDataSyncService;
private readonly IS_ClassRepository _classRepository;
private readonly IS_StudentRepository _studentRepository;
private readonly IS_ClassAssocTeacherRepository _classAssocTeacherRepository;
private readonly IN_SportsTestResultRepository _sportsTestResultRepository;
private readonly IN_SportsTestCategoryRepository _sportsTestCategoryRepository;
[ActivatorUtilitiesConstructor]
public S_ClassService(IMapper mapper,
ICacheService cacheService,
ICacheQueryService cacheQueryService,
IS_ClassRepository classRepository,
IS_ClassAssocTeacherRepository classAssocTeacherRepository,
IS_StudentRepository studentRepository,
IN_SportsTestResultRepository sportsTestResultRepository,
IN_SportsTestCategoryRepository sportsTestCategoryRepository,
IotDataSyncService iotDataSyncService)
{
_mapper = mapper;
_cacheService = cacheService;
_classRepository = classRepository;
_cacheQueryService = cacheQueryService;
_classAssocTeacherRepository = classAssocTeacherRepository;
_studentRepository = studentRepository;
_sportsTestResultRepository = sportsTestResultRepository;
_sportsTestCategoryRepository = sportsTestCategoryRepository;
_iotDataSyncService = iotDataSyncService;
}
#endregion
/// <summary>
/// 根据年级Id获取所有班级
/// </summary>
/// <param name="gradeId"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<List<ClassNameModel>> GetClassNames(int gradeId)
{
var list = await (
from g in _classRepository.DbContext.Set<S_Class>()
where g.SchoolCode.Equals(UserContext.Current.TenantId) && g.GradeId == gradeId
select new ClassNameModel()
{
Id = g.Id,
ClassName = g.ClassName
}).OrderBy(x => x.Id).ToListAsync();
return list;
}
/// <summary>
/// 获取班级列表
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<PageDataDto<ClassPageListModel>> GetClassPageList(ClassPageListParam paramDto)
{
var tenantId = UserContext.Current.TenantId;
var teacherClassIds = new List<int>();
var isTeacher = (UserContext.Current.RoleId == 3);
if (isTeacher)
{
var teacher = await _classRepository.DbContext.Set<S_Teacher>().FirstOrDefaultAsync(x => x.SchoolCode == tenantId && x.TeacherPhoneNo == UserContext.Current.UserInfo.PhoneNo);
var teacherClassList = await (
from at in _classRepository.DbContext.Set<S_ClassAssocTeacher>()
join c in _classRepository.DbContext.Set<S_Class>() on at.ClassId equals c.Id
where at.TeacherId == teacher.Id
select c).ToListAsync();
teacherClassIds = teacherClassList.Select(c => c.Id).Distinct().ToList();
}
// 基础班级和年级查询
var query = (from c in _classRepository.DbContext.Set<S_Class>()
join g in _classRepository.DbContext.Set<S_Grade>() on c.GradeId equals g.Id
join a in _classRepository.DbContext.Set<S_SchoolAssocGrade>() on g.Id equals a.GradeId
where c.SchoolCode == tenantId && (!isTeacher || teacherClassIds.Contains(c.Id))
select new
{
c.Id,
c.ClassName,
c.GradeId,
g.GradeName
}).Distinct();
// 条件筛选
if (!string.IsNullOrWhiteSpace(paramDto.ClassName))
{
query = query.Where(x => x.ClassName.Contains(paramDto.ClassName));
}
if (paramDto.GradeId > 0)
{
query = query.Where(x => x.GradeId == paramDto.GradeId);
}
// 获取班级ID列表
var classIds = await query.Select(x => x.Id).ToListAsync();
// 查询教师信息并拼接 TeacherName 和 TeacherPhoneNo
var teacherInfos = await (from assoc in _classRepository.DbContext.Set<S_ClassAssocTeacher>()
join t in _classRepository.DbContext.Set<S_Teacher>() on assoc.TeacherId equals t.Id
where classIds.Contains(assoc.ClassId) && t.SchoolCode.Equals(UserContext.Current.TenantId) && t.TeacherStatus != TeacherStatus.Depart
group t by assoc.ClassId into groupedTeachers
select new
{
ClassId = groupedTeachers.Key,
TeacherNames = string.Join(", ", groupedTeachers.Select(t => t.TeacherName)),
TeacherPhoneNos = string.Join(", ", groupedTeachers.Select(t => t.TeacherPhoneNo))
}).ToListAsync();
// 查询学生数量
var studentCounts = await (from s in _classRepository.DbContext.Set<S_Student>()
where classIds.Contains(s.ClassId) && s.SchoolCode == tenantId
group s by s.ClassId into groupedStudents
select new
{
ClassId = groupedStudents.Key,
Count = groupedStudents.Count()
}).ToListAsync();
// 合并数据
var list = await query
.OrderBy(x => x.Id)
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
.Take(paramDto.PageSize)
.ToListAsync();
var result = list.Select(x =>
{
var teacherInfo = teacherInfos.FirstOrDefault(t => t.ClassId == x.Id);
var studentCount = studentCounts.FirstOrDefault(s => s.ClassId == x.Id)?.Count ?? 0;
return new ClassPageListModel
{
Id = x.Id,
ClassName = x.ClassName,
GradeId = x.GradeId,
GradeName = x.GradeName,
TeacherName = teacherInfo?.TeacherNames ?? "无",
TeacherPhoneNo = teacherInfo?.TeacherPhoneNos ?? "无",
StudentCount = studentCount
};
}).ToList();
// 结果包装
return new PageDataDto<ClassPageListModel>
{
Total = classIds.Count,
Datas = result
};
}
/// <summary>
/// 导出班级
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<List<ClassPageListModel>> GetClassList(ClassPageListExportParam paramDto)
{
var tenantId = UserContext.Current.TenantId;
var teacherClassIds = new List<int>();
var isTeacher = (UserContext.Current.RoleId == 3);
if (isTeacher)
{
var teacher = await _classRepository.DbContext.Set<S_Teacher>().FirstOrDefaultAsync(x => x.SchoolCode == tenantId && x.TeacherPhoneNo == UserContext.Current.UserInfo.PhoneNo);
var teacherClassList = await (
from at in _classRepository.DbContext.Set<S_ClassAssocTeacher>()
join c in _classRepository.DbContext.Set<S_Class>() on at.ClassId equals c.Id
where at.TeacherId == teacher.Id
select c).ToListAsync();
teacherClassIds = teacherClassList.Select(c => c.Id).Distinct().ToList();
}
var query = (from c in _classRepository.DbContext.Set<S_Class>()
join g in _classRepository.DbContext.Set<S_Grade>() on c.GradeId equals g.Id
join a in _classRepository.DbContext.Set<S_SchoolAssocGrade>() on g.Id equals a.GradeId
where c.SchoolCode == tenantId && (!isTeacher || teacherClassIds.Contains(c.Id))
select new
{
c.Id,
c.ClassName,
c.GradeId,
g.GradeName
}).Distinct();
// 条件筛选
if (!string.IsNullOrWhiteSpace(paramDto.ClassName))
{
query = query.Where(x => x.ClassName.Contains(paramDto.ClassName));
}
if (paramDto.GradeId > 0)
{
query = query.Where(x => x.GradeId == paramDto.GradeId);
}
// 获取班级ID列表
var classIds = await query.Select(x => x.Id).ToListAsync();
// 查询教师信息并拼接 TeacherName 和 TeacherPhoneNo
var teacherInfos = await (from assoc in _classRepository.DbContext.Set<S_ClassAssocTeacher>()
join t in _classRepository.DbContext.Set<S_Teacher>() on assoc.TeacherId equals t.Id
where classIds.Contains(assoc.ClassId) && t.SchoolCode.Equals(UserContext.Current.TenantId) && t.TeacherStatus != TeacherStatus.Depart
group t by assoc.ClassId into groupedTeachers
select new
{
ClassId = groupedTeachers.Key,
TeacherNames = string.Join(", ", groupedTeachers.Select(t => t.TeacherName)),
TeacherPhoneNos = string.Join(", ", groupedTeachers.Select(t => t.TeacherPhoneNo))
}).ToListAsync();
// 查询学生数量
var studentCounts = await (from s in _classRepository.DbContext.Set<S_Student>()
where classIds.Contains(s.ClassId) && s.SchoolCode == tenantId
group s by s.ClassId into groupedStudents
select new
{
ClassId = groupedStudents.Key,
Count = groupedStudents.Count()
}).ToListAsync();
var list = await query.OrderBy(x => x.Id).ToListAsync();
var result = list.Select(x =>
{
var teacherInfo = teacherInfos.FirstOrDefault(t => t.ClassId == x.Id);
var studentCount = studentCounts.FirstOrDefault(s => s.ClassId == x.Id)?.Count ?? 0;
return new ClassPageListModel
{
Id = x.Id,
ClassName = x.ClassName,
GradeId = x.GradeId,
GradeName = x.GradeName,
TeacherName = teacherInfo?.TeacherNames ?? "无",
TeacherPhoneNo = teacherInfo?.TeacherPhoneNos ?? "无",
StudentCount = studentCount
};
}).ToList();
return result;
}
/// <summary>
/// 班级详情
/// </summary>
/// <param name="classId"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<ClassDetailsModel> GetClassDetails(int classId)
{
var classModel = await _classRepository.FindAsyncFirst(x => x.Id == classId);
if (classModel == null)
throw new ArgumentNullException("数据不存在");
var teacherList = await _classAssocTeacherRepository.FindAsIQueryable(x => x.ClassId == classId).Select(x => x.TeacherId).ToListAsync();
return new ClassDetailsModel()
{
ClassId = classModel.Id,
GradeId = classModel.GradeId,
TeacherIds = teacherList
};
}
/// <summary>
/// 更新班级
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task ModifyClass(ModifyClassParam paramDto)
{
var tenantId = UserContext.Current.TenantId;
var classModel = await _classRepository.FindAsyncFirst(x => x.Id == paramDto.ClassId);
if (classModel == null)
throw new ArgumentNullException("未找到要更新得数据");
var exist = await _classRepository.ExistsAsync(
x => x.SchoolCode == tenantId
&& x.ClassName == paramDto.ClassName
&& x.GradeId == paramDto.GradeId
&& x.Id != paramDto.ClassId);
if (exist)
throw new Exception("班级名称已存在");
classModel.ClassName = paramDto.ClassName;
using (var transaction = _classRepository.DbContext.Database.BeginTransaction())
{
try
{
_classRepository.Update(classModel);
var teacherList = await _classAssocTeacherRepository.FindAsync(x => x.ClassId == paramDto.ClassId);
_classAssocTeacherRepository.DbContext.RemoveRange(teacherList);
var classAssocTeacherList = new List<S_ClassAssocTeacher>();
paramDto.TeacherIds.ForEach(x =>
{
classAssocTeacherList.Add(new S_ClassAssocTeacher()
{
ClassId = paramDto.ClassId,
TeacherId = x,
Creator = UserContext.Current.UserId,
CreateDate = DateTime.Now,
Modifier = UserContext.Current.UserId,
ModifyDate = DateTime.Now,
});
});
await _classAssocTeacherRepository.AddRangeAsync(classAssocTeacherList);
await _classRepository.SaveChangesAsync();
// 提交事务
transaction.Commit();
//调用回调函数同步数据到IOT
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
//{
// EventType = EventType.Update.GetDisplayName(),
// DataType = IOTDataSyncType.Class.GetDisplayName(),
// Json = JsonConvert.SerializeObject(classModel)
//}));
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
EventType = EventType.Update.GetDisplayName(),
DataType = IOTDataSyncType.Class.GetDisplayName(),
Json = JsonConvert.SerializeObject(classModel)
});
}
catch (Exception ex)
{
// 发生错误,回滚事务
transaction.Rollback();
Console.WriteLine("事务回滚:" + ex.Message);
}
}
}
/// <summary>
/// 添加班级
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task AddClass(AddClassParam paramDto)
{
var tenantId = UserContext.Current.TenantId;
var exist = await _classRepository.ExistsAsync(x => x.SchoolCode == tenantId && x.ClassName == paramDto.ClassName && x.GradeId == paramDto.GradeId);
if (exist)
throw new Exception("班级名称已存在");
var classEntity = new S_Class()
{
GradeId = paramDto.GradeId,
GradeName = paramDto.GradeName,
ClassName = paramDto.ClassName,
Creator = UserContext.Current.UserId,
SchoolCode = UserContext.Current.TenantId,
CreateDate = DateTime.Now
};
using (var transaction = _classRepository.DbContext.Database.BeginTransaction())
{
try
{
await _classRepository.AddAsync(classEntity);
await _classRepository.SaveChangesAsync();
int classId = classEntity.Id;
var classAssocTeacherList = new List<S_ClassAssocTeacher>();
paramDto.TeacherIds.ForEach(x =>
{
classAssocTeacherList.Add(new S_ClassAssocTeacher()
{
ClassId = classId,
TeacherId = x,
Creator = UserContext.Current.UserId,
CreateDate = DateTime.Now,
Modifier = UserContext.Current.UserId,
ModifyDate = DateTime.Now,
});
});
await _classAssocTeacherRepository.AddRangeAsync(classAssocTeacherList);
await _classRepository.SaveChangesAsync();
// 提交事务
transaction.Commit();
//调用回调函数同步数据到IOT
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
//{
// EventType = EventType.Add.GetDisplayName(),
// DataType = IOTDataSyncType.Class.GetDisplayName(),
// Json = JsonConvert.SerializeObject(new List<S_Class>() { classEntity })
//}));
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
EventType = EventType.Add.GetDisplayName(),
DataType = IOTDataSyncType.Class.GetDisplayName(),
Json = JsonConvert.SerializeObject(new List<S_Class>() { classEntity })
});
}
catch (Exception ex)
{
// 发生错误,回滚事务
transaction.Rollback();
Console.WriteLine("事务回滚:" + ex.Message);
}
}
}
/// <summary>
/// 批量添加班级
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task BatchAddClass(BatchAddClassParam paramDto)
{
var tenantId = UserContext.Current.TenantId;
var classEntityList = new List<S_Class>();
var nowTime = DateTime.Now;
for (int i = 0; i < paramDto.ClassCount; i++)
{
var className = $"{(i + 1).ToChineseNumber()}班";
var exist = await _classRepository.ExistsAsync(x => x.SchoolCode == tenantId && x.ClassName == className && x.GradeId == paramDto.GradeId);
if (exist) continue;
var classEntity = new S_Class()
{
GradeId = paramDto.GradeId,
GradeName = paramDto.GradeName,
ClassName = className,
SchoolCode = UserContext.Current.TenantId,
Creator = UserContext.Current.UserId,
CreateDate = nowTime
};
classEntityList.Add(classEntity);
}
using (var transaction = _classRepository.DbContext.Database.BeginTransaction())
{
try
{
await _classRepository.AddRangeAsync(classEntityList);
await _classRepository.SaveChangesAsync();
var addedRecordIds = classEntityList.Select(c => c.Id).ToList();
var classAssocTeacherList = new List<S_ClassAssocTeacher>();
addedRecordIds.ForEach(c =>
{
paramDto.TeacherIds.ForEach(x =>
{
classAssocTeacherList.Add(new S_ClassAssocTeacher()
{
ClassId = c,
TeacherId = x,
Creator = UserContext.Current.UserId,
CreateDate = DateTime.Now,
Modifier = UserContext.Current.UserId,
ModifyDate = DateTime.Now,
});
});
});
await _classAssocTeacherRepository.AddRangeAsync(classAssocTeacherList);
await _classRepository.SaveChangesAsync();
// 提交事务
transaction.Commit();
//调用回调函数同步数据到IOT
//_ = Task.Run(() => _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
//{
// EventType = EventType.Update.GetDisplayName(),
// DataType = IOTDataSyncType.Class.GetDisplayName(),
// Json = JsonConvert.SerializeObject(classEntityList)
//}));
await _iotDataSyncService.DataSyncCallBack(new DataSyncCallBackParam
{
EventType = EventType.Update.GetDisplayName(),
DataType = IOTDataSyncType.Class.GetDisplayName(),
Json = JsonConvert.SerializeObject(classEntityList)
});
}
catch (Exception ex)
{
// 发生错误,回滚事务
transaction.Rollback();
Console.WriteLine("事务回滚:" + ex.Message);
}
}
}
public async Task<ClassDataStatsModel> ClassWholeDataStats(ClassDataStatsParam paramDto)
{
var res = new ClassDataStatsModel();
var tenantId = UserContext.Current.TenantId;
if (!paramDto.ClassId.HasValue || paramDto.ClassId <= 0)
{
paramDto.ClassId = this._classRepository.DbContext.Set<S_Class>().First().Id;
}
var classModel = await (from c in _classRepository.DbContext.Set<S_Class>()
join a in _classRepository.DbContext.Set<S_ClassAssocTeacher>() on c.Id equals a.ClassId into associations
from association in associations.DefaultIfEmpty()
join t in _classRepository.DbContext.Set<S_Teacher>() on association.TeacherId equals t.Id into teachers
from teacher in teachers.DefaultIfEmpty()
where c.Id == paramDto.ClassId && c.SchoolCode.Equals(UserContext.Current.TenantId)
select new ClassPageListModel()
{
Id = c.Id,
GradeId = c.GradeId,
GradeName = c.GradeName,
ClassName = c.ClassName,
TeacherName = teacher.TeacherName,
TeacherPhoneNo = teacher.TeacherPhoneNo
}).FirstOrDefaultAsync();
if (classModel == null)
throw new ArgumentNullException("未找到班级数据");
res.TeacherName = classModel.TeacherName;
res.ClassName = classModel.ClassName;
var students = await _studentRepository.FindAsIQueryable(x => x.ClassId == paramDto.ClassId)
.Select(x => new
{
x.ClassId,
x.StudentNo,
x.StudentName,
x.ClassName,
x.Sex,
x.Age
}).ToListAsync();
res.StudentCount = students.Count;
// 从缓存中获取数据
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync
(
x => x.SchoolCode.Equals(tenantId) && x.ClassId == paramDto.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,
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,
Rank = x.Score.GetRank()
}).ToList();
// 计算总人数
double totalCount = monitorList.Count();
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);
//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;
}
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 }
};
res.TestResultAvg = 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;
}
);
foreach (var stu in students)
{
var stuResults = monitorList.FirstOrDefault(c => c.StudentNo == stu.StudentNo);
res.ClassDetailsList.Add(new ClassDetails()
{
StudentNo = stu.StudentNo,
StudentName = stu.StudentName,
Sex = stu.Sex == SexType.Male ? "男" : "女",
GradeAndClassName = $"{classModel.GradeName}-{classModel.ClassName}",
GradeId = classModel.GradeId,
ClassId = classModel.Id,
Rank = stuResults.Rank
});
}
return res;
}
/// <summary>
/// 各体测项目等级占比
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<Dictionary<string, float>> CategoryRankRatio(CategoryParam paramDto)
{
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x =>
x.GradeId == paramDto.GradeId &&
x.ClassId == paramDto.ClassId &&
x.SchoolCode.Equals(UserContext.Current.TenantId) &&
x.CategoryValue == paramDto.CategoryValue
, paramDto.Mode);
var result = sportsTestResults
.Where(x => x.CategoryValue == paramDto.CategoryValue)
.GroupBy(x => x.Rank)
.ToDictionary(g => g.Key, g => (float)g.Count());
int totalCount = sportsTestResults.Count(x => x.CategoryValue == paramDto.CategoryValue);
if (totalCount == 0)
{
return new Dictionary<string, float>();
}
// 计算比例
foreach (var key in result.Keys.ToList())
{
result[key] = (float)Math.Round(result[key] / totalCount, 2);
}
if (result != null)
{
// 计算并调整最后一个百分比确保总和为100%
var sum = result.Values.Sum(c => c);
var adjustment = 1 - sum;
var lastKey = result.Keys.Last();
result[lastKey] += adjustment;
// 如果最后一个值小于0.01,移除这一项
if (result[lastKey] < 0.01)
{
result.Remove(lastKey);
}
}
return result;
}
/// <summary>
/// 班级体侧等级占比人数
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<ExcellentRateChart> TestResultRankRate(ClassResultRankRate paramDto)
{
var res = new ExcellentRateChart();
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x =>
x.GradeId == paramDto.GradeId &&
x.ClassId == paramDto.ClassId &&
x.RankEnum == paramDto.Rank &&
x.SchoolCode.Equals(UserContext.Current.TenantId)
, paramDto.Mode);
var categoryList = await (from s in _sportsTestResultRepository.DbContext.Set<S_GradeAssocCategory>()
join n in _sportsTestResultRepository.DbContext.Set<N_SportsTestCategory>()
on s.CategoryValue equals n.CategoryValue
where s.GradeId == paramDto.GradeId
select new
{
n.CategoryValue,
n.CategoryName
}).ToListAsync();
foreach (var category in categoryList)
{
var categoryResults = sportsTestResults.Where(x => x.CategoryValue == category.CategoryValue).ToList();
var sexAndOverall = new SexAndOverall
{
FemaleValue = categoryResults.Count(x => x.Sex == SexType.Female),
MaleValue = categoryResults.Count(x => x.Sex == SexType.Male),
OverallValue = categoryResults.Count()
};
res.AxisX.Add(category.CategoryName);
res.AxisY.Add(sexAndOverall);
}
return res;
}
/// <summary>
/// 成绩趋势
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<VariousSportsProportion> ResultTrends(ClassResultTrendsParam paramDto)
{
var sportsTestResults = await _cacheQueryService.GeSportsTestDataCacheAsync(x =>
x.GradeId == paramDto.GradeId &&
x.ClassId == paramDto.ClassId &&
x.SchoolCode.Equals(UserContext.Current.TenantId) &&
x.CategoryValue == paramDto.CategoryValue
, paramDto.Mode);
var result = new VariousSportsProportion();
DateTime currentDate = DateTime.Now;
switch (paramDto.CycleTime)
{
case CycleTimeEnum.InThePastWeek:
// 近一周:按天展示
var pastWeekResults = sportsTestResults
.Where(x => x.ScoreTime >= currentDate.AddDays(-7))
.GroupBy(x => x.ScoreTime.Date);
foreach (var group in pastWeekResults)
{
result.AxisX.Add(group.Key.ToString("yyyy-MM-dd"));
var score = (group.Sum(x => x.Score) + group.Sum(x => x.AdditionalScore)) / (group.Select(x => x.StudentNo).Distinct().Count());
result.AxisY.Add((float)Math.Round(score));
}
break;
case CycleTimeEnum.InThePastTwoWeeks:
// 近两周:按天展示
var pastTwoWeeksResults = sportsTestResults
.Where(x => x.ScoreTime >= currentDate.AddDays(-14))
.GroupBy(x => x.ScoreTime.Date);
foreach (var group in pastTwoWeeksResults)
{
result.AxisX.Add(group.Key.ToString("yyyy-MM-dd"));
var score = (group.Sum(x => x.Score) + group.Sum(x => x.AdditionalScore)) / (group.Select(x => x.StudentNo).Distinct().Count());
result.AxisY.Add((float)Math.Round(score));
}
break;
case CycleTimeEnum.InThePastMonth:
// 近一月每5天一个阶段展示
var pastMonthResults = sportsTestResults
.Where(x => x.ScoreTime >= currentDate.AddDays(-30))
.GroupBy(x => (currentDate - x.ScoreTime).Days / 5);
foreach (var group in pastMonthResults)
{
var minDate = group.Min(r => r.ScoreTime).ToString("yyyy-MM-dd");
var maxDate = group.Max(r => r.ScoreTime).ToString("yyyy-MM-dd");
result.AxisX.Add($"{minDate} - {maxDate}");
var score = (group.Sum(x => x.Score) + group.Sum(x => x.AdditionalScore)) / (group.Select(x => x.StudentNo).Distinct().Count());
result.AxisY.Add((float)Math.Round(score));
}
break;
case CycleTimeEnum.InThePastYear:
// 近一年:按月展示
var pastYearResults = sportsTestResults
.Where(x => x.ScoreTime >= currentDate.AddYears(-1))
.GroupBy(x => new { x.ScoreTime.Year, x.ScoreTime.Month });
foreach (var group in pastYearResults)
{
result.AxisX.Add($"{group.Key.Year}-{group.Key.Month:D2}");
var score = (group.Sum(x => x.Score) + group.Sum(x => x.AdditionalScore)) / (group.Select(x => x.StudentNo).Distinct().Count());
result.AxisY.Add((float)Math.Round(score));
}
break;
default:
// 默认处理,如果没有匹配的情况
break;
}
return result;
}
}
}