新增 班级考试成绩分段功能

删除 多余的班级类型字段
This commit is contained in:
小肥羊 2025-09-24 19:17:49 +08:00
parent 43a16815ca
commit fb6147ecbf
5 changed files with 247 additions and 206 deletions

View File

@ -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
{
/// <summary>
/// 学科类型
/// </summary>
public string SubjectStr => SubjectId?.ToString() ?? "总分";
}
public class ImportExamDto
{
/// <summary>
@ -46,11 +54,6 @@ namespace Learn.Archives.API.Controllers.Dto
[ExcelColumnName("云校班级号")]
public string Class { get; set; }
/// <summary>
///
/// </summary>
[ExcelColumnName("班级类型")]
public string ClassType { get; set; }
/// <summary>
/// 学生姓名
/// </summary>
[ExcelColumnName("学生姓名")]

View File

@ -27,13 +27,14 @@ namespace Learn.Archives.API.Controllers
readonly Repository<Exam> examService;
readonly Repository<School> schoolService;
readonly Repository<ExamTags> tagService;
readonly Repository<ExamClassTag> classTagService;
readonly Repository<ExamUserInfo> examUserInfoService;
readonly LiveUserInfo userInfo;
readonly IHttpContextAccessor accessor;
public ExamClassInfoController(Repository<ExamClassInfo> baseService, LiveUserInfo userInfo,
IHttpContextAccessor httpContext, Repository<ExamUserInfo> examUserInfoService,
Repository<Exam> examService, Repository<School> schoolService,
Repository<ExamTags> tagService) : base(baseService)
Repository<ExamTags> tagService, Repository<ExamClassTag> 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<SubjectEnum, decimal>? ImportExamInfoSubjectDic(ImportExamInfo info)
{
return new Dictionary<SubjectEnum, decimal>()
{
{ 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 ;
}
}
/// <summary>
/// 导入考试信息
/// </summary>
@ -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<ClassTypeEnum>());
.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<ClassTypeEnum>().GetHashCode() + s.Student;
var name = s.Class + s.Student;
if (!userDic.ContainsKey(name))
{
s.Error = "未能匹配到年级班级下对应的学生";
@ -198,6 +171,154 @@ namespace Learn.Archives.API.Controllers
return Ok();
}
/// <summary>
/// 下载导入成绩模板
/// </summary>
/// <returns></returns>
[HttpGet, ResultIgnore, AllowAnonymous]
public IActionResult DwImportTemplate()
{
List<ImportExamInfo> resultList = new List<ImportExamInfo>() { new ImportExamInfo()
{
School="例子学校[导入时候请删除]",
Class="测试班级",
Grade="高2028",
Student="学生姓名",
=80.5m,
=80.5m,
=80m,
= 80m,
= 80m,
= 80m,
= 80m,
= 80m,
= 80.5m,
=721.5m
} };
return File(resultList.ExportExcel(), "application/ms-excel",
$"导入成绩模板{DateTime.Now.ToString("MMddHHmm")}.xlsx");
}
/// <summary>
/// 删除班级考试信息
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> DeleteExamInfo(RestartEntryDto dto)
{
if (dto.ClassId == 0 || dto.ExamId == 0)
Oh.ModelError("传入了异常参数");
var exam = examService.GetById(dto.ExamId);
if (exam is null)
Oh.ModelError("传入了无效的考试");
var dCount = await baseService.AsDeleteable().Where(s => s.ClassId == dto.ClassId)
.ExecuteCommandAsync();
var dCount1 = await examUserInfoService.AsDeleteable().Where(s => s.ClassId == dto.ClassId)
.ExecuteCommandAsync();
return Ok();
}
public override Task<dynamic> PageList([FromBody] QueryRequestBase model)
{
var c = model.Conditions.FirstOrDefault(s => s.FieldName == "Grade");
if (c != null)
{
var gInfo = GradeHelper.GetStudentGradeBaseByGrade(c.FieldValue);
if (gInfo != null)
{
model.Conditions = model.Conditions.Where(s => s != c).ToList();
model.Conditions.Add(new SqlSugar.ConditionalModel()
{
FieldName = "GradeLevel",
FieldValue = gInfo.GradeLevel,
});
model.Conditions.Add(new SqlSugar.ConditionalModel()
{
FieldName = "GradeYear",
FieldValue = gInfo.GradeYear.ToString(),
CSharpTypeName="int"
});
}
}
return base.PageList(model);
}
/// <summary>
/// 重新计算考试成绩排名
/// </summary>
/// <param name="examId">考试id</param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> 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();
}
/// <summary>
/// 获取班级考试分段排名
/// </summary>
/// <param name="examId">考试id</param>
/// <returns></returns>
[HttpGet]
public async Task<IEnumerable<ExamClassTagReq>> 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<ExamClassTagReq>()
.ToArrayAsync();
return arr.OrderBy(s => s.SubjectId);
}
[NonAction]
private Dictionary<SubjectEnum, decimal>? ImportExamInfoSubjectDic(ImportExamInfo info)
{
return new Dictionary<SubjectEnum, decimal>()
{
{ 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;
}
}
/// <summary>
/// 计算考试成绩
/// </summary>
@ -209,9 +330,9 @@ namespace Learn.Archives.API.Controllers
public static async Task CalculatingTestResults(Exam exam, Repository<ExamUserInfo> eUService,
Repository<School> sService, Repository<ExamTags> tagService)
{
var userInfoArr = await eUService.AsQueryable()
.Where(s => s.ExamId == exam.Id)
.ToArrayAsync();
var userInfoArr = await eUService.AsQueryable()
.Where(s => s.ExamId == exam.Id)
.ToArrayAsync();
var insertTotalClassInfo = new List<ExamClassInfo>();
var insertTotalClassTag = new List<ExamClassTag>();
@ -275,13 +396,14 @@ namespace Learn.Archives.API.Controllers
{
MaxScore = item.MaxScore,
MinScore = item.MinScore,
ExamId =exam.Id,
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)] = tag;
}
classTagArr[(int)(item.SubjectId ?? 0)].OnLineCount++;
}
@ -298,18 +420,21 @@ namespace Learn.Archives.API.Controllers
//总分平均分
eCInfo.Average = avgTotal / eCInfo.PeopleCount;
//计算上线率
if(classTagDic.ContainsKey(eCInfo.ClassId))
if (classTagDic.ContainsKey(eCInfo.ClassId))
foreach (var item in classTagDic[eCInfo.ClassId])
item.OnLineRate = (decimal)item.OnLineCount / (decimal)eCInfo.PeopleCount;
if(item !=null) 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 examTagArr in insertTotalClassTag.GroupBy(s => s.ExamTagId))
{
var i = 0;
i = 0;
foreach (var item in examTagArr.OrderByDescending(s => s.OnLineRate)
.GroupBy(s => s.OnLineRate))
{
@ -319,7 +444,7 @@ namespace Learn.Archives.API.Controllers
}
//计算年级平均分排名
var i = 0;
i = 0;
foreach (var item in insertTotalClassInfo.OrderByDescending(s => s.Average)
.GroupBy(s => s.Average))
{
@ -332,8 +457,10 @@ namespace Learn.Archives.API.Controllers
baseDB.Ado.BeginTran();
try
{
await baseDB.Deleteable<ExamClassInfo>().Where(s=>s.ExamId==exam.Id).ExecuteCommandAsync();
await baseDB.Deleteable<ExamClassInfo>().Where(s => s.ExamId == exam.Id).ExecuteCommandAsync();
await baseDB.Deleteable<ExamClassTag>().Where(s => s.ExamId == exam.Id).ExecuteCommandAsync();
await baseDB.Insertable(insertTotalClassInfo).ExecuteCommandAsync();
await baseDB.Insertable(insertTotalClassTag).ExecuteCommandAsync();
baseDB.Ado.CommitTran();
}
catch (Exception ex)
@ -343,80 +470,5 @@ namespace Learn.Archives.API.Controllers
}
}
/// <summary>
/// 下载导入成绩模板
/// </summary>
/// <returns></returns>
[HttpGet, ResultIgnore, AllowAnonymous]
public IActionResult DwImportTemplate()
{
List<ImportExamInfo> resultList = new List<ImportExamInfo>() { new ImportExamInfo()
{
School="例子学校[导入时候请删除]",
Class="测试班级",
ClassType="普通班级",
Grade="高2028",
Student="学生姓名",
=80.5m,
=80.5m,
=80m,
= 80m,
= 80m,
= 80m,
= 80m,
= 80m,
= 80.5m,
=721.5m
} };
return File(resultList.ExportExcel(), "application/ms-excel",
$"导入成绩模板{DateTime.Now.ToString("MMddHHmm")}.xlsx");
}
/// <summary>
/// 删除班级考试信息
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> DeleteExamInfo(RestartEntryDto dto)
{
if (dto.ClassId == 0 || dto.ExamId == 0)
Oh.ModelError("传入了异常参数");
var exam = examService.GetById(dto.ExamId);
if (exam is null)
Oh.ModelError("传入了无效的考试");
var dCount = await baseService.AsDeleteable().Where(s => s.ClassId == dto.ClassId)
.ExecuteCommandAsync();
var dCount1 = await examUserInfoService.AsDeleteable().Where(s => s.ClassId == dto.ClassId)
.ExecuteCommandAsync();
return Ok();
}
public override Task<dynamic> PageList([FromBody] QueryRequestBase model)
{
var c = model.Conditions.FirstOrDefault(s => s.FieldName == "Grade");
if (c != null)
{
var gInfo = GradeHelper.GetStudentGradeBaseByGrade(c.FieldValue);
if (gInfo != null)
{
model.Conditions = model.Conditions.Where(s => s != c).ToList();
model.Conditions.Add(new SqlSugar.ConditionalModel()
{
FieldName = "GradeLevel",
FieldValue = gInfo.GradeLevel,
});
model.Conditions.Add(new SqlSugar.ConditionalModel()
{
FieldName = "GradeYear",
FieldValue = gInfo.GradeYear.ToString(),
CSharpTypeName="int"
});
}
}
return base.PageList(model);
}
}
}

