Compare commits

...

25 Commits

Author SHA1 Message Date
hy 8135ee0f4c Merge pull request 'staging' (#20) from staging into master
Reviewed-on: #20
2025-10-14 11:13:23 +08:00
hy 628c1c5b3c Merge pull request '优化 日志记录 管理员导入' (#19) from dev into staging
Reviewed-on: #19
2025-10-14 11:08:18 +08:00
小肥羊 12c022e05c 优化 日志记录 管理员导入 2025-10-14 10:41:07 +08:00
hy 07967f1390 Merge pull request '修复 上线率为分析原因' (#18) from dev into staging
Reviewed-on: #18
2025-09-25 16:10:44 +08:00
小肥羊 7c46a2f49e 修复 上线率为分析原因 2025-09-25 16:09:58 +08:00
hy 218bf66fc6 Merge pull request 'dev' (#17) from dev into staging
Reviewed-on: #17
2025-09-25 15:48:34 +08:00
小肥羊 90a6815c7a 修复 班级分段分析错误问题 2025-09-25 15:42:53 +08:00
小肥羊 d31c898d35 修复 班级学生成绩排序异常 2025-09-25 14:03:49 +08:00
hy db0e5905fa Merge pull request 'dev' (#16) from dev into staging
Reviewed-on: #16
2025-09-24 19:18:29 +08:00
小肥羊 fb6147ecbf 新增 班级考试成绩分段功能
删除 多余的班级类型字段
2025-09-24 19:17:49 +08:00
小肥羊 43a16815ca 新增 考试 多学科成绩分段功能 2025-09-23 18:20:31 +08:00
hy 67363cd50d Merge pull request 'dev' (#15) from dev into staging
Reviewed-on: #15
2025-09-14 15:46:47 +08:00
小肥羊 abcdad03b0 新增 查询职位id 2025-09-12 18:33:51 +08:00
小肥羊 d0638bcfd4 新增 赴校信息的拓展 问题执行记录 2025-09-05 18:12:55 +08:00
小肥羊 9dbd3e4900 迁移 用户数据库为 _v1 2025-09-03 11:51:32 +08:00
hy a1a6324b8b Merge pull request 'dev' (#13) from dev into staging
Reviewed-on: #13
2025-08-27 15:44:33 +08:00
hy 12ffbe5754 Merge pull request '新增 edit学生类型' (#12) from dev into staging
Reviewed-on: #12
2025-08-27 10:37:25 +08:00
hy ab5fc42607 Merge pull request '优化 赴校信息导入模板1' (#10) from dev into staging
Reviewed-on: #10
2025-08-26 20:17:47 +08:00
hy a5e044ca7e Merge pull request '优化 赴校信息导入模板' (#8) from dev into staging
Reviewed-on: #8
2025-08-26 20:10:16 +08:00
hy ae5d2a8293 Merge pull request 'dev' (#7) from dev into staging
Reviewed-on: #7
2025-08-26 19:59:55 +08:00
hy 119576da72 Merge pull request 'dev' (#6) from dev into staging
Reviewed-on: #6
2025-08-26 19:21:24 +08:00
tiananlin 57e98333cf 添加 Learn.Archives.API/Dockerfiles/Dockerfile-production 2025-08-26 15:14:35 +08:00
hy d22e07353d Merge pull request 'dev' (#5) from dev into staging
Reviewed-on: #5
2025-08-26 14:36:39 +08:00
hy aa7b035eb6 Merge pull request 'dev' (#4) from dev into staging
Reviewed-on: #4
2025-08-26 10:10:35 +08:00
hy 520a3ef59f Merge pull request '完善 学生导入新增的字段' (#2) from dev into staging
Reviewed-on: #2
2025-08-25 16:53:30 +08:00
23 changed files with 772 additions and 223 deletions

View File

@ -3,10 +3,16 @@ 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 Learn.Archives.Core.Model.Enum;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using System.Diagnostics;
using System.Security.Claims;
using System.Text.RegularExpressions;
using UserCenter.Model.Common;
namespace Learn.Archives.API.Controllers
{
@ -15,11 +21,17 @@ namespace Learn.Archives.API.Controllers
readonly Repository<Admin> baseService;
readonly Repository<MenuRelation> menuRelationDB;
readonly Repository<Menu> menuDB;
public AdminController(Repository<Admin> baseService, Repository<MenuRelation> menuRelationDB, Repository<Menu> menuDB) : base(baseService)
readonly Repository<AdminRole> roleDB;
readonly LiveUserInfo userInfo;
readonly IHttpContextAccessor accessor;
public AdminController(Repository<Admin> baseService, Repository<MenuRelation> menuRelationDB, Repository<Menu> menuDB, IHttpContextAccessor accessor, Repository<AdminRole> roleDB, LiveUserInfo userInfo = null) : base(baseService)
{
this.baseService = baseService;
this.menuRelationDB = menuRelationDB;
this.menuDB = menuDB;
this.accessor = accessor;
this.roleDB = roleDB;
this.userInfo = userInfo;
}
/// <summary>
/// 管理员登录
@ -44,7 +56,7 @@ namespace Learn.Archives.API.Controllers
if (admin.Password != model.Password.GetMD5())
Oh.Error("登录失败,密码错误");
// 获取租户信息
var buttonRole = admin.RoleId==1
var buttonRole = admin.RoleId == 1
? ["*:*:*"]
: await menuRelationDB.AsQueryable()
.LeftJoin<Menu>((mr, m) => mr.MenuId == m.Id)
@ -73,12 +85,107 @@ namespace Learn.Archives.API.Controllers
}
public override Task<bool> Edit([FromBody] Admin model)
public override async Task<bool> Edit([FromBody] Admin model)
{
//创建用户时 密码加密
if (model.Id == 0)
model.Password = model.Password.GetMD5();
return base.Edit(model);
if (string.IsNullOrEmpty(model.Account) || model.Account.Length < 2 ||
string.IsNullOrEmpty(model.Phone) || model.Phone.Length < 11 ||
string.IsNullOrEmpty(model.Name) || model.Phone.Length < 2)
{
Oh.ModelError("账号/手机号/名称 不合法");
}
if (await baseService.IsAnyAsync(s => s.Account == model.Account && s.Id != model.Id))
Oh.ModelError($"账号 {model.Account} 已被使用!");
return await base.Edit(model);
}
/// <summary>
/// 下载导入模板
/// </summary>
/// <returns></returns>
[HttpGet, ResultIgnore, AllowAnonymous]
public IActionResult DwImportTemplate()
{
var resultList = new List<AdminImport>() { new AdminImport()
{
Account = "登录账号[建议使用手机号]",
Name = "必填:用户名称",
Phone = "联系方式",
Role = "必填:与系统的角色名称匹配\r\n普通成员 管理员",
Password = "必填: 登录密码",
} };
return File(resultList.ExportExcel(), "application/ms-excel",
$"导入管理员模板{DateTime.Now.ToString("MMddHHmm")}.xlsx");
}
/// <summary>
/// 导入考试信息
/// </summary>
/// <returns></returns>
[HttpPost, ResultIgnore]
[HttpLogEnable]
public async Task<IActionResult> Import(IFormFile? file)
{
if(!userInfo.IsSa)
Oh.ModelError("只允许管理员使用本功能!");
var fl = file != null ? file : accessor.HttpContext?.Request.Form.Files[0];
if (fl == null) Oh.ModelError("传入无效的数据");
if (!Path.GetExtension(fl.FileName).Equals(".xlsx", StringComparison.OrdinalIgnoreCase))
Oh.ModelError("请选择导入文件为.xlsx的后缀名!");
//分析excel
IEnumerable<AdminImportError> dataList;
using var stream = new MemoryStream();
{
await fl.CopyToAsync(stream);
dataList = stream.Query<AdminImportError>()
.Where(s => !string.IsNullOrEmpty(s.Account));
}
if (dataList == null || dataList.Count() == 0)
Oh.ModelError("导入失败:无有效数据");
//处理数据
var accountArr = await baseService.AsQueryable()
.Select(s => s.Account).Distinct()
.ToArrayAsync();
var accountH = accountArr.ToHashSet();
var roleDic = await roleDB.AsQueryable()
.ToDictionaryAsync(s => s.Name, s => s.Id);
var errorExcelInfo = new List<AdminImportError>();
var insertInfo = new List<Admin>();
foreach (var imp in dataList)
{
imp.Account = imp.Account.Trim();
imp.Phone = imp.Phone.Trim();
imp.Name = imp.Name.Trim();
imp.Role = imp.Role.Trim();
if (accountH.Contains(imp.Account))
{
imp.Error = $"导入失败:账号已被使用!";
errorExcelInfo.Add(imp);
continue;
}
else if (!roleDic.ContainsKey(imp.Role))
{
imp.Error = $"导入失败:无效的 角色名称!";
errorExcelInfo.Add(imp);
continue;
}
var admin = imp.Adapt<Admin>();
admin.Enable = true;
admin.RoleId = (long)roleDic[imp.Role];
admin.Password = imp.Password.Trim().GetMD5();
insertInfo.Add(admin);
}
if (errorExcelInfo.Count != 0)
return File(errorExcelInfo.ExportExcel(), "application/ms-excel"
, $"错误管理员信息{DateTime.Now.ToString("MMddHHmm")}.xlsx");
//写入数据库
await baseService.InsertRangeAsync(insertInfo);
return Ok();
}
}
}

View File

@ -0,0 +1,10 @@
using UserCenter.Model;
using UserCenter.Model.Common;
namespace Learn.Archives.API.Controllers.Dto
{
public class ClassDto:Classes
{
public string Grade => GradeHelper.GetGrade(this.GradeLevel, GraduationYear);
}
}

View File

@ -1,10 +1,37 @@
using UserCenter.Model;
using MiniExcelLibs.Attributes;
using UserCenter.Model;
using UserCenter.Model.Common;
namespace Learn.Archives.API.Controllers.Dto
{
public class ClassDto:Classes
public class AdminImportError : AdminImport
{
public string Grade => GradeHelper.GetGrade(this.GradeLevel, GraduationYear);
[ExcelColumn(Name = "错误原因", Width = 25)]
public string Error { get; set; }
}
public class AdminImport
{
[ExcelColumn(Name = "账号", Width = 30)]
public string Account { get; set; }
[ExcelColumn(Name = "名称", Width = 15)]
public string Name { get; set; }
[ExcelColumn(Name = "电话号码", Width = 30)]
public string Phone { get; set; }
[ExcelColumn(Name = "角色", Width = 30)]
public string Role { get; set; }
/// <summary>
/// 密码
/// </summary>
[ExcelColumn(Name = "密码", Width = 20)]
public string Password { get; set; }
}
}

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

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using System.Buffers.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Claims;
using UserCenter.Model;
@ -25,10 +26,15 @@ namespace Learn.Archives.API.Controllers
readonly Repository<ExamClassInfo> baseService;
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) : base(baseService)
public ExamClassInfoController(Repository<ExamClassInfo> baseService, LiveUserInfo userInfo,
IHttpContextAccessor httpContext, Repository<ExamUserInfo> examUserInfoService,
Repository<Exam> examService, Repository<School> schoolService,
Repository<ExamTags> tagService, Repository<ExamClassTag> classTagService) : base(baseService)
{
this.baseService = baseService;
this.userInfo = userInfo;
@ -36,23 +42,8 @@ namespace Learn.Archives.API.Controllers
this.examUserInfoService = examUserInfoService;
this.examService = examService;
this.schoolService = schoolService;
}
[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.},
};
this.tagService = tagService;
this.classTagService = classTagService;
}
/// <summary>
@ -118,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 = "未能匹配班级";
@ -134,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 = "未能匹配到年级班级下对应的学生";
@ -175,115 +166,11 @@ namespace Learn.Archives.API.Controllers
//写入数据库
await examUserInfoService.AsInsertable(insertUserInfo).ExecuteCommandAsync();
await CalculatingTestResults(exam,examUserInfoService,schoolService);
await CalculatingTestResults(exam,examUserInfoService,schoolService, tagService);
return Ok();
}
/// <summary>
/// 计算考试成绩
/// </summary>
/// <param name="exam"></param>
/// <param name="examUserInfoService"></param>
/// <param name="schoolService"></param>
/// <returns></returns>
[NonAction]
public static async Task CalculatingTestResults(Exam exam, Repository<ExamUserInfo> eUService, Repository<School> sService)
{
var userInfoArr = await eUService.AsQueryable()
.Where(s => s.ExamId == exam.Id)
.ToArrayAsync();
var insertTotalClassInfo = new List<ExamClassInfo>();
var db = sService.Context;
foreach (var schoolArr in userInfoArr.GroupBy(s => s.SchoolId))
{
var insertClassInfo = new List<ExamClassInfo>();
var school = await sService.GetFirstAsync(s => s.Id == schoolArr.Key);
var classArr = await db.Queryable<Classes>().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;
foreach (var eUserInfo in classUserArr)
{
var v = eUserInfo.AssignScore;
//上线人数
if (v >= exam.ScoreLine)
eCInfo.OnLineCount++;
//最大小分
if (v < eCInfo.MinScore)
eCInfo.MinScore = v;
if (v > eCInfo.MaxScore)
eCInfo.MaxScore = v;
avgTotal += v;//追加得分
}
//总分平均分
eCInfo.Average = avgTotal / eCInfo.PeopleCount;
//计算上线率
eCInfo.OnLineRate = (decimal)eCInfo.OnLineCount / (decimal)eCInfo.PeopleCount;
}
insertTotalClassInfo.AddRange(insertClassInfo);
}
{ //计算年级上线率排名
var i = 0;
foreach (var item in insertTotalClassInfo.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<ExamClassInfo>().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}] !");
}
}
/// <summary>
/// 下载导入成绩模板
@ -296,7 +183,6 @@ namespace Learn.Archives.API.Controllers
{
School="例子学校[导入时候请删除]",
Class="测试班级",
ClassType="普通班级",
Grade="高2028",
Student="学生姓名",
=80.5m,
@ -359,5 +245,217 @@ namespace Learn.Archives.API.Controllers
}
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>
/// <param name="exam"></param>
/// <param name="examUserInfoService"></param>
/// <param name="schoolService"></param>
/// <returns></returns>
[NonAction]
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 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;
foreach (var schoolArr in userInfoArr.GroupBy(s => s.SchoolId))
{
var school = await sService.GetFirstAsync(s => s.Id == schoolArr.Key);
var classArr = await db.Queryable<Classes>().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,
};
insertTotalClassInfo.Add(eCInfo);
var avgTotal = 0m;
//todo 班级分段分析
var classTagDic = new Dictionary<long, ExamClassTag>();
foreach (var eUserInfo in classUserArr)
{
//上线人数
foreach (var item in eTagArr)
{
var subV = SubjectScore(eUserInfo, item.SubjectId);
if (!classTagDic.TryGetValue(item.Id, out ExamClassTag? tag))
{
tag = new ExamClassTag()
{
MaxScore = item.MaxScore,
MinScore = item.MinScore,
ClassId = classInfo.Id,
PeopleCount = eCInfo.PeopleCount,
ExamId = exam.Id,
ExamTagId = item.Id,
Name = item.TagName,
SubjectId = item.SubjectId
};
insertTotalClassTag.Add(tag);
classTagDic.Add(item.Id, tag);
}
//总分分段
if (subV >= item.MinScore && subV <= item.MaxScore)
{
tag.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;
}
}
{
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<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)
{
baseDB.Ado.RollbackTran();
Oh.ModelError($"导入失败:写入数据时候出现了异常 [{ex.Message}] !");
}
}
}
}

View File

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

@ -6,9 +6,11 @@ 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
{
@ -24,7 +26,7 @@ namespace Learn.Archives.API.Controllers
this.baseService = baseService;
this.userInfo = userInfo;
}
public override Task<dynamic> PageList([FromBody] QueryRequestBase model)
public override async Task<dynamic> PageList([FromBody] QueryRequestBase model)
{
var c = model.Conditions.FirstOrDefault(s => s.FieldName == "Grade");
if (c != null)
@ -46,7 +48,18 @@ namespace Learn.Archives.API.Controllers
});
}
}
return base.PageList(model);
var oldSer = model.OrderBy.ToEnum<SubjectEnum>();
if (oldSer != null)
{
model.OrderBy = "id";
var res = (PageResult<ExamUserInfo>)await base.PageList(model);
if (model.OrderByType == SqlSugar.OrderByType.Asc)
res.Data = res.Data.OrderBy(s => s.SubjectDic?[oldSer.Value]).ToList();
else
res.Data = res.Data.OrderByDescending(s => s.SubjectDic?[oldSer.Value]).ToList();
return res;
}
return await base.PageList(model);
}
}
}

