using Furion.JsonSerialization;
using NPOI.SS.UserModel;
using YBEE.EQM.Core;
namespace YBEE.EQM.Application;
///
/// 高中成绩管理服务
///
public class NceeScoreService(IRepository rep) : INceeScoreService, ITransient
{
private readonly IRepository _rep = rep;
private readonly List _chooseCourses = [5, 6, 7, 9];
///
/// 上传成绩(仅原始分,适用于五区联考或本区独立赋分)
///
///
///
///
public async Task UploadOnlyRawScore(string filePath, int nceePlanId)
{
/* ----------------------------------------------------------
* 处理步骤:
* 1.验证表头
* 2.读取数据
* 3.处理学生
* 4.批量插入
---------------------------------------------------------- */
try
{
#region 1.验证表结构
using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
IWorkbook workbook = ExcelUtil.GetWorkbook(filePath, fs);
var sheet = workbook.GetSheetAt(0);
var rows = sheet.GetRowEnumerator();
var evaluator = ExcelUtil.GetEvaluator(workbook);
// 少于2行验证
if (sheet.LastRowNum < 2)
{
//"第一行应为填写说明,第二行应为标题行,请勿修改模板结构。"
return;
}
// 读取表头
rows.MoveNext();
IRow headerRow = (IRow)rows.Current;
int index = 0;
int ORG_ID = index++;
int ORG_NAME = index++;
int NAME_INDEX = index++;
int EXAM_NUMBER_INDEX = index++;
int CLASS_INDEX = index++;
int DIRECTION_INDEX = index++;
int DIRECTION_ID_INDEX = index++;
int COURSE_COMB_INDEX = index++;
int COURSE_COMB_ID_INDEX = index++;
int COURSE_START_INDEX = index;
Dictionary headers = new()
{
{ ORG_ID, "机构ID" },
{ ORG_NAME, "机构" },
{ NAME_INDEX, "姓名" },
{ EXAM_NUMBER_INDEX, "考号" },
{ CLASS_INDEX, "班级号" },
{ DIRECTION_INDEX, "选择方向" },
{ DIRECTION_ID_INDEX, "选择方向科目ID" },
{ COURSE_COMB_INDEX, "选科组合" },
{ COURSE_COMB_ID_INDEX, "选科组合ID" },
};
List headerErrors = [];
for (int i = 0; i < COURSE_START_INDEX; i++)
{
if (headerRow.GetCell(i)?.ToString() != headers[i])
{
char letter = (char)('A' + i);
headerErrors.Add(letter.ToString());
}
}
if (headerErrors.Count != 0)
{
string columnErrors = string.Join("、", headerErrors);
//result.ErrorMessage.Add($"第1行标题行{columnErrors}列名错误。从A列开始依次应为抽样类型、学校ID、学校、姓名、证件类型、证件号码、考号、年级、班级。");
//return result;
throw new Exception("列头错误");
}
//result.StructureCorrect = true;
#endregion
#region 2.读取数据
var plan = await _rep.Change().DetachedEntities.FirstOrDefaultAsync(t => t.Id == nceePlanId) ?? throw Oops.Oh(ErrorCode.E2001, "计划");
var courseDict = (await _rep.Change().DetachedEntities.ToListAsync()).ToDictionary(t => t.Name);
//var orgs = await _rep.Change().DetachedEntities.Where(t => t.EducationStage == EducationStage.SENIOR_HIGH_SCHOOL_STAGE).ToListAsync();
var courseCombs = await _rep.Change().DetachedEntities.ToListAsync();
var courseCombDict = courseCombs.ToDictionary(t => t.Id, t => t);
// 获取需要导入的科目列表
Dictionary courses = [];
int validCellNum = COURSE_START_INDEX;
for (int gi = COURSE_START_INDEX; gi < headerRow.LastCellNum; gi++)
{
var cn = headerRow.GetCell(gi)?.ToString()?.Trim() ?? "";
if (string.IsNullOrEmpty(cn))
{
continue;
}
courses.Add(gi, courseDict[cn]);
validCellNum = gi + 1;
}
int rn = 1;
List students = [];
List scores = [];
while (rows.MoveNext())
{
rn++;
IRow row = (IRow)rows.Current;
string rv = row.GetCell(0)?.ToString().Trim() ?? "";
if (rv == "")
{
break;
}
NceeStudentImportDto stu = new();
// 机构ID
if (short.TryParse(row.GetCell(ORG_ID)?.ToString(), out short orgId))
{
stu.SysOrgId = orgId;
}
else
{
throw new Exception($"[{rn}]机构ID错误");
}
// 姓名
stu.Name = row.GetCell(NAME_INDEX)?.ToString();
// 考号
stu.ExamNumber = row.GetCell(EXAM_NUMBER_INDEX)?.ToString();
// 班号
if (short.TryParse(row.GetCell(CLASS_INDEX)?.ToString(), out short cn))
{
stu.ClassNumber = cn;
}
else
{
throw new Exception($"[{rn}]班号错误");
}
// 方向ID
if (short.TryParse(row.GetCell(DIRECTION_ID_INDEX)?.ToString(), out short directionId))
{
stu.DirectionCourseId = directionId;
}
//else
//{
// throw new Exception($"[{rn}]方向ID错误");
//}
// 组合ID
if (short.TryParse(row.GetCell(COURSE_COMB_ID_INDEX)?.ToString(), out short courseCombId))
{
stu.NceeCourseCombId = courseCombId;
}
//else
//{
// throw new Exception($"[{rn}]组合ID错误");
//}
// 取各科成绩
int sc = 0;
for (int gi = COURSE_START_INDEX; gi < validCellNum; gi++)
{
var cell = row.GetCell(gi);
if (cell == null || cell.ToString().Trim() == "")
{
continue;
}
if (!courses.ContainsKey(gi)) { continue; }
var course = courses[gi];
NceeScoreImportDto item = new()
{
NceeStudentId = stu.Id,
CourseId = course.Id,
};
if (cell.CellType == CellType.Numeric)
{
item.Score = (decimal)cell.NumericCellValue;
}
else if (cell.CellType == CellType.Formula)
{
var cv = evaluator.Evaluate(cell);
if (cv.CellType == CellType.Numeric)
{
item.Score = (decimal)cv.NumberValue;
}
else
{
continue;
}
}
if (item.Score > 0)
{
if (!_chooseCourses.Any(t => t == course.Id))
{
item.ScoreX = item.Score;
}
scores.Add(item);
sc++;
}
}
if (sc > 0)
{
students.Add(stu);
}
}
workbook.Close();
fs.Close();
#endregion
#region 3.处理学生
// 清理学生
string deleteStudentSql = $"DELETE FROM ncee_student WHERE ncee_plan_id = {nceePlanId};";
await _rep.SqlNonQueryAsync(deleteStudentSql);
var uid = CurrentSysUserInfo.SysUserId;
if (uid == 0)
{
uid = 1;
}
List insertValues = [];
int scount = students.Count;
for (int i = 0; i < scount; i++)
{
var t = students[i];
string dcid = "NULL";
if (t.DirectionCourseId.HasValue)
{
dcid = t.DirectionCourseId.Value.ToString();
}
string nccid = "NULL";
if (t.NceeCourseCombId.HasValue)
{
nccid = t.NceeCourseCombId.Value.ToString();
}
insertValues.Add($"({t.Id}, {nceePlanId}, {t.SysOrgId}, {plan.GradeId}, {t.ClassNumber}, '{t.ExamNumber}', '{t.Name}', {dcid}, {nccid}, 0, 0)");
if ((i + 1) % 1000 == 0 || i == scount - 1)
{
string insertSql = $@"
INSERT INTO ncee_student(id, ncee_plan_id, sys_org_id, grade_id, class_number, exam_number, `name`, direction_course_id, ncee_course_comb_id, score, score_x) VALUES
{string.Join(",", insertValues)}
";
await _rep.SqlNonQueryAsync(insertSql);
insertValues.Clear();
}
}
#endregion
#region 4.批量导入
// 清理成绩
string deleteScoreSql = $"DELETE FROM ncee_score WHERE ncee_plan_id = {nceePlanId};";
await _rep.SqlNonQueryAsync(deleteScoreSql);
insertValues.Clear();
scount = scores.Count;
for (int i = 0; i < scount; i++)
{
var t = scores[i];
insertValues.Add($"({t.Id}, {nceePlanId}, {t.NceeStudentId}, {t.CourseId}, {t.Score}, {t.ScoreX})");
if ((i + 1) % 1000 == 0 || i == scount - 1)
{
string insertSql = $@"
INSERT INTO ncee_score(id, ncee_plan_id, ncee_student_id, course_id, score, score_x) VALUES
{string.Join(",", insertValues)}
";
await _rep.SqlNonQueryAsync(insertSql);
insertValues.Clear();
}
}
#endregion
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
File.Delete(filePath);
}
}
///
/// 上传成绩(带转换分和等级,适用于六校联考)
///
///
///
///
///
public async Task UploadWithConvertScore(string filePath, int nceePlanId)
{
/* ----------------------------------------------------------
* 处理步骤:
* 1.验证表头
* 2.读取数据
* 3.处理学生
* 4.批量插入
---------------------------------------------------------- */
try
{
#region 1.验证表结构
using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
IWorkbook workbook = ExcelUtil.GetWorkbook(filePath, fs);
var sheet = workbook.GetSheetAt(0);
var rows = sheet.GetRowEnumerator();
var evaluator = ExcelUtil.GetEvaluator(workbook);
// 少于2行验证
if (sheet.LastRowNum < 2)
{
//"第一行应为填写说明,第二行应为标题行,请勿修改模板结构。"
return;
}
// 读取表头
rows.MoveNext();
IRow headerRow = (IRow)rows.Current;
int index = 0;
int ORG_ID = index++;
int ORG_NAME = index++;
int NAME_INDEX = index++;
int EXAM_NUMBER_INDEX = index++;
int CLASS_INDEX = index++;
int DIRECTION_INDEX = index++;
int DIRECTION_ID_INDEX = index++;
int COURSE_COMB_INDEX = index++;
int COURSE_COMB_ID_INDEX = index++;
int COURSE_START_INDEX = index;
Dictionary headers = new()
{
{ ORG_ID, "机构ID" },
{ ORG_NAME, "机构" },
{ NAME_INDEX, "姓名" },
{ EXAM_NUMBER_INDEX, "考号" },
{ CLASS_INDEX, "班级号" },
{ DIRECTION_INDEX, "选择方向" },
{ DIRECTION_ID_INDEX, "选择方向科目ID" },
{ COURSE_COMB_INDEX, "选科组合" },
{ COURSE_COMB_ID_INDEX, "选科组合ID" },
};
List headerErrors = [];
for (int i = 0; i < COURSE_START_INDEX; i++)
{
if (headerRow.GetCell(i)?.ToString() != headers[i])
{
char letter = (char)('A' + i);
headerErrors.Add(letter.ToString());
}
}
if (headerErrors.Count != 0)
{
string columnErrors = string.Join("、", headerErrors);
//result.ErrorMessage.Add($"第1行标题行{columnErrors}列名错误。从A列开始依次应为抽样类型、学校ID、学校、姓名、证件类型、证件号码、考号、年级、班级。");
//return result;
throw new Exception("列头错误");
}
//result.StructureCorrect = true;
#endregion
#region 2.读取数据
var plan = await _rep.Change().DetachedEntities.FirstOrDefaultAsync(t => t.Id == nceePlanId) ?? throw Oops.Oh(ErrorCode.E2001, "计划");
var courseDict = (await _rep.Change().DetachedEntities.ToListAsync()).ToDictionary(t => t.Name);
//var orgs = await _rep.Change().DetachedEntities.Where(t => t.EducationStage == EducationStage.SENIOR_HIGH_SCHOOL_STAGE).ToListAsync();
var courseCombs = await _rep.Change().DetachedEntities.ToListAsync();
var courseCombDict = courseCombs.ToDictionary(t => t.Id, t => t);
var convertGrades = await _rep.Change().DetachedEntities.ToListAsync();
var convertGradeDict = convertGrades.ToDictionary(t => t.Name);
// 获取需要导入的科目列表
Dictionary courses = new();
int validCellNum = COURSE_START_INDEX;
for (int gi = COURSE_START_INDEX; gi < headerRow.LastCellNum; gi++)
{
var cn = headerRow.GetCell(gi)?.ToString()?.Trim() ?? "";
if (string.IsNullOrEmpty(cn))
{
continue;
}
string tm = cn[^1..].ToUpper();
var cnn = cn;
if (tm == "X" || tm == "G")
{
cnn = cn[..^1];
}
courses.Add(gi, new()
{
CourseName = cn,
Course = courseDict[cnn],
IsRawScore = tm != "X" && tm != "G",
IsConvertGrade = tm == "G",
IsConvertScore = tm == "X",
});
validCellNum = gi + 1;
}
int rn = 1;
List students = new();
List scores = new();
while (rows.MoveNext())
{
rn++;
IRow row = (IRow)rows.Current;
string rv = row.GetCell(0)?.ToString().Trim() ?? "";
if (rv == "")
{
break;
}
NceeStudentImportDto stu = new();
// 机构ID
if (short.TryParse(row.GetCell(ORG_ID)?.ToString(), out short orgId))
{
stu.SysOrgId = orgId;
}
else
{
throw new Exception($"[{rn}]机构ID错误");
}
// 姓名
stu.Name = row.GetCell(NAME_INDEX)?.ToString();
// 考号
stu.ExamNumber = row.GetCell(EXAM_NUMBER_INDEX)?.ToString();
// 班号
if (short.TryParse(row.GetCell(CLASS_INDEX)?.ToString(), out short cn))
{
stu.ClassNumber = cn;
}
else
{
throw new Exception($"[{rn}]班号错误");
}
// 方向ID
if (short.TryParse(row.GetCell(DIRECTION_ID_INDEX)?.ToString(), out short directionId))
{
stu.DirectionCourseId = directionId;
}
//else
//{
// throw new Exception($"[{rn}]方向ID错误");
//}
// 组合ID
if (short.TryParse(row.GetCell(COURSE_COMB_ID_INDEX)?.ToString(), out short courseCombId))
{
stu.NceeCourseCombId = courseCombId;
}
//else
//{
// throw new Exception($"[{rn}]组合ID错误");
//}
// 取各科成绩
List courseScores = [];
for (int gi = COURSE_START_INDEX; gi < validCellNum; gi++)
{
var cell = row.GetCell(gi);
if (cell == null || cell.ToString().Trim() == "")
{
continue;
}
if (!courses.ContainsKey(gi)) { continue; }
var course = courses[gi];
NceeScoreImportDto item;
if (course.IsConvertScore || course.IsConvertGrade)
{
item = courseScores.FirstOrDefault(t => t.CourseId == course.Course.Id);
}
else
{
item = new()
{
NceeStudentId = stu.Id,
CourseId = course.Course.Id,
};
}
if (course.IsConvertGrade == false)
{
decimal score = 0;
if (cell.CellType == CellType.Numeric)
{
score = (decimal)cell.NumericCellValue;
}
else if (cell.CellType == CellType.Formula)
{
var cv = evaluator.Evaluate(cell);
if (cv.CellType == CellType.Numeric)
{
score = (decimal)cv.NumberValue;
}
else
{
continue;
}
}
if (score > 0)
{
if (course.IsRawScore == true)
{
item.Score = score;
if (!_chooseCourses.Any(t => t == course.Course.Id))
{
item.ScoreX = score;
}
courseScores.Add(item);
}
else if (course.IsConvertScore == true)
{
item.ScoreX = score;
}
}
}
else
{
var gn = cell.ToString().Trim().ToUpper();
var g = convertGradeDict[gn];
item.NceeConvertGradeId = g.Id;
item.NceeConvertGradeName = g.Name;
}
}
if (courseScores.Count > 0)
{
stu.Score = courseScores.Sum(t => t.Score);
stu.ScoreX = courseScores.Sum(t => t.ScoreX);
students.Add(stu);
scores.AddRange(courseScores);
}
}
workbook.Close();
fs.Close();
#endregion
#region 3.处理学生
// 清理学生
string deleteStudentSql = $"DELETE FROM ncee_student WHERE ncee_plan_id = {nceePlanId};";
await _rep.SqlNonQueryAsync(deleteStudentSql);
var uid = CurrentSysUserInfo.SysUserId;
if (uid == 0)
{
uid = 1;
}
List insertValues = new();
int scount = students.Count;
for (int i = 0; i < scount; i++)
{
var t = students[i];
string dcid = "NULL";
if (t.DirectionCourseId.HasValue)
{
dcid = t.DirectionCourseId.Value.ToString();
}
string nccid = "NULL";
if (t.NceeCourseCombId.HasValue)
{
nccid = t.NceeCourseCombId.Value.ToString();
}
insertValues.Add($"({t.Id}, {nceePlanId}, {t.SysOrgId}, {plan.GradeId}, {t.ClassNumber}, '{t.ExamNumber}', '{t.Name}', {dcid}, {nccid}, {t.Score}, {t.ScoreX})");
if ((i + 1) % 1000 == 0 || i == scount - 1)
{
string insertSql = $@"
INSERT INTO ncee_student(id, ncee_plan_id, sys_org_id, grade_id, class_number, exam_number, `name`, direction_course_id, ncee_course_comb_id, score, score_x) VALUES
{string.Join(",", insertValues)}
";
await _rep.SqlNonQueryAsync(insertSql);
insertValues.Clear();
}
}
#endregion
#region 4.批量导入
// 清理成绩
string deleteScoreSql = $"DELETE FROM ncee_score WHERE ncee_plan_id = {nceePlanId};";
await _rep.SqlNonQueryAsync(deleteScoreSql);
insertValues.Clear();
scount = scores.Count;
for (int i = 0; i < scount; i++)
{
var t = scores[i];
string ncgid = "NULL";
if (t.NceeConvertGradeId.HasValue)
{
ncgid = t.NceeConvertGradeId.Value.ToString();
}
insertValues.Add($"({t.Id}, {nceePlanId}, {t.NceeStudentId}, {t.CourseId}, {ncgid}, '{t.NceeConvertGradeName}', {t.Score}, {t.ScoreX})");
if ((i + 1) % 1000 == 0 || i == scount - 1)
{
string insertSql = $@"
INSERT INTO ncee_score(id, ncee_plan_id, ncee_student_id, course_id, ncee_convert_grade_id, ncee_convert_grade_name, score, score_x) VALUES
{string.Join(",", insertValues)}
";
await _rep.SqlNonQueryAsync(insertSql);
insertValues.Clear();
}
}
#endregion
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
File.Delete(filePath);
}
}
///
/// 上传未选科原始成绩(适用于高一未选科)
///
///
///
///
///
public async Task UploadNoDirectionCourse(string filePath, int nceePlanId)
{
/* ----------------------------------------------------------
* 处理步骤:
* 1.验证表头
* 2.读取数据
* 3.处理学生
* 4.批量插入
---------------------------------------------------------- */
try
{
#region 1.验证表结构
using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
IWorkbook workbook = ExcelUtil.GetWorkbook(filePath, fs);
var sheet = workbook.GetSheetAt(0);
var rows = sheet.GetRowEnumerator();
var evaluator = ExcelUtil.GetEvaluator(workbook);
// 少于2行验证
if (sheet.LastRowNum < 2)
{
//"第一行应为填写说明,第二行应为标题行,请勿修改模板结构。"
return;
}
// 读取表头
rows.MoveNext();
IRow headerRow = (IRow)rows.Current;
int index = 0;
int ORG_ID = index++;
int ORG_NAME = index++;
int NAME_INDEX = index++;
int EXAM_NUMBER_INDEX = index++;
int CLASS_INDEX = index++;
int COURSE_START_INDEX = index;
Dictionary headers = new()
{
{ ORG_ID, "机构ID" },
{ ORG_NAME, "机构" },
{ NAME_INDEX, "姓名" },
{ EXAM_NUMBER_INDEX, "考号" },
{ CLASS_INDEX, "班级号" },
};
List headerErrors = [];
for (int i = 0; i < COURSE_START_INDEX; i++)
{
if (headerRow.GetCell(i)?.ToString() != headers[i])
{
char letter = (char)('A' + i);
headerErrors.Add(letter.ToString());
}
}
if (headerErrors.Any())
{
string columnErrors = string.Join("、", headerErrors);
//result.ErrorMessage.Add($"第1行标题行{columnErrors}列名错误。从A列开始依次应为抽样类型、学校ID、学校、姓名、证件类型、证件号码、考号、年级、班级。");
//return result;
throw new Exception("列头错误");
}
//result.StructureCorrect = true;
#endregion
#region 2.读取数据
var plan = await _rep.Change().DetachedEntities.FirstOrDefaultAsync(t => t.Id == nceePlanId) ?? throw Oops.Oh(ErrorCode.E2001, "计划");
var courseDict = (await _rep.Change().DetachedEntities.ToListAsync()).ToDictionary(t => t.Name);
// 获取需要导入的科目列表
Dictionary courses = new();
int validCellNum = COURSE_START_INDEX;
for (int gi = COURSE_START_INDEX; gi < headerRow.LastCellNum; gi++)
{
var cn = headerRow.GetCell(gi)?.ToString()?.Trim() ?? "";
if (string.IsNullOrEmpty(cn))
{
continue;
}
courses.Add(gi, courseDict[cn]);
validCellNum = gi + 1;
}
int rn = 1;
List students = new();
List scores = new();
while (rows.MoveNext())
{
rn++;
IRow row = (IRow)rows.Current;
string rv = row.GetCell(0)?.ToString().Trim() ?? "";
if (rv == "")
{
break;
}
NceeStudentImportDto stu = new();
// 机构ID
if (short.TryParse(row.GetCell(ORG_ID)?.ToString(), out short orgId))
{
stu.SysOrgId = orgId;
}
else
{
throw new Exception($"[{rn}]机构ID错误");
}
// 姓名
stu.Name = row.GetCell(NAME_INDEX)?.ToString();
// 考号
stu.ExamNumber = row.GetCell(EXAM_NUMBER_INDEX)?.ToString();
// 班号
if (short.TryParse(row.GetCell(CLASS_INDEX)?.ToString(), out short cn))
{
stu.ClassNumber = cn;
}
else
{
throw new Exception($"[{rn}]班号错误");
}
// 取各科成绩
List courseScores = new();
for (int gi = COURSE_START_INDEX; gi < validCellNum; gi++)
{
var cell = row.GetCell(gi);
if (cell == null || cell.ToString().Trim() == "")
{
continue;
}
if (!courses.ContainsKey(gi)) { continue; }
var course = courses[gi];
NceeScoreImportDto item = new()
{
NceeStudentId = stu.Id,
CourseId = course.Id,
};
decimal score = 0;
if (cell.CellType == CellType.Numeric)
{
score = (decimal)cell.NumericCellValue;
}
else if (cell.CellType == CellType.Formula)
{
var cv = evaluator.Evaluate(cell);
if (cv.CellType == CellType.Numeric)
{
score = (decimal)cv.NumberValue;
}
else
{
continue;
}
}
if (score > 0)
{
item.Score = score;
item.ScoreX = score;
courseScores.Add(item);
}
}
if (courseScores.Count > 0)
{
stu.Score = courseScores.Sum(t => t.Score);
stu.ScoreX = courseScores.Sum(t => t.ScoreX);
students.Add(stu);
scores.AddRange(courseScores);
}
}
workbook.Close();
fs.Close();
#endregion
#region 3.处理学生
// 清理学生
string deleteStudentSql = $"DELETE FROM ncee_student WHERE ncee_plan_id = {nceePlanId};";
await _rep.SqlNonQueryAsync(deleteStudentSql);
var uid = CurrentSysUserInfo.SysUserId;
if (uid == 0)
{
uid = 1;
}
List insertValues = new();
int scount = students.Count;
for (int i = 0; i < scount; i++)
{
var t = students[i];
insertValues.Add($"({t.Id}, {nceePlanId}, {t.SysOrgId}, {plan.GradeId}, {t.ClassNumber}, '{t.ExamNumber}', '{t.Name}', 99, 0, {t.Score}, {t.ScoreX})");
if ((i + 1) % 1000 == 0 || i == scount - 1)
{
string insertSql = $@"
INSERT INTO ncee_student(id, ncee_plan_id, sys_org_id, grade_id, class_number, exam_number, `name`, direction_course_id, ncee_course_comb_id, score, score_x) VALUES
{string.Join(",", insertValues)}
";
await _rep.SqlNonQueryAsync(insertSql);
insertValues.Clear();
}
}
#endregion
#region 4.批量导入
// 清理成绩
string deleteScoreSql = $"DELETE FROM ncee_score WHERE ncee_plan_id = {nceePlanId};";
await _rep.SqlNonQueryAsync(deleteScoreSql);
insertValues.Clear();
scount = scores.Count;
for (int i = 0; i < scount; i++)
{
var t = scores[i];
insertValues.Add($"({t.Id}, {nceePlanId}, {t.NceeStudentId}, {t.CourseId}, NULL, '', {t.Score}, {t.ScoreX})");
if ((i + 1) % 1000 == 0 || i == scount - 1)
{
string insertSql = $@"
INSERT INTO ncee_score(id, ncee_plan_id, ncee_student_id, course_id, ncee_convert_grade_id, ncee_convert_grade_name, score, score_x) VALUES
{string.Join(",", insertValues)}
";
await _rep.SqlNonQueryAsync(insertSql);
insertValues.Clear();
}
}
#endregion
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
File.Delete(filePath);
}
}
///
/// 执行模拟划线
///
///
///
public async Task Execute(int nceePlanId)
{
var nceePlan = await _rep.Change().FirstOrDefaultAsync(t => t.Id == nceePlanId) ?? throw Oops.Oh(ErrorCode.E2001);
var nceePlanConfig = JSON.Deserialize(nceePlan.Config);
// 执行分数转换
if (nceePlanConfig.ConvertEnabled)
{
await ExecuteScoreConvert(nceePlanId);
}
else
{
await ExecuteUpdateOrder(nceePlanId);
}
// 执行划线
await ExecuteLine(nceePlanId, nceePlanConfig);
}
#region 私有方法
///
/// 执行划线
///
///
///
///
private async Task ExecuteLine(int nceePlanId, NceePlanConfig config)
{
var baseLines = await _rep.Change().Where(t => t.NceePlanId == nceePlanId).OrderBy(t => t.NceeLineLevel).ToListAsync();
// 单科有效分
List courseLineScores = [];
#region 计算总有效分
if (config.CalcTotalLineScoreEnabled)
{
foreach (var line in baseLines)
{
// 计算总有效分
var lineScoreX = await _rep.SqlScalarAsync(@$"
SELECT MIN(score_x) AS score_x
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY score_x DESC) AS rn, score_x
FROM ncee_student
WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId
) AS T1
WHERE T1.rn <= (SELECT COUNT(1) FROM ncee_student WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId) * @lineRate
", new { NceePlanId = nceePlanId, line.DirectionCourseId, line.LineRate });
line.LineScoreX = lineScoreX;
}
await _rep.Change().UpdateNowAsync(baseLines);
}
#endregion
#region 计算单科有效分
if (config.CalcCourseLineScoreEnabled)
{
// 1.总分排序,合并单科独立排序
// 2.取总分上线分对应行的单科成绩为有效分
foreach (var line in baseLines)
{
// 计算单科有效分
var courseLineScoreX = await _rep.SqlQueryAsync($@"
SELECT
MIN(T1.yuwen_score_x) AS yuwen_score_x, -- 语文
MIN(T1.shuxue_score_x) AS shuxue_score_x, -- 数学
MIN(T1.yingyu_score_x) AS yingyu_score_x, -- 英语
MIN(T1.fangxiang_score_x) AS fangxiang_score_x, -- 方向(物理或历史)
MIN(T1.zonghe_score_x) AS zonghe_score_x -- 综合
FROM
(
SELECT T1.rn,
T2.score_x AS yuwen_score_x,
T3.score_x AS shuxue_score_x,
T4.score_x AS yingyu_score_x,
T5.score_x AS fangxiang_score_x,
T6.score_x AS zonghe_score_x,
IFNULL(T2.score_x, 0) + IFNULL(T3.score_x, 0) + IFNULL(T4.score_x, 0) + IFNULL(T5.score_x, 0) + IFNULL(T6.score_x, 0) AS score_x
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY score_x DESC) AS rn
FROM ncee_student AS T1
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId
) AS T1
LEFT JOIN
(
SELECT ROW_NUMBER() OVER(ORDER BY T2.score_x DESC) AS rn, T2.score_x
FROM ncee_student AS T1
JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id = 1
) AS T2 ON T1.rn = T2.rn
LEFT JOIN
(
SELECT ROW_NUMBER() OVER(ORDER BY T2.score_x DESC) AS rn, T2.score_x
FROM ncee_student AS T1
JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id = 2
) AS T3 ON T1.rn = T3.rn
LEFT JOIN
(
SELECT ROW_NUMBER() OVER(ORDER BY T2.score_x DESC) AS rn, T2.score_x
FROM ncee_student AS T1
JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id = 3
) AS T4 ON T1.rn = T4.rn
LEFT JOIN
(
SELECT ROW_NUMBER() OVER(ORDER BY T2.score_x DESC) AS rn, T2.score_x
FROM ncee_student AS T1
JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id = @directionCourseId
) AS T5 ON T1.rn = T5.rn
LEFT JOIN
(
SELECT ROW_NUMBER() OVER(ORDER BY T1.score_x DESC) AS rn, t1.score_x
FROM
(
SELECT T2.ncee_student_id, SUM(T2.score_x) AS score_x
FROM ncee_student AS T1
JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id IN(5, 6, 7, 9)
GROUP BY T2.ncee_student_id
) AS T1
) AS T6 ON T1.rn = T6.rn
) AS T1
WHERE T1.score_x >= @totalLineScoreX
", new { NceePlanId = nceePlanId, line.DirectionCourseId, TotalLineScoreX = line.LineScoreX });
var cline = courseLineScoreX.FirstOrDefault();
if (cline != null)
{
courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = 1, LineScoreX = cline.YuwenScoreX });
courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = 2, LineScoreX = cline.ShuxueScoreX });
courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = 3, LineScoreX = cline.YingyuScoreX });
courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = line.DirectionCourseId, LineScoreX = cline.FangxiangScoreX });
courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = 101, LineScoreX = cline.ZongheScoreX });
}
}
await _rep.Change().Where(t => t.NceePlanId == nceePlanId).ExecuteDeleteAsync();
List totalLines = new();
foreach (var line in baseLines)
{
totalLines.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = 100, LineScoreX = line.LineScoreX });
}
await _rep.Change().InsertNowAsync(totalLines);
await _rep.Change().InsertNowAsync(courseLineScores);
}
else
{
courseLineScores = await _rep.Change().Where(t => t.NceePlanId == nceePlanId).ToListAsync();
}
#endregion
#region 计算总分上线
// 清除数据
await _rep.Change().Where(t => t.NceePlanId == nceePlanId).ExecuteDeleteAsync();
// 总分划线
foreach (var line in baseLines)
{
// 整体 - 方向
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_total(type, ncee_plan_id, ncee_line_level, direction_course_id, grade_id, line_count, total_count, line_rate)
SELECT {(short)NceeDataScopeType.TOTAL}, @nceePlanId, @nceeLineLevel, T1.*, T1.line_count / T1.total_count AS line_rate
FROM
(
SELECT
T1.direction_course_id,
T1.grade_id,
COUNT(1) AS line_count,
(
SELECT COUNT(1) AS total_count
FROM ncee_student
WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId AND score_x > 0
) AS total_count
FROM ncee_student AS T1
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T1.score_x >= @lineScoreX
GROUP BY T1.direction_course_id, T1.grade_id
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX });
// 机构 - 方向
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_total(type, ncee_plan_id, ncee_line_level, direction_course_id, sys_org_id, grade_id, line_count, total_count, line_rate)
SELECT {(short)NceeDataScopeType.ORG}, @nceePlanId, @nceeLineLevel, T1.*, T1.line_count / T1.total_count AS line_rate
FROM
(
SELECT
T1.direction_course_id,
T1.sys_org_id,
T1.grade_id,
COUNT(1) AS line_count,
T2.total_count
FROM ncee_student AS T1
JOIN
(
SELECT sys_org_id, COUNT(1) AS total_count
FROM ncee_student
WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId AND score_x > 0
GROUP BY sys_org_id
) AS T2 ON T1.sys_org_id = T2.sys_org_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T1.score_x >= @lineScoreX
GROUP BY T1.direction_course_id, T1.sys_org_id, T1.grade_id
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX });
// 机构 - 方向 - 组合
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_total(type, ncee_plan_id, ncee_line_level, direction_course_id, ncee_course_comb_id, sys_org_id, grade_id, line_count, total_count, line_rate)
SELECT {(short)NceeDataScopeType.COMB}, @nceePlanId, @nceeLineLevel, T1.*, T1.line_count / T1.total_count AS line_rate
FROM
(
SELECT
T1.direction_course_id,
T1.ncee_course_comb_id,
T1.sys_org_id,
T1.grade_id,
COUNT(1) AS line_count,
T2.total_count
FROM ncee_student AS T1
JOIN
(
SELECT ncee_course_comb_id, sys_org_id, COUNT(1) AS total_count
FROM ncee_student
WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId AND score_x > 0
GROUP BY ncee_course_comb_id, sys_org_id
) AS T2 ON T1.sys_org_id = T2.sys_org_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T1.ncee_course_comb_id = T2.ncee_course_comb_id AND T1.score_x >= @lineScoreX
GROUP BY T1.direction_course_id, T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX });
// 机构 - 班级 - 方向 - 组合
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_total(type, ncee_plan_id, ncee_line_level, direction_course_id, ncee_course_comb_id, sys_org_id, grade_id, class_number, line_count, total_count, line_rate)
SELECT {(short)NceeDataScopeType.CLASS}, @nceePlanId, @nceeLineLevel, T1.*, T1.line_count / T1.total_count AS line_rate
FROM
(
SELECT
T1.direction_course_id,
T1.ncee_course_comb_id,
T1.sys_org_id,
T1.grade_id,
T1.class_number,
COUNT(1) AS line_count,
T2.total_count
FROM ncee_student AS T1
JOIN
(
SELECT ncee_course_comb_id, sys_org_id, class_number, COUNT(1) AS total_count
FROM ncee_student
WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId AND score_x > 0
GROUP BY ncee_course_comb_id, sys_org_id, class_number
) AS T2 ON T1.sys_org_id = T2.sys_org_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T1.ncee_course_comb_id = T2.ncee_course_comb_id AND T1.class_number = T2.class_number AND T1.score_x >= @lineScoreX
GROUP BY T1.direction_course_id, T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX });
}
#endregion
#region 计算科目有效分上线
// 清除数据
await _rep.Change().Where(t => t.NceePlanId == nceePlanId).ExecuteDeleteAsync();
// 总分划线
foreach (var line in baseLines)
{
var courseLines = courseLineScores.Where(t => t.DirectionCourseId == line.DirectionCourseId && t.NceeLineLevel == line.NceeLineLevel).ToList();
foreach (var courseLine in courseLines)
{
string inCourses = courseLine.CourseId.ToString();
if (courseLine.CourseId == 101)
{
inCourses = "5, 6, 7, 9";
}
// 单上线:整体 - 方向
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_course(type, ncee_plan_id, ncee_line_level, direction_course_id, course_id, grade_id, line_count, total_count, line_rate, is_double_line)
SELECT {(short)NceeDataScopeType.TOTAL}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 0
FROM
(
SELECT
T1.grade_id,
COUNT(1) AS line_count,
(
SELECT COUNT(1) AS total_count
FROM
(
SELECT DISTINCT T1.grade_id, T2.ncee_student_id
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.grade_id, T2.ncee_student_id
) AS T1
) AS total_count
FROM
(
SELECT T1.grade_id, T2.ncee_student_id, SUM(T2.score_x) AS course_score_x
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.grade_id, T2.ncee_student_id
) AS T1
WHERE T1.course_score_x >= @courseLineScoreX
GROUP BY T1.grade_id
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
// 双上线:整体 - 方向
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_course(type, ncee_plan_id, ncee_line_level, direction_course_id, course_id, grade_id, line_count, total_count, line_rate, is_double_line)
SELECT {(short)NceeDataScopeType.TOTAL}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 1
FROM
(
SELECT
T1.grade_id,
COUNT(1) AS line_count,
(
SELECT COUNT(1) AS total_count
FROM
(
SELECT DISTINCT T1.grade_id, T2.ncee_student_id
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.grade_id, T2.ncee_student_id
) AS T1
) AS total_count
FROM
(
SELECT T1.grade_id, T2.ncee_student_id, MAX(T1.score_x) AS score_x, SUM(T2.score_x) AS course_score_x
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.grade_id, T2.ncee_student_id
) AS T1
WHERE T1.score_x >= @lineScoreX AND T1.course_score_x >= @courseLineScoreX
GROUP BY T1.grade_id
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
// 单上线:机构 - 方向
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_course(type, ncee_plan_id, ncee_line_level, direction_course_id, course_id, sys_org_id, grade_id, line_count, total_count, line_rate, is_double_line)
SELECT {(short)NceeDataScopeType.ORG}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 0
FROM
(
SELECT
T1.sys_org_id,
T1.grade_id,
COUNT(1) AS line_count,
T2.total_count
FROM
(
SELECT T1.sys_org_id, T1.grade_id, T2.ncee_student_id, SUM(T2.score_x) AS course_score_x
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.sys_org_id, T1.grade_id, T2.ncee_student_id
) AS T1
JOIN
(
SELECT T1.sys_org_id, COUNT(1) AS total_count
FROM
(
SELECT DISTINCT T1.sys_org_id, T1.grade_id, T2.ncee_student_id
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.sys_org_id, T1.grade_id, T2.ncee_student_id
) AS T1
GROUP BY T1.sys_org_id
) AS T2 ON T1.sys_org_id = T2.sys_org_id
WHERE T1.course_score_x >= @courseLineScoreX
GROUP BY T1.sys_org_id, T1.grade_id
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
// 双上线:机构 - 方向
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_course(type, ncee_plan_id, ncee_line_level, direction_course_id, course_id, sys_org_id, grade_id, line_count, total_count, line_rate, is_double_line)
SELECT {(short)NceeDataScopeType.ORG}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 1
FROM
(
SELECT
T1.sys_org_id,
T1.grade_id,
COUNT(1) AS line_count,
T2.total_count
FROM
(
SELECT T1.sys_org_id, T1.grade_id, T2.ncee_student_id, MAX(T1.score_x) AS score_x, SUM(T2.score_x) AS course_score_x
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.sys_org_id, T1.grade_id, T2.ncee_student_id
) AS T1
JOIN
(
SELECT T1.sys_org_id, COUNT(1) AS total_count
FROM
(
SELECT DISTINCT T1.sys_org_id, T1.grade_id, T2.ncee_student_id
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.sys_org_id, T1.grade_id, T2.ncee_student_id
) AS T1
GROUP BY T1.sys_org_id
) AS T2 ON T1.sys_org_id = T2.sys_org_id
WHERE T1.score_x >= @lineScoreX AND T1.course_score_x >= @courseLineScoreX
GROUP BY T1.sys_org_id, T1.grade_id
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
// 单上线:机构 - 方向 - 组合
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_course(type, ncee_plan_id, ncee_line_level, direction_course_id, course_id, ncee_course_comb_id, sys_org_id, grade_id, line_count, total_count, line_rate, is_double_line)
SELECT {(short)NceeDataScopeType.COMB}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 0
FROM
(
SELECT
T1.ncee_course_comb_id,
T1.sys_org_id,
T1.grade_id,
COUNT(1) AS line_count,
T2.total_count
FROM
(
SELECT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id, SUM(T2.score_x) AS course_score_x
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
) AS T1
JOIN
(
SELECT T1.ncee_course_comb_id, T1.sys_org_id, COUNT(1) AS total_count
FROM
(
SELECT DISTINCT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
) AS T1
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id
) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.ncee_course_comb_id = T2.ncee_course_comb_id
WHERE T1.course_score_x >= @courseLineScoreX
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
// 双上线:机构 - 方向 - 组合
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_course(type, ncee_plan_id, ncee_line_level, direction_course_id, course_id, ncee_course_comb_id, sys_org_id, grade_id, line_count, total_count, line_rate, is_double_line)
SELECT {(short)NceeDataScopeType.COMB}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 1
FROM
(
SELECT
T1.ncee_course_comb_id,
T1.sys_org_id,
T1.grade_id,
COUNT(1) AS line_count,
T2.total_count
FROM
(
SELECT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id, MAX(T1.score_x) AS score_x, SUM(T2.score_x) AS course_score_x
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
) AS T1
JOIN
(
SELECT T1.ncee_course_comb_id, T1.sys_org_id, COUNT(1) AS total_count
FROM
(
SELECT DISTINCT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
) AS T1
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id
) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.ncee_course_comb_id = T2.ncee_course_comb_id
WHERE T1.score_x >= @lineScoreX AND T1.course_score_x >= @courseLineScoreX
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
// 机构 - 班级 - 方向 - 组合
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_course(type, ncee_plan_id, ncee_line_level, direction_course_id, course_id, ncee_course_comb_id, sys_org_id, grade_id, class_number, line_count, total_count, line_rate, is_double_line)
SELECT {(short)NceeDataScopeType.CLASS}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 0
FROM
(
SELECT
T1.ncee_course_comb_id,
T1.sys_org_id,
T1.grade_id,
T1.class_number,
COUNT(1) AS line_count,
T2.total_count
FROM
(
SELECT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id, SUM(T2.score_x) AS course_score_x
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
) AS T1
JOIN
(
SELECT T1.ncee_course_comb_id, T1.sys_org_id, T1.class_number, COUNT(1) AS total_count
FROM
(
SELECT DISTINCT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
) AS T1
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.class_number
) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.ncee_course_comb_id = T2.ncee_course_comb_id AND T1.class_number = T2.class_number
WHERE T1.course_score_x >= @courseLineScoreX
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
// 机构 - 班级 - 方向 - 组合
await _rep.SqlNonQueryAsync($@"
INSERT INTO ncee_line_course(type, ncee_plan_id, ncee_line_level, direction_course_id, course_id, ncee_course_comb_id, sys_org_id, grade_id, class_number, line_count, total_count, line_rate, is_double_line)
SELECT {(short)NceeDataScopeType.CLASS}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 1
FROM
(
SELECT
T1.ncee_course_comb_id,
T1.sys_org_id,
T1.grade_id,
T1.class_number,
COUNT(1) AS line_count,
T2.total_count
FROM
(
SELECT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id, MAX(T1.score_x) AS score_x, SUM(T2.score_x) AS course_score_x
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
) AS T1
JOIN
(
SELECT T1.ncee_course_comb_id, T1.sys_org_id, T1.class_number, COUNT(1) AS total_count
FROM
(
SELECT DISTINCT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
FROM ncee_student AS T1
LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
) AS T1
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.class_number
) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.ncee_course_comb_id = T2.ncee_course_comb_id AND T1.class_number = T2.class_number
WHERE T1.score_x >= @lineScoreX AND T1.course_score_x >= @courseLineScoreX
GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number
) AS T1
", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
}
}
#endregion
}
///
/// 执行分数转换
///
///
///
private async Task ExecuteScoreConvert(int nceePlanId)
{
await _rep.Change().Where(t => t.NceePlanId == nceePlanId).ExecuteDeleteAsync();
var convertGrades = await _rep.Change().DetachedEntities.OrderBy(t => t.Sequence).ToListAsync();
var convertGradeDict = convertGrades.ToDictionary(t => t.Id, t => t);
// 分科转换
foreach (var courseId in _chooseCourses)
{
var scores = await _rep.DetachedEntities.Where(t => t.NceeStudent.NceePlanId == nceePlanId && t.CourseId == courseId && t.Score > 0).OrderByDescending(t => t.Score).ToListAsync();
if (scores.Count == 0)
{
continue;
}
var convertRanges = GetConvertRange(nceePlanId, courseId, convertGrades, scores);
// 更新转换区间
await _rep.Change().Where(t => t.NceePlanId == nceePlanId && t.CourseId == courseId).ExecuteDeleteAsync();
await _rep.Change().InsertNowAsync(convertRanges);
// 更新转换分
List replaceValues = [];
int cscount = scores.Count;
for (int i = 0; i < cscount; i++)
{
var s = scores[i];
var cr = convertRanges.FirstOrDefault(t => s.Score >= t.MinScore && s.Score <= t.MaxScore);
var cg = convertGradeDict[cr.NceeConvertGradeId];
var scoreX = GetScoreX(s.Score, cg, cr);
replaceValues.Add($"({s.Id}, {nceePlanId}, {s.NceeStudentId}, {s.CourseId}, {s.Score}, {scoreX}, {cr.NceeConvertGradeId}, '{cg.Name}')");
if ((i + 1) % 1000 == 0 || i == cscount - 1)
{
string replaceSql = $@"
REPLACE INTO ncee_score(id, ncee_plan_id, ncee_student_id, course_id, score, score_x, ncee_convert_grade_id, ncee_convert_grade_name) VALUES
{string.Join(",", replaceValues)}
";
await _rep.SqlNonQueryAsync(replaceSql);
replaceValues.Clear();
}
}
}
// 更新总分
await _rep.SqlNonQueryAsync($@"
-- 更新总分
UPDATE ncee_student AS T1
JOIN
(
SELECT ncee_student_id, SUM(score) AS score, SUM(score_x) AS score_x
FROM ncee_score
WHERE ncee_plan_id = {nceePlanId}
GROUP BY ncee_student_id
) AS T2 ON T1.id = T2.ncee_student_id
SET T1.score = T2.score, T1.score_x = T2.score_x
WHERE T1.ncee_plan_id = {nceePlanId}
;
-- 更新排名
UPDATE ncee_student AS T1
JOIN
(
SELECT id,
RANK() OVER(PARTITION BY direction_course_id ORDER BY score DESC) AS order_in_total,
RANK() OVER(PARTITION BY direction_course_id ORDER BY score_x DESC) AS order_in_total_x,
RANK() OVER(PARTITION BY direction_course_id, sys_org_id ORDER BY score DESC) AS order_in_org,
RANK() OVER(PARTITION BY direction_course_id, sys_org_id ORDER BY score_x DESC) AS order_in_org_x
FROM ncee_student
WHERE ncee_plan_id = {nceePlanId}
) AS T2 ON T1.id = T2.id
SET T1.order_in_total = T2.order_in_total,
T1.order_in_total_x = T2.order_in_total_x,
T1.order_in_org = T2.order_in_org,
T1.order_in_org_x = T2.order_in_org_x
;
");
}
///
/// 更新排名
///
///
///
private async Task ExecuteUpdateOrder(int nceePlanId)
{
// 更新总分
await _rep.SqlNonQueryAsync($@"
-- 更新排名
UPDATE ncee_student AS T1
JOIN
(
SELECT id,
RANK() OVER(PARTITION BY direction_course_id ORDER BY score DESC) AS order_in_total,
RANK() OVER(PARTITION BY direction_course_id ORDER BY score_x DESC) AS order_in_total_x,
RANK() OVER(PARTITION BY direction_course_id, sys_org_id ORDER BY score DESC) AS order_in_org,
RANK() OVER(PARTITION BY direction_course_id, sys_org_id ORDER BY score_x DESC) AS order_in_org_x
FROM ncee_student
WHERE ncee_plan_id = {nceePlanId}
) AS T2 ON T1.id = T2.id
SET T1.order_in_total = T2.order_in_total,
T1.order_in_total_x = T2.order_in_total_x,
T1.order_in_org = T2.order_in_org,
T1.order_in_org_x = T2.order_in_org_x
");
}
///
/// 获取转换区间
///
///
///
///
///
///
private static List GetConvertRange(int nceePlanId, short courseId, List convertGrades, List nceeScores)
{
int scount = nceeScores.Count;
var totalMaxScore = nceeScores.Select(t => t.Score).Max();
var totalMinScore = nceeScores.Select(t => t.Score).Min();
var cgs = convertGrades.OrderBy(t => t.Id).ToList();
var scores = nceeScores.OrderByDescending(t => t.Score).ToList();
List ncrs = [];
decimal lastMinScore = decimal.MaxValue;
foreach (var cg in cgs)
{
NceeConvertRange range = new()
{
NceePlanId = nceePlanId,
NceeConvertGradeId = cg.Id,
CourseId = courseId,
};
var i = (int)Math.Min(Math.Floor(cg.EndRate * scount), scount - 1);
if (cg.BeginRate == 0)
{
range.MaxScore = totalMaxScore;
}
else
{
range.MaxScore = scores.Where(t => t.Score < lastMinScore).Select(t => t.Score).Max();
}
if (cg.EndRate == 1)
{
range.MinScore = totalMinScore;
}
else
{
range.MinScore = scores[i].Score;
}
lastMinScore = range.MinScore;
ncrs.Add(range);
}
return ncrs;
}
///
/// 获取转换分
///
///
///
///
///
private static decimal GetScoreX(decimal score, NceeConvertGrade convertGrade, NceeConvertRange convertRange)
{
// (Y2 - Y) / (Y- Y1) = (X2 - X) / (X - X1)
// Y1,Y2为原始分区间下限和上限
// X1,X2为转换分区间下限和上限
// Y为原始分
// X为转换分
// a = Y2 - Y
var a = (convertRange.MaxScore - score);
// b = Y - Y1
var b = (score - convertRange.MinScore);
return Math.Round((b * convertGrade.MaxScore + a * convertGrade.MinScore) / (a + b));
}
#endregion
}