diff --git a/Learn.Archives.API/Controllers/Dto/ExamClassInfoDto.cs b/Learn.Archives.API/Controllers/Dto/ExamClassInfoDto.cs index a6b065e..a18a342 100644 --- a/Learn.Archives.API/Controllers/Dto/ExamClassInfoDto.cs +++ b/Learn.Archives.API/Controllers/Dto/ExamClassInfoDto.cs @@ -1,7 +1,15 @@ -using MiniExcelLibs.Attributes; +using Learn.Archives.Core.Model; +using MiniExcelLibs.Attributes; namespace Learn.Archives.API.Controllers.Dto { + public class ExamClassTagReq : ExamClassTag + { + /// + /// 学科类型 + /// + public string SubjectStr => SubjectId?.ToString() ?? "总分"; + } public class ImportExamDto { /// @@ -46,11 +54,6 @@ namespace Learn.Archives.API.Controllers.Dto [ExcelColumnName("云校班级号")] public string Class { get; set; } /// - /// - /// - [ExcelColumnName("班级类型")] - public string ClassType { get; set; } - /// /// 学生姓名 /// [ExcelColumnName("学生姓名")] diff --git a/Learn.Archives.API/Controllers/ExamClassInfoController.cs b/Learn.Archives.API/Controllers/ExamClassInfoController.cs index b474e78..4abca20 100644 --- a/Learn.Archives.API/Controllers/ExamClassInfoController.cs +++ b/Learn.Archives.API/Controllers/ExamClassInfoController.cs @@ -27,13 +27,14 @@ namespace Learn.Archives.API.Controllers readonly Repository examService; readonly Repository schoolService; readonly Repository tagService; + readonly Repository classTagService; readonly Repository examUserInfoService; readonly LiveUserInfo userInfo; readonly IHttpContextAccessor accessor; public ExamClassInfoController(Repository baseService, LiveUserInfo userInfo, - IHttpContextAccessor httpContext, Repository examUserInfoService, - Repository examService, Repository schoolService, - Repository tagService) : base(baseService) + IHttpContextAccessor httpContext, Repository examUserInfoService, + Repository examService, Repository schoolService, + Repository tagService, Repository classTagService) : base(baseService) { this.baseService = baseService; this.userInfo = userInfo; @@ -42,37 +43,9 @@ namespace Learn.Archives.API.Controllers this.examService = examService; this.schoolService = schoolService; this.tagService = tagService; + this.classTagService = classTagService; } - [NonAction] - private Dictionary? ImportExamInfoSubjectDic(ImportExamInfo info) - { - return new Dictionary() - { - { SubjectEnum.语文, info.语文}, - { SubjectEnum.数学, info.数学}, - { SubjectEnum.英语, info.英语}, - { SubjectEnum.物理, info.物理}, - { SubjectEnum.化学, info.化学}, - { SubjectEnum.生物, info.生物}, - { SubjectEnum.政治, info.政治}, - { SubjectEnum.历史, info.历史}, - { SubjectEnum.地理, info.地理}, - }; - } - [NonAction] - private static decimal? SubjectScore(ExamUserInfo info,SubjectEnum? s) - { - switch (s) - { - case null: - return info.AssignScore; - default: - if (info?.SubjectDic is null) - return -999; - return info.SubjectDic.ContainsKey(s.Value)? info.SubjectDic?[s.Value] : -999 ; - } - } /// /// 导入考试信息 /// @@ -136,14 +109,14 @@ namespace Learn.Archives.API.Controllers !p.DeleteState && !c.DeleteState && !u.DeleteState && !s.DeleteState) .Select((s, c, p, pr, u) => new { - Name = c.Name + c.Type.ToString() + u.RealName, + Name = c.Name + u.RealName, u.Id, }).ToDictionaryAsync(s => s.Name, s => s.Id); //处理学生成绩数据 var userList = dataList.Select(s => { var classInfo = classArr - .FirstOrDefault(x => x.Name == s.Class && x.Type == s.ClassType.ToEnum()); + .FirstOrDefault(x => x.Name == s.Class ); if (classInfo == null) { s.Error = "未能匹配班级"; @@ -152,7 +125,7 @@ namespace Learn.Archives.API.Controllers } var grade = GradeHelper.GetStudentGradeBaseByGrade(s.Grade); var sub = ImportExamInfoSubjectDic(s); - var name = s.Class + s.ClassType.ToEnum().GetHashCode() + s.Student; + var name = s.Class + s.Student; if (!userDic.ContainsKey(name)) { s.Error = "未能匹配到年级班级下对应的学生"; @@ -198,151 +171,6 @@ namespace Learn.Archives.API.Controllers return Ok(); } - /// - /// 计算考试成绩 - /// - /// - /// - /// - /// - [NonAction] - public static async Task CalculatingTestResults(Exam exam, Repository eUService, - Repository sService, Repository tagService) - { - var userInfoArr = await eUService.AsQueryable() - .Where(s => s.ExamId == exam.Id) - .ToArrayAsync(); - - var insertTotalClassInfo = new List(); - var insertTotalClassTag = new List(); - var eTagArr = await tagService.AsQueryable().Where(s => s.ExamId == exam.Id) - .ToArrayAsync(); - var db = sService.Context; - foreach (var schoolArr in userInfoArr.GroupBy(s => s.SchoolId)) - { - - var insertClassInfo = new List(); - var insertClassTag = new List(); - var school = await sService.GetFirstAsync(s => s.Id == schoolArr.Key); - var classArr = await db.Queryable().Where(c => c.SchoolId == school.Id && - c.GradeLevel == exam.GradeLevel && - c.GraduationYear == exam.GradeYear && !c.DeleteState).ToArrayAsync(); - - foreach (var classUserArr in userInfoArr.GroupBy(s => s.ClassId)) - { - var classInfo = classArr.First(s => s.Id == classUserArr.Key); - var eCInfo = new ExamClassInfo() - { - ExamId = exam.Id, - ExamName = exam.Name, - SchoolId = classInfo.SchoolId, - SchoolName = school.Name, - ClassId = classInfo.Id, - ClassName = classInfo.Name, - GradeLevel = classInfo.GradeLevel, - GradeYear = classInfo.GraduationYear, - PeopleCount = classUserArr.Count(), - MinScore = int.MaxValue, - MaxScore = -99, - BaseSchoolScore = exam.BaseSchoolScore, - TestPaperType = exam.TestPaperType, - Type = exam.Type, - Average1 = exam.BaseSchoolScore, - }; - insertClassInfo.Add(eCInfo); - var avgTotal = 0m; - - //todo 班级分段分析 - var classTagDic = new Dictionary(); - foreach (var eUserInfo in classUserArr) - { - if (!classTagDic.TryGetValue(eUserInfo.ClassId, out ExamClassTag[]? classTagArr)) - { - classTagArr = new ExamClassTag[10]; - classTagDic.Add(eUserInfo.ClassId, classTagArr); - } - //上线人数 - foreach (var item in eTagArr) - { - var subV = SubjectScore(eUserInfo, item.SubjectId); - //总分分段 - if (subV >= item.MinScore && subV <= item.MaxScore) - { - var tag = classTagArr[(int)(item.SubjectId ?? 0)]; - if (tag is null) - { - tag = new ExamClassTag() - { - MaxScore = item.MaxScore, - MinScore = item.MinScore, - ExamId =exam.Id, - ExamTagId = item.Id, - Name = item.TagName, - SubjectId = item.SubjectId - }; - insertClassTag.Add(tag); - classTagArr[(int)(item.SubjectId ?? 0)]= tag; - } - classTagArr[(int)(item.SubjectId ?? 0)].OnLineCount++; - } - - } - var v = eUserInfo.AssignScore; - //最大小分 - if (v < eCInfo.MinScore) - eCInfo.MinScore = v; - if (v > eCInfo.MaxScore) - eCInfo.MaxScore = v; - avgTotal += v;//追加得分 - } - //总分平均分 - eCInfo.Average = avgTotal / eCInfo.PeopleCount; - //计算上线率 - if(classTagDic.ContainsKey(eCInfo.ClassId)) - foreach (var item in classTagDic[eCInfo.ClassId]) - item.OnLineRate = (decimal)item.OnLineCount / (decimal)eCInfo.PeopleCount; - } - insertTotalClassInfo.AddRange(insertClassInfo); - insertTotalClassTag.AddRange(insertClassTag); - } - - { //计算班级上线率排名 - foreach (var examTagArr in insertTotalClassTag.GroupBy(s => s.ExamTagId)) - { - var i = 0; - foreach (var item in examTagArr.OrderByDescending(s => s.OnLineRate) - .GroupBy(s => s.OnLineRate)) - { - foreach (var u in item) - u.OnLineRanking = ++i; - } - } - - //计算年级平均分排名 - var i = 0; - foreach (var item in insertTotalClassInfo.OrderByDescending(s => s.Average) - .GroupBy(s => s.Average)) - { - foreach (var u in item) - u.AverageRank = ++i; - } - } - //写入数据库 - var baseDB = eUService.Context; - baseDB.Ado.BeginTran(); - try - { - await baseDB.Deleteable().Where(s=>s.ExamId==exam.Id).ExecuteCommandAsync(); - await baseDB.Insertable(insertTotalClassInfo).ExecuteCommandAsync(); - baseDB.Ado.CommitTran(); - } - catch (Exception ex) - { - baseDB.Ado.RollbackTran(); - Oh.ModelError($"导入失败:写入数据时候出现了异常 [{ex.Message}] !"); - } - - } /// /// 下载导入成绩模板 @@ -355,7 +183,6 @@ namespace Learn.Archives.API.Controllers { School="例子学校[导入时候请删除]", Class="测试班级", - ClassType="普通班级", Grade="高2028", Student="学生姓名", 语文=80.5m, @@ -418,5 +245,230 @@ namespace Learn.Archives.API.Controllers } return base.PageList(model); } + + + + /// + /// 重新计算考试成绩排名 + /// + /// 考试id + /// + [HttpGet] + public async Task RecalculateExamRankings(long examId) + { + if (examId == 0) + Oh.ModelError("传入了异常参数"); + var exam = examService.GetById(examId); + if (exam is null) + Oh.ModelError("无效的考试"); + await CalculatingTestResults(exam, examUserInfoService, schoolService, tagService); + return Ok(); + + } + + + /// + /// 获取班级考试分段排名 + /// + /// 考试id + /// + [HttpGet] + public async Task> ClassRanking(long examId,long classId) + { + if (examId == 0) + Oh.ModelError("传入异常参数"); + if (! await examService.IsAnyAsync(s => s.Id == examId)) + Oh.ModelError("无效的考试"); + var arr = await classTagService.AsQueryable().Where(s => s.ExamId == examId && s.ClassId == classId) + .Select() + .ToArrayAsync(); + return arr.OrderBy(s => s.SubjectId); + } + + + + + + [NonAction] + private Dictionary? ImportExamInfoSubjectDic(ImportExamInfo info) + { + return new Dictionary() + { + { SubjectEnum.语文, info.语文}, + { SubjectEnum.数学, info.数学}, + { SubjectEnum.英语, info.英语}, + { SubjectEnum.物理, info.物理}, + { SubjectEnum.化学, info.化学}, + { SubjectEnum.生物, info.生物}, + { SubjectEnum.政治, info.政治}, + { SubjectEnum.历史, info.历史}, + { SubjectEnum.地理, info.地理}, + }; + } + [NonAction] + private static decimal? SubjectScore(ExamUserInfo info, SubjectEnum? s) + { + switch (s) + { + case null: + return info.AssignScore; + default: + if (info?.SubjectDic is null) + return -999; + return info.SubjectDic.ContainsKey(s.Value) ? info.SubjectDic?[s.Value] : -999; + } + } + + /// + /// 计算考试成绩 + /// + /// + /// + /// + /// + [NonAction] + public static async Task CalculatingTestResults(Exam exam, Repository eUService, + Repository sService, Repository tagService) + { + var userInfoArr = await eUService.AsQueryable() + .Where(s => s.ExamId == exam.Id) + .ToArrayAsync(); + + var insertTotalClassInfo = new List(); + var insertTotalClassTag = new List(); + var eTagArr = await tagService.AsQueryable().Where(s => s.ExamId == exam.Id) + .ToArrayAsync(); + var db = sService.Context; + foreach (var schoolArr in userInfoArr.GroupBy(s => s.SchoolId)) + { + + var insertClassInfo = new List(); + var insertClassTag = new List(); + var school = await sService.GetFirstAsync(s => s.Id == schoolArr.Key); + var classArr = await db.Queryable().Where(c => c.SchoolId == school.Id && + c.GradeLevel == exam.GradeLevel && + c.GraduationYear == exam.GradeYear && !c.DeleteState).ToArrayAsync(); + + foreach (var classUserArr in userInfoArr.GroupBy(s => s.ClassId)) + { + var classInfo = classArr.First(s => s.Id == classUserArr.Key); + var eCInfo = new ExamClassInfo() + { + ExamId = exam.Id, + ExamName = exam.Name, + SchoolId = classInfo.SchoolId, + SchoolName = school.Name, + ClassId = classInfo.Id, + ClassName = classInfo.Name, + GradeLevel = classInfo.GradeLevel, + GradeYear = classInfo.GraduationYear, + PeopleCount = classUserArr.Count(), + MinScore = int.MaxValue, + MaxScore = -99, + BaseSchoolScore = exam.BaseSchoolScore, + TestPaperType = exam.TestPaperType, + Type = exam.Type, + Average1 = exam.BaseSchoolScore, + }; + insertClassInfo.Add(eCInfo); + var avgTotal = 0m; + + //todo 班级分段分析 + var classTagDic = new Dictionary(); + foreach (var eUserInfo in classUserArr) + { + if (!classTagDic.TryGetValue(eUserInfo.ClassId, out ExamClassTag[]? classTagArr)) + { + classTagArr = new ExamClassTag[10]; + classTagDic.Add(eUserInfo.ClassId, classTagArr); + } + //上线人数 + foreach (var item in eTagArr) + { + var subV = SubjectScore(eUserInfo, item.SubjectId); + //总分分段 + if (subV >= item.MinScore && subV <= item.MaxScore) + { + var tag = classTagArr[(int)(item.SubjectId ?? 0)]; + if (tag is null) + { + tag = new ExamClassTag() + { + MaxScore = item.MaxScore, + MinScore = item.MinScore, + ClassId = classInfo.Id, + ExamId = exam.Id, + ExamTagId = item.Id, + Name = item.TagName, + SubjectId = item.SubjectId + }; + insertClassTag.Add(tag); + classTagArr[(int)(item.SubjectId ?? 0)] = tag; + } + classTagArr[(int)(item.SubjectId ?? 0)].OnLineCount++; + } + + } + var v = eUserInfo.AssignScore; + //最大小分 + if (v < eCInfo.MinScore) + eCInfo.MinScore = v; + if (v > eCInfo.MaxScore) + eCInfo.MaxScore = v; + avgTotal += v;//追加得分 + } + //总分平均分 + eCInfo.Average = avgTotal / eCInfo.PeopleCount; + //计算上线率 + if (classTagDic.ContainsKey(eCInfo.ClassId)) + foreach (var item in classTagDic[eCInfo.ClassId]) + if(item !=null) item.OnLineRate = (decimal)item.OnLineCount / (decimal)eCInfo.PeopleCount; + } + insertTotalClassInfo.AddRange(insertClassInfo); + insertTotalClassTag.AddRange(insertClassTag); + } + + { + + var i = 0; + //计算班级上线率排名 + foreach (var examTagArr in insertTotalClassTag.GroupBy(s => s.ExamTagId)) + { + i = 0; + foreach (var item in examTagArr.OrderByDescending(s => s.OnLineRate) + .GroupBy(s => s.OnLineRate)) + { + foreach (var u in item) + u.OnLineRanking = ++i; + } + } + + //计算年级平均分排名 + i = 0; + foreach (var item in insertTotalClassInfo.OrderByDescending(s => s.Average) + .GroupBy(s => s.Average)) + { + foreach (var u in item) + u.AverageRank = ++i; + } + } + //写入数据库 + var baseDB = eUService.Context; + baseDB.Ado.BeginTran(); + try + { + await baseDB.Deleteable().Where(s => s.ExamId == exam.Id).ExecuteCommandAsync(); + await baseDB.Deleteable().Where(s => s.ExamId == exam.Id).ExecuteCommandAsync(); + await baseDB.Insertable(insertTotalClassInfo).ExecuteCommandAsync(); + await baseDB.Insertable(insertTotalClassTag).ExecuteCommandAsync(); + baseDB.Ado.CommitTran(); + } + catch (Exception ex) + { + baseDB.Ado.RollbackTran(); + Oh.ModelError($"导入失败:写入数据时候出现了异常 [{ex.Message}] !"); + } + + } } } diff --git a/Learn.Archives.API/Controllers/StudentController.cs b/Learn.Archives.API/Controllers/StudentController.cs index d74102e..6f65129 100644 --- a/Learn.Archives.API/Controllers/StudentController.cs +++ b/Learn.Archives.API/Controllers/StudentController.cs @@ -221,7 +221,6 @@ namespace Learn.Archives.API.Controllers School = s.School, Grade = gStr, Class = s.Class, - ClassType = s.ClassType??ClassTypeEnum.云校班.ToString(), Phone = s.Phone, RealName = s.RealName, Stages = s.Grade.Contains("初") ? StudentStagesEnum.初中.ToString() : StudentStagesEnum.高中.ToString() @@ -302,7 +301,6 @@ namespace Learn.Archives.API.Controllers School = s.School, Grade = gStr, Class = s.Class, - ClassType = s.ClassType??ClassTypeEnum.云校班.ToString(), ExamNo = s.Id.ToString(), Phone = s.Phone, RealName = s.RealName, @@ -353,7 +351,6 @@ namespace Learn.Archives.API.Controllers School = "必填:与系统匹配", Grade = "必填:可选值\r\n[初一初二初三,高一高二高山]", Class = "必填:与系统匹配\r\n格式:10班[数字+班]", - ClassType = "必填:可选值\r\n[云校班 海豚智学班 蓝鲸智库班 中职班 其他 雅思班 点阵笔班级 移动校园班级 智学班 ...]", Status = "选填 可选值\r\n[就读,退出]", AmountRelief ="选填: 为0则视为 '未申请减免'", ReliefType ="选填: 建卡贫困户\r\n低保户\r\n教师子女 \r\n孤儿\r\n艺体生\r\n残疾学生\r\n领导特殊承诺减免\r\n领导同意的特殊贫困减免", @@ -385,7 +382,6 @@ namespace Learn.Archives.API.Controllers School = "必填:与系统匹配", Grade = "必填:可选值\r\n[初一初二初三,高一高二高山]", Class = "必填:与系统匹配\r\n格式:10班[数字+班]\r\n任教类型是年级主任时不填", - ClassType = "必填:可选值\r\n[云校班 海豚智学班 蓝鲸智库班 中职班 其他 雅思班 点阵笔班级 移动校园班级 智学班 ...]\r\n任教类型是年级主任时不填", Subject = "选填学科", ExamNo ="选填: 填写老师任职信息[不在授课架构中的职务]", }}; diff --git a/Learn.Archives.Core/Model/Dto/UserCenterServiceDto.cs b/Learn.Archives.Core/Model/Dto/UserCenterServiceDto.cs index 1b4b135..19ca055 100644 --- a/Learn.Archives.Core/Model/Dto/UserCenterServiceDto.cs +++ b/Learn.Archives.Core/Model/Dto/UserCenterServiceDto.cs @@ -83,11 +83,6 @@ namespace Learn.Archives.Core.Model.Dto /// [ExcelColumn(Name = "班级", Width = 15)] public string Class { get; set; } - /// - /// 班级类型 - /// - [ExcelColumn(Name = "班级类型", Width = 20)] - public string ClassType { get; set; } /// /// 科目 @@ -161,11 +156,6 @@ namespace Learn.Archives.Core.Model.Dto /// [ExcelColumn(Name="班级", Width = 15)] public string Class { get; set; } - /// - /// 班级 - /// - [ExcelColumn(Name="班级类型", Width = 20)] - public string ClassType { get; set; } /// /// 减免金额 @@ -295,11 +285,6 @@ namespace Learn.Archives.Core.Model.Dto [ExcelColumn(Name="班级")] public string Class { get; set; } /// - /// 班级 - /// - [ExcelColumn(Name="班级类型")] - public string ClassType { get; set; } - /// /// 科目 /// [ExcelColumn(Name="科目")] diff --git a/Learn.Archives.Core/Model/ExamClassTag.cs b/Learn.Archives.Core/Model/ExamClassTag.cs index 9cefd5c..b14b668 100644 --- a/Learn.Archives.Core/Model/ExamClassTag.cs +++ b/Learn.Archives.Core/Model/ExamClassTag.cs @@ -24,6 +24,11 @@ namespace Learn.Archives.Core.Model [SugarColumn(Length = 20)] public long ExamId { get; set; } + /// + /// 班级id + /// + public long ClassId { get; set; } + /// /// 考试标签id ///