View File

@ -10,7 +10,9 @@ using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using SqlSugar;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Security.Claims;
using System.Text.RegularExpressions;
using UserCenter.Model;
@ -20,20 +22,22 @@ using UserCenter.Model.Enum;
namespace Learn.Archives.API.Controllers
{
/// <summary>
/// 年级控制器
/// 学生接口
/// </summary>
public class StudentController : BackController<Student>
{
private readonly IHttpContextAccessor _httpContextAccessor;
readonly Repository<Student> baseService;
readonly Repository<Position> positionService;
readonly UserCenterService _userCenterService;
readonly LiveUserInfo userInfo;
public StudentController(Repository<Student> baseService, LiveUserInfo userInfo, IHttpContextAccessor httpContextAccessor, UserCenterService userCenterService) : base(baseService)
public StudentController(Repository<Student> baseService, LiveUserInfo userInfo, IHttpContextAccessor httpContextAccessor, UserCenterService userCenterService, Repository<Position> positionService) : base(baseService)
{
this.baseService = baseService;
this.userInfo = userInfo;
_httpContextAccessor = httpContextAccessor;
_userCenterService = userCenterService;
this.positionService = positionService;
}
[NonAction]
@ -54,6 +58,42 @@ namespace Learn.Archives.API.Controllers
Oh.ModelError("无效数据");
return await baseService.AsQueryable().FirstAsync(s => s.UserCenterId == uid);
}
/// <summary>
/// 获取职位id
/// <para> 调用流程 用户中心->档案系统</para>
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<long[]> PosititonIds(PositionIdsReq[] data)
{
if (data == null || data.Count()==0)
Oh.ModelError("无效数据");
var query = new Expressionable<Position>();
foreach (var pos in data)
{
query = query.Or(q =>
q.SchoolId == pos.SchoolId &&
q.PositionType == pos.PositionType &&
q.GradeLevel == pos.GradeLevel &&
q.GraduationYear == pos.GraduationYear &&
q.PositionLevel == pos.PositionLevel
&&
(
// PositionLevel == 3只匹配前三个字段
(pos.PositionLevel == 3) ||
// PositionLevel == 4再加上 ClassId
(pos.PositionLevel == 4 && q.ClassId == pos.ClassId) ||
// PositionLevel == 5再加上 ClassId + SubjectId
(pos.PositionLevel == 5 && q.ClassId == pos.ClassId && q.SubjectId == pos.SubjectId)
)
);
}
return await positionService.AsQueryable()
.Where(query.ToExpression())
.Select(p => p.Id).ToArrayAsync();
}
/// <summary>
/// 修改用户信息
@ -181,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()
@ -262,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,
@ -309,11 +347,10 @@ namespace Learn.Archives.API.Controllers
{
var resultList = new List<StudentInfoImport>() { new StudentInfoImport()
{
RealName = "导入规范[导入时请删除本]",
RealName = "导入规范[导入时请删除本]",
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领导同意的特殊贫困减免",
@ -340,12 +377,11 @@ namespace Learn.Archives.API.Controllers
new TeacherInfoImport()
{
Phone="必填",
RealName = "导入规范[导入时请删除本]",
RealName = "导入规范[导入时请删除本]",
UserType = "必填 可选值\r\n[年级主任,班主任,教师]",
School = "必填:与系统匹配",
Grade = "必填:可选值\r\n[初一初二初三,高一高二高山]",
Class = "必填:与系统匹配\r\n格式:10班[数字+班]\r\n任教类型是年级主任时不填",
ClassType = "必填:可选值\r\n[云校班 海豚智学班 蓝鲸智库班 中职班 其他 雅思班 点阵笔班级 移动校园班级 智学班 ...]\r\n任教类型是年级主任时不填",
Subject = "选填学科",
ExamNo ="选填: 填写老师任职信息[不在授课架构中的职务]",
}};

View File

@ -21,6 +21,7 @@ using Learn.Archives.Core.Common;
using Learn.Archives.Core.Model.Dto;
using Learn.Archives.Core.Model;
using SqlSugar.IOC;
using static System.Net.Mime.MediaTypeNames;
namespace Learn.Archives.API.Expand
{
@ -50,8 +51,32 @@ namespace Learn.Archives.API.Expand
this.userInfo = userInfo;
}
/// <summary>
/// 执行接口前文件做缓存处理
/// </summary>
/// <param name="context"></param>
/// <exception cref="CustomException"></exception>
public void ExecutingFileCached(ActionExecutingContext context)
{
//特殊处理ResultIgnore不进行返回结果包装原样输出
var endpoint = context.HttpContext.GetEndpoint();
// 直接返回原始结果,不封装
if (endpoint?.Metadata.GetMetadata<HttpLogEnable>() == null) return;
if (context.HttpContext.Request.HasFormContentType &&
context.HttpContext.Request.Form.Files != null &&
context.HttpContext.Request.Form.Files.Count() > 0)
{
context.HttpContext.Items["FileCached"]=
context.HttpContext.Request.Form.Files.Select(s =>
{
var stream = new MemoryStream();
s.CopyTo(stream);
stream.Position = 0;
return (s, stream);
}).ToArray();
}
}
/// <summary>
/// 执行接口前400 处理
/// </summary>
@ -132,43 +157,43 @@ namespace Learn.Archives.API.Expand
string request = null;
var logId = Yitter.IdGenerator.YitIdHelper.NextId();
if (!context.Request.Method
.Equals("GET", StringComparison.InvariantCultureIgnoreCase))
if (!context.Request.Method.Equals("GET", StringComparison.InvariantCultureIgnoreCase))
{
context.Request.EnableBuffering();
//记录请求参数
if (context.Request.Body.CanSeek)
{
try
{
if (context.Request.HasFormContentType && context.Request?.Form?.Files?.Count() > 0)
var fileArr = context.Items.ContainsKey("FileCached") ? context.Items["FileCached"] as (IFormFile file, MemoryStream stream)[] : null;
if (context.Request.HasFormContentType && fileArr != null)
{
// 设置保存目录例如项目根目录下的Uploads文件夹
string uploadsFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UploadLogs", logId.ToString());
// 创建目录(如果不存在)
if (!Directory.Exists(uploadsFolder))
Directory.CreateDirectory(uploadsFolder);
foreach (var file in context.Request.Form.Files)
foreach (var fileInfo in fileArr)
{
// 生成安全文件名(防止路径遍历攻击)
string uniqueFileName = Guid.NewGuid().ToString().Substring(0, 5) + "_" + Path.GetFileName(file.FileName);
string filePath = Path.Combine(uploadsFolder, uniqueFileName);
string uniqueFileName = Guid.NewGuid().ToString().Substring(0, 5) + "_" + Path.GetFileName(fileInfo.file.FileName);
// 保存文件
using var stream = new FileStream(filePath, FileMode.Create);
await file.CopyToAsync(stream);
using var stream = new FileStream(Path.Combine(uploadsFolder, uniqueFileName), FileMode.Create, FileAccess.Write);
fileInfo.stream.Position = 0;
await fileInfo.stream.CopyToAsync(stream);
fileInfo.stream.Dispose();
}
request = $"请求体包含{context.Request.Form.Files.Count()}个文件 目录 {uploadsFolder}";
}
else
{
context.Request.Body.Position = 0;
using var sr = new StreamReader(context.Request.Body);
using var sr = new System.IO.StreamReader(context.Request.Body);
request = await sr.ReadToEndAsync();
}
}
catch (Exception ex)
{
request = "处理请求日志时发生了错误 \r\n" + ex.ToString();
request = "处理请求入参时发生了错误 \r\n" + ex.ToString() + "\r\n 原有请求数据 " + request;
}
}
}
@ -181,7 +206,7 @@ namespace Learn.Archives.API.Expand
Request = request,
IP = context.Connection?.RemoteIpAddress?.ToString(),
ResponseCode = result?.Code ?? -1,
Response = result != null ? JsonSerializer.Serialize(result) : null,
Response = (result != null ? JsonSerializer.Serialize(result) : null) ,
Authorization = context.Request.Headers.ContainsKey("Authorization")
? context.Request.Headers["Authorization"].ToString()
: string.Empty,
@ -193,18 +218,12 @@ namespace Learn.Archives.API.Expand
}
/// <summary>
/// 在Controller的Action执行前执行
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuting(ActionExecutingContext context)
public override async void OnActionExecuting(ActionExecutingContext context)
{
Executing400(context);
ExecutingFileCached(context);
base.OnActionExecuting(context);
}
@ -214,6 +233,8 @@ namespace Learn.Archives.API.Expand
/// <param name="context"></param>
public override async void OnActionExecuted(ActionExecutedContext context)
{
try
{
BaseReturn<object>? res = ApiResultFormatting(context);

View File

@ -17,17 +17,6 @@ builder.Services.AddLogging(loggingBuilder =>
loggingBuilder.SetMinimumLevel(LogLevel.Warning); // 设置最小日志级别为 Warning
});
builder.Services.AddControllers(options =>
{
// 全局模型赋值默认值 和 统一返回格式处理
options.Filters.Add<HttpLogAttribute>();
})
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);//中文转换时不使用Unicode
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;// 默认小驼峰 null 大驼峰
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerExpand("学校档案系统");
builder.Configuration.AddAppConfig(args);
@ -43,6 +32,17 @@ builder.Services.AddHttpContextAccessor();
builder.Services.AddControllers(options =>
{
// 全局模型赋值默认值 和 统一返回格式处理
options.Filters.Add<HttpLogAttribute>();
})
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);//中文转换时不使用Unicode
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;// 默认小驼峰 null 大驼峰
});
var app = builder.Build();
AppCommon.Services = app.Services;

