From fb6147ecbf234f6754f274da138964307ba0f260 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E8=82=A5=E7=BE=8A?= <1048382248@qq.com>
Date: Wed, 24 Sep 2025 19:17:49 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E7=8F=AD=E7=BA=A7?=
=?UTF-8?q?=E8=80=83=E8=AF=95=E6=88=90=E7=BB=A9=E5=88=86=E6=AE=B5=E5=8A=9F?=
=?UTF-8?q?=E8=83=BD=20=E5=88=A0=E9=99=A4=20=E5=A4=9A=E4=BD=99=E7=9A=84?=
=?UTF-8?q?=E7=8F=AD=E7=BA=A7=E7=B1=BB=E5=9E=8B=E5=AD=97=E6=AE=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Controllers/Dto/ExamClassInfoDto.cs | 15 +-
.../Controllers/ExamClassInfoController.cs | 414 ++++++++++--------
.../Controllers/StudentController.cs | 4 -
.../Model/Dto/UserCenterServiceDto.cs | 15 -
Learn.Archives.Core/Model/ExamClassTag.cs | 5 +
5 files changed, 247 insertions(+), 206 deletions(-)
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
///