dev #16

Merged
hy merged 2 commits from dev into staging 2025-09-24 19:18:30 +08:00
9 changed files with 291 additions and 36 deletions
Showing only changes of commit 43a16815ca - Show all commits

View File

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs; using MiniExcelLibs;
using System.Buffers.Text; using System.Buffers.Text;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Security.Claims; using System.Security.Claims;
using UserCenter.Model; using UserCenter.Model;
@ -25,10 +26,14 @@ namespace Learn.Archives.API.Controllers
readonly Repository<ExamClassInfo> baseService; readonly Repository<ExamClassInfo> baseService;
readonly Repository<Exam> examService; readonly Repository<Exam> examService;
readonly Repository<School> schoolService; readonly Repository<School> schoolService;
readonly Repository<ExamTags> tagService;
readonly Repository<ExamUserInfo> examUserInfoService; readonly Repository<ExamUserInfo> examUserInfoService;
readonly LiveUserInfo userInfo; readonly LiveUserInfo userInfo;
readonly IHttpContextAccessor accessor; readonly IHttpContextAccessor accessor;
public ExamClassInfoController(Repository<ExamClassInfo> baseService, LiveUserInfo userInfo, IHttpContextAccessor httpContext, Repository<ExamUserInfo> examUserInfoService, Repository<Exam> examService, Repository<School> schoolService) : base(baseService) public ExamClassInfoController(Repository<ExamClassInfo> baseService, LiveUserInfo userInfo,
IHttpContextAccessor httpContext, Repository<ExamUserInfo> examUserInfoService,
Repository<Exam> examService, Repository<School> schoolService,
Repository<ExamTags> tagService) : base(baseService)
{ {
this.baseService = baseService; this.baseService = baseService;
this.userInfo = userInfo; this.userInfo = userInfo;
@ -36,8 +41,9 @@ namespace Learn.Archives.API.Controllers
this.examUserInfoService = examUserInfoService; this.examUserInfoService = examUserInfoService;
this.examService = examService; this.examService = examService;
this.schoolService = schoolService; this.schoolService = schoolService;
this.tagService = tagService;
} }
[NonAction] [NonAction]
private Dictionary<SubjectEnum, decimal>? ImportExamInfoSubjectDic(ImportExamInfo info) private Dictionary<SubjectEnum, decimal>? ImportExamInfoSubjectDic(ImportExamInfo info)
{ {
@ -54,7 +60,19 @@ namespace Learn.Archives.API.Controllers
{ 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>
/// 导入考试信息 /// 导入考试信息
/// </summary> /// </summary>
@ -175,7 +193,7 @@ namespace Learn.Archives.API.Controllers
//写入数据库 //写入数据库
await examUserInfoService.AsInsertable(insertUserInfo).ExecuteCommandAsync(); await examUserInfoService.AsInsertable(insertUserInfo).ExecuteCommandAsync();
await CalculatingTestResults(exam,examUserInfoService,schoolService); await CalculatingTestResults(exam,examUserInfoService,schoolService, tagService);
return Ok(); return Ok();
} }
@ -188,18 +206,23 @@ namespace Learn.Archives.API.Controllers
/// <param name="schoolService"></param> /// <param name="schoolService"></param>
/// <returns></returns> /// <returns></returns>
[NonAction] [NonAction]
public static async Task CalculatingTestResults(Exam exam, Repository<ExamUserInfo> eUService, Repository<School> sService) public static async Task CalculatingTestResults(Exam exam, Repository<ExamUserInfo> eUService,
Repository<School> sService, Repository<ExamTags> tagService)
{ {
var userInfoArr = await eUService.AsQueryable() var userInfoArr = await eUService.AsQueryable()
.Where(s => s.ExamId == exam.Id) .Where(s => s.ExamId == exam.Id)
.ToArrayAsync(); .ToArrayAsync();
var insertTotalClassInfo = new List<ExamClassInfo>(); var insertTotalClassInfo = new List<ExamClassInfo>();
var insertTotalClassTag = new List<ExamClassTag>();
var eTagArr = await tagService.AsQueryable().Where(s => s.ExamId == exam.Id)
.ToArrayAsync();
var db = sService.Context; var db = sService.Context;
foreach (var schoolArr in userInfoArr.GroupBy(s => s.SchoolId)) foreach (var schoolArr in userInfoArr.GroupBy(s => s.SchoolId))
{ {
var insertClassInfo = new List<ExamClassInfo>(); var insertClassInfo = new List<ExamClassInfo>();
var insertClassTag = new List<ExamClassTag>();
var school = await sService.GetFirstAsync(s => s.Id == schoolArr.Key); var school = await sService.GetFirstAsync(s => s.Id == schoolArr.Key);
var classArr = await db.Queryable<Classes>().Where(c => c.SchoolId == school.Id && var classArr = await db.Queryable<Classes>().Where(c => c.SchoolId == school.Id &&
c.GradeLevel == exam.GradeLevel && c.GradeLevel == exam.GradeLevel &&
@ -228,12 +251,43 @@ namespace Learn.Archives.API.Controllers
}; };
insertClassInfo.Add(eCInfo); insertClassInfo.Add(eCInfo);
var avgTotal = 0m; var avgTotal = 0m;
//todo 班级分段分析
var classTagDic = new Dictionary<long, ExamClassTag[]>();
foreach (var eUserInfo in classUserArr) foreach (var eUserInfo in classUserArr)
{ {
var v = eUserInfo.AssignScore; if (!classTagDic.TryGetValue(eUserInfo.ClassId, out ExamClassTag[]? classTagArr))
{
classTagArr = new ExamClassTag[10];
classTagDic.Add(eUserInfo.ClassId, classTagArr);
}
//上线人数 //上线人数
if (v >= exam.ScoreLine) foreach (var item in eTagArr)
eCInfo.OnLineCount++; {
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) if (v < eCInfo.MinScore)
eCInfo.MinScore = v; eCInfo.MinScore = v;
@ -244,23 +298,28 @@ namespace Learn.Archives.API.Controllers
//总分平均分 //总分平均分
eCInfo.Average = avgTotal / eCInfo.PeopleCount; eCInfo.Average = avgTotal / eCInfo.PeopleCount;
//计算上线率 //计算上线率
eCInfo.OnLineRate = (decimal)eCInfo.OnLineCount / (decimal)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); insertTotalClassInfo.AddRange(insertClassInfo);
insertTotalClassTag.AddRange(insertClassTag);
} }
{ //计算年级上线率排名 { //计算班级上线率排名
var i = 0; foreach (var examTagArr in insertTotalClassTag.GroupBy(s => s.ExamTagId))
foreach (var item in insertTotalClassInfo.OrderByDescending(s => s.OnLineRate)
.GroupBy(s => s.OnLineRate))
{ {
foreach (var u in item) var i = 0;
u.OnLineRanking = ++i; foreach (var item in examTagArr.OrderByDescending(s => s.OnLineRate)
.GroupBy(s => s.OnLineRate))
{
foreach (var u in item)
u.OnLineRanking = ++i;
}
} }
//计算年级平均分排名 //计算年级平均分排名
i = 0; var i = 0;
foreach (var item in insertTotalClassInfo.OrderByDescending(s => s.Average) foreach (var item in insertTotalClassInfo.OrderByDescending(s => s.Average)
.GroupBy(s => s.Average)) .GroupBy(s => s.Average))
{ {

View File

@ -20,18 +20,20 @@ namespace Learn.Archives.API.Controllers
{ {
readonly Repository<Exam> baseService; readonly Repository<Exam> baseService;
readonly Repository<School> schoolService; readonly Repository<School> schoolService;
readonly Repository<ExamTags> tagService;
readonly Repository<ExamClassInfo> examClassInfoService; readonly Repository<ExamClassInfo> examClassInfoService;
readonly Repository<ExamUserInfo> examUserInfoService; readonly Repository<ExamUserInfo> examUserInfoService;
readonly LiveUserInfo userInfo; readonly LiveUserInfo userInfo;
public ExamController(Repository<Exam> baseService, LiveUserInfo userInfo, public ExamController(Repository<Exam> baseService, LiveUserInfo userInfo,
Repository<ExamClassInfo> examClassInfoService, Repository<ExamUserInfo> examUserInfoService, Repository<ExamClassInfo> examClassInfoService, Repository<ExamUserInfo> examUserInfoService,
Repository<School> schoolService) : base(baseService) Repository<School> schoolService, Repository<ExamTags> tagService) : base(baseService)
{ {
this.baseService = baseService; this.baseService = baseService;
this.userInfo = userInfo; this.userInfo = userInfo;
this.examClassInfoService = examClassInfoService; this.examClassInfoService = examClassInfoService;
this.examUserInfoService = examUserInfoService; this.examUserInfoService = examUserInfoService;
this.schoolService = schoolService; this.schoolService = schoolService;
this.tagService = tagService;
} }
public override Task<dynamic> PageList([FromBody] QueryRequestBase model) public override Task<dynamic> PageList([FromBody] QueryRequestBase model)
{ {
@ -69,7 +71,7 @@ namespace Learn.Archives.API.Controllers
} }
var res =await base.Edit(model); var res =await base.Edit(model);
if (res) if (res)
await ExamClassInfoController.CalculatingTestResults(model, examUserInfoService, schoolService); await ExamClassInfoController.CalculatingTestResults(model, examUserInfoService, schoolService, tagService);
return res ; return res ;
} }
public override async Task<bool> Del([FromBody] params long[] ids) public override async Task<bool> Del([FromBody] params long[] ids)

View File

@ -0,0 +1,28 @@
using Learn.Archives.API.Controllers.Dto;
using Learn.Archives.API.Expand;
using Learn.Archives.Core.Common;
using Learn.Archives.Core.Model;
using Learn.Archives.Core.Model.Dto;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using UserCenter.Model;
using UserCenter.Model.Common;
using UserCenter.Model.Enum;
namespace Learn.Archives.API.Controllers
{
/// <summary>
/// 年级控制器
/// </summary>
public class ExamTagsController : BackController<ExamTags>
{
readonly Repository<ExamTags> baseService;
public ExamTagsController(Repository<ExamTags> baseService) : base(baseService)
{
this.baseService = baseService;
}
}
}

View File

@ -14,7 +14,7 @@
"DB": { "DB": {
"ConnectionString": "AllowLoadLocalInfile=true;Server=58.17.132.2;User ID=marking;Password=qwe123!@#;Port=3306;Database=learn.archives;CharSet=utf8mb4;Port=43306;pooling=true;SslMode=None;", "ConnectionString": "AllowLoadLocalInfile=true;Server=58.17.132.2;User ID=marking;Password=qwe123!@#;Port=3306;Database=learn.archives;CharSet=utf8mb4;Port=43306;pooling=true;SslMode=None;",
"SqlType": "MySql", "SqlType": "MySql",
"UpdateTable": false "UpdateTable": true
}, },
"AuthKey": { "AuthKey": {
"Secret": "9FAB7AC7-F1DB-4C56-B84F-044055A34AF2", "Secret": "9FAB7AC7-F1DB-4C56-B84F-044055A34AF2",

View File

@ -0,0 +1,13 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Learn.Archives.Core.Model.Dto
{
}

View File

@ -38,7 +38,8 @@ namespace Learn.Archives.Core.Model
/// </summary> /// </summary>
public string? _grade; public string? _grade;
/// <summary> /// <summary>
/// 年级 /// 年级
/// <para>AOP自动转换年级</para>
/// </summary> /// </summary>
[SugarColumn(IsIgnore = true)] [SugarColumn(IsIgnore = true)]
public string Grade public string Grade

View File

@ -1,4 +1,5 @@
using Learn.Archives.Core.Model.Enum; using Learn.Archives.Core.Model.Dto;
using Learn.Archives.Core.Model.Enum;
using Learn.Archives.Core.Model.Interface; using Learn.Archives.Core.Model.Interface;
using SqlSugar; using SqlSugar;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
@ -71,18 +72,19 @@ namespace Learn.Archives.Core.Model
/// </summary> /// </summary>
public int GradeYear { get; set; } public int GradeYear { get; set; }
/// <summary> ///// <summary>
/// 上线率 考试排名 ///// 上线率 考试排名
/// </summary> ///// </summary>
public decimal OnLineRanking { get; set; } //public decimal OnLineRanking { get; set; }
/// <summary> ///// <summary>
/// 上线率 ///// 上线率
/// </summary> ///// </summary>
public decimal OnLineRate { get; set; } //public decimal OnLineRate { get; set; }
/// <summary> ///// <summary>
/// 上线人数 ///// 上线人数
/// </summary> ///// </summary>
public int OnLineCount { get; set; } //public int OnLineCount { get; set; }
/// <summary> /// <summary>
/// 参加人数 /// 参加人数
/// </summary> /// </summary>

View File

@ -0,0 +1,77 @@
using Learn.Archives.Core.Model.Dto;
using Learn.Archives.Core.Model.Enum;
using Learn.Archives.Core.Model.Interface;
using SqlSugar;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Text.Json;
using UserCenter.Model;
using UserCenter.Model.Common;
using UserCenter.Model.Enum;
using UserCenter.Model.Interface;
namespace Learn.Archives.Core.Model
{
/// <summary>
/// 班级考试详情
/// </summary>
[SugarTable("examclasstag")]
public class ExamClassTag : EntityBaseId, IDB
{
/// <summary>
/// 考试Id
/// </summary>
[SugarColumn(Length = 20)]
public long ExamId { get; set; }
/// <summary>
/// 考试标签id
/// </summary>
public long ExamTagId { get; set; }
/// <summary>
/// 标签名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 分段所属学科
/// <para>可空 空即为总分分段</para>
/// </summary>
[SugarColumn(IsNullable = true)]
public SubjectEnum? SubjectId { get; set; }
/// <summary>
/// 最小分值
/// </summary>
[SugarColumn(DecimalDigits = 2)]
public decimal MinScore { get; set; }
/// <summary>
/// 最大分值
/// </summary>
[SugarColumn(DecimalDigits = 2)]
public decimal MaxScore { get; set; }
/// <summary>
/// 上线率 考试排名
/// </summary>
public int OnLineRanking { get; set; }
/// <summary>
/// 上线率
/// </summary>
[SugarColumn(DecimalDigits = 2)]
public decimal OnLineRate { get; set; }
/// <summary>
/// 上线人数
/// </summary>
public int OnLineCount { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; } = DateTime.Now;
}
}

View File

@ -0,0 +1,73 @@
using System;
using System.Linq;
using System.Text;
using UserCenter.Model;
using UserCenter.Model.Interface;
using SqlSugar;
using UserCenter.Model.Enum;
using Learn.Archives.Core.Model.Interface;
namespace Learn.Archives.Core.Model
{
///<summary>
/// 考试成绩分段表
///</summary>
[SugarTable("examtags")]
public partial class ExamTags : EntityBaseId, IDB
{
public ExamTags()
{
this.IsDefault = Convert.ToInt32("0");
this.CreateTime = DateTime.Now;
}
/// <summary>
///
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public override long Id { get; set; }
/// <summary>
/// 考试编号
/// </summary>
public long ExamId { get; set; }
/// <summary>
/// 分段所属学科
/// <para>可空 空即为总分分段</para>
/// </summary>
[SugarColumn(IsNullable = true)]
public SubjectEnum? SubjectId { get; set; }
/// <summary>
/// 最小分值
/// </summary>
[SugarColumn(DecimalDigits = 2)]
public decimal MinScore { get; set; }
/// <summary>
/// 最大分值
/// </summary>
[SugarColumn(DecimalDigits = 2)]
public decimal MaxScore { get; set; }
/// <summary>
/// 标签名称
/// </summary>
public string TagName { get; set; }
/// <summary>
/// 是否为默认标签 0否 1
/// </summary>
public int IsDefault { get; set; }
/// <summary>
/// 添加时间
/// </summary>
public DateTime CreateTime { get; set; }
}
}