View File

@ -19,7 +19,7 @@
"OtherDBArr": [
{
"ConfigId": 1001, //
"ConnectionString": "AllowLoadLocalInfile=true;Server=58.17.132.2;User ID=marking;Password=qwe123!@#;Port=3306;Database=usercenter;CharSet=utf8mb4;Port=43306;pooling=true;SslMode=None;",
"ConnectionString": "AllowLoadLocalInfile=true;Server=58.17.132.2;User ID=marking;Password=qwe123!@#;Port=3306;Database=usercenter_v1;CharSet=utf8mb4;Port=43306;pooling=true;SslMode=None;",
"SqlType": "MySql"
}
]

View File

@ -14,7 +14,7 @@
"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;",
"SqlType": "MySql",
"UpdateTable": false
"UpdateTable": true
},
"AuthKey": {
"Secret": "9FAB7AC7-F1DB-4C56-B84F-044055A34AF2",
@ -29,7 +29,7 @@
{
"ConfigId": 1001, //
//"ConnectionString": "AllowLoadLocalInfile=true;Server=192.168.2.9;User ID=root;Password=qwe123!@#;Port=3306;Database=usercenter;CharSet=utf8mb4;pooling=true;SslMode=None;",
"ConnectionString": "AllowLoadLocalInfile=true;Server=58.17.132.2;User ID=marking;Password=qwe123!@#;Port=3306;Database=usercenter;CharSet=utf8mb4;Port=43306;pooling=true;SslMode=None;",
"ConnectionString": "AllowLoadLocalInfile=true;Server=58.17.132.2;User ID=marking;Password=qwe123!@#;Port=3306;Database=usercenter_v1;CharSet=utf8mb4;Port=43306;pooling=true;SslMode=None;",
"SqlType": "MySql"
}
]