View File

@ -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 ="选填: 填写老师任职信息[不在授课架构中的职务]",
}};

View File

@ -83,11 +83,6 @@ namespace Learn.Archives.Core.Model.Dto
/// </summary>
[ExcelColumn(Name = "班级", Width = 15)]
public string Class { get; set; }
/// <summary>
/// 班级类型
/// </summary>
[ExcelColumn(Name = "班级类型", Width = 20)]
public string ClassType { get; set; }
/// <summary>
/// 科目
@ -161,11 +156,6 @@ namespace Learn.Archives.Core.Model.Dto
/// </summary>
[ExcelColumn(Name="班级", Width = 15)]
public string Class { get; set; }
/// <summary>
/// 班级
/// </summary>
[ExcelColumn(Name="班级类型", Width = 20)]
public string ClassType { get; set; }
/// <summary>
/// 减免金额
@ -295,11 +285,6 @@ namespace Learn.Archives.Core.Model.Dto
[ExcelColumn(Name="班级")]
public string Class { get; set; }
/// <summary>
/// 班级
/// </summary>
[ExcelColumn(Name="班级类型")]
public string ClassType { get; set; }
/// <summary>
/// 科目
/// </summary>
[ExcelColumn(Name="科目")]

View File

@ -24,6 +24,11 @@ namespace Learn.Archives.Core.Model
[SugarColumn(Length = 20)]
public long ExamId { get; set; }
/// <summary>
/// 班级id
/// </summary>
public long ClassId { get; set; }
/// <summary>
/// 考试标签id
/// </summary>