View File

@ -24,6 +24,9 @@ namespace Learn.Archives.Core.Common
public async Task InvokeAsync(HttpContext context)
{
if (!context.Request.Body.CanSeek)
context.Request.EnableBuffering(); // 允许重新读取请求体
if (context.Request.Path.StartsWithSegments("/swagger")
&& (context.Request.Path.Value?.Contains("swagger.json") ?? true))
{
@ -36,7 +39,6 @@ namespace Learn.Archives.Core.Common
if (await IsAuthorized(usernamePassword[0], usernamePassword[1]))
{
await _next(context);
return;
}

View File

@ -28,6 +28,6 @@
<PackageReference Include="SqlSugar.IOC" Version="2.0.0" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.170" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="UserCenter.Model" Version="1.4.3" />
<PackageReference Include="UserCenter.Model" Version="1.4.4" />
</ItemGroup>
</Project>

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

@ -51,7 +51,7 @@ namespace Learn.Archives.Core.Model.Dto
/// </summary>
public DateTime? ExecutionTime { get; set; }
/// <summary>
/// 操作人 [后台自动赋值提交人名称]
/// 操作人
/// </summary>
public string? Operator { get; set; }
public string? ExecutionTimeStr => ExecutionTime?.ToString("yyyy-MM-dd");
@ -86,6 +86,10 @@ namespace Learn.Archives.Core.Model.Dto
/// 解决时间
/// </summary>
public DateTime? EndTime { get; set; }
/// <summary>
/// 反馈问题的执行记录
/// </summary>
public RecordDto[]? RecordArr { get; set; }
public string? EndTimeStr=> EndTime?.ToString("yyyy-MM-dd");

View File

@ -10,6 +10,38 @@ using UserCenter.Model;
namespace Learn.Archives.Core.Model.Dto
{
public class PositionIdsReq
{
/// <summary>
/// 学校编号
/// </summary>
public long SchoolId { get; set; }
/// <summary>
/// 年级
/// </summary>
public string GradeLevel { get; set; }
/// <summary>
/// 毕业届
/// </summary>
public int GraduationYear { get; set; }
/// <summary>
/// 班级编号
/// </summary>
public long? ClassId { get; set; }
/// <summary>
/// 职级
/// </summary>
public int PositionLevel { get; set; }
public int? PositionType { get; set; } = 2;
/// <summary>
/// 科目
/// </summary>
public int? SubjectId { get; set; }
}
public class TeacherInfoImportError : TeacherInfoImport
{
/// <summary>
@ -51,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>
/// 科目
@ -129,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>
/// 减免金额
@ -263,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

@ -38,7 +38,8 @@ namespace Learn.Archives.Core.Model
/// </summary>
public string? _grade;
/// <summary>
/// 年级
/// 年级
/// <para>AOP自动转换年级</para>
/// </summary>
[SugarColumn(IsIgnore = true)]
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 SqlSugar;
using System.ComponentModel.DataAnnotations;
@ -71,18 +72,19 @@ namespace Learn.Archives.Core.Model
/// </summary>
public int GradeYear { get; set; }
/// <summary>
/// 上线率 考试排名
/// </summary>
public decimal OnLineRanking { get; set; }
/// <summary>
/// 上线率
/// </summary>
public decimal OnLineRate { get; set; }
/// <summary>
/// 上线人数
/// </summary>
public int OnLineCount { get; set; }
///// <summary>
///// 上线率 考试排名
///// </summary>
//public decimal OnLineRanking { get; set; }
///// <summary>
///// 上线率
///// </summary>
//public decimal OnLineRate { get; set; }
///// <summary>
///// 上线人数
///// </summary>
//public int OnLineCount { get; set; }
/// <summary>
/// 参加人数
/// </summary>

View File

@ -0,0 +1,86 @@
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 ClassId { 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(IsIgnore = true)]
public decimal OnLineRate => (decimal)OnLineCount / (decimal)PeopleCount;
/// <summary>
/// 总人数
/// </summary>
public int PeopleCount { 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; }
}
}

View File

@ -89,6 +89,12 @@ namespace Learn.Archives.Core.Model
[SugarColumn(IsNullable = true, Length = 1000)]
public string? ClassMeeting { get; set; }
/// <summary>
/// 预计解决时间
/// </summary>
[SugarColumn(IsNullable = true)]
public DateTime? EndTime { get; set; }
/// <summary>
/// 反馈问题数量
/// </summary>