NceeScoreService.cs 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689
  1. using Furion.JsonSerialization;
  2. using NPOI.SS.UserModel;
  3. using YBEE.EQM.Core;
  4. namespace YBEE.EQM.Application;
  5. /// <summary>
  6. /// 高中成绩管理服务
  7. /// </summary>
  8. public class NceeScoreService(IRepository<NceeScore> rep) : INceeScoreService, ITransient
  9. {
  10. /// <summary>
  11. /// 上传成绩(仅原始分,适用于五区联考或本区独立赋分)
  12. /// </summary>
  13. /// <param name="filePath"></param>
  14. /// <param name="nceePlanId"></param>
  15. /// <returns></returns>
  16. public async Task UploadOnlyRawScore(string filePath, int nceePlanId)
  17. {
  18. /* ----------------------------------------------------------
  19. * 处理步骤:
  20. * 1.验证表头
  21. * 2.读取数据
  22. * 3.处理学生
  23. * 4.批量插入
  24. ---------------------------------------------------------- */
  25. try
  26. {
  27. #region 1.验证表结构
  28. using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
  29. IWorkbook workbook = ExcelUtil.GetWorkbook(filePath, fs);
  30. var sheet = workbook.GetSheetAt(0);
  31. var rows = sheet.GetRowEnumerator();
  32. var evaluator = ExcelUtil.GetEvaluator(workbook);
  33. // 少于2行验证
  34. if (sheet.LastRowNum < 2)
  35. {
  36. //"第一行应为填写说明,第二行应为标题行,请勿修改模板结构。"
  37. return;
  38. }
  39. // 读取表头
  40. rows.MoveNext();
  41. IRow headerRow = (IRow)rows.Current;
  42. int index = 0;
  43. int ORG_ID = index++;
  44. int ORG_NAME = index++;
  45. int NAME_INDEX = index++;
  46. int EXAM_NUMBER_INDEX = index++;
  47. int CLASS_INDEX = index++;
  48. int DIRECTION_INDEX = index++;
  49. int DIRECTION_ID_INDEX = index++;
  50. int COURSE_COMB_INDEX = index++;
  51. int COURSE_COMB_ID_INDEX = index++;
  52. int COURSE_START_INDEX = index;
  53. Dictionary<int, string> headers = new()
  54. {
  55. { ORG_ID, "机构ID" },
  56. { ORG_NAME, "机构" },
  57. { NAME_INDEX, "姓名" },
  58. { EXAM_NUMBER_INDEX, "考号" },
  59. { CLASS_INDEX, "班级号" },
  60. { DIRECTION_INDEX, "选择方向" },
  61. { DIRECTION_ID_INDEX, "选择方向科目ID" },
  62. { COURSE_COMB_INDEX, "选科组合" },
  63. { COURSE_COMB_ID_INDEX, "选科组合ID" },
  64. };
  65. List<string> headerErrors = [];
  66. for (int i = 0; i < COURSE_START_INDEX; i++)
  67. {
  68. if (headerRow.GetCell(i)?.ToString() != headers[i])
  69. {
  70. char letter = (char)('A' + i);
  71. headerErrors.Add(letter.ToString());
  72. }
  73. }
  74. if (headerErrors.Count != 0)
  75. {
  76. string columnErrors = string.Join("、", headerErrors);
  77. //result.ErrorMessage.Add($"第1行标题行{columnErrors}列名错误。从A列开始依次应为抽样类型、学校ID、学校、姓名、证件类型、证件号码、考号、年级、班级。");
  78. //return result;
  79. throw new Exception("列头错误");
  80. }
  81. //result.StructureCorrect = true;
  82. #endregion
  83. #region 2.读取数据
  84. var plan = await rep.Change<NceePlan>().DetachedEntities.FirstOrDefaultAsync(t => t.Id == nceePlanId) ?? throw Oops.Oh(ErrorCode.E2001, "计划");
  85. var courseDict = (await rep.Change<Course>().DetachedEntities.ToListAsync()).ToDictionary(t => t.Name);
  86. //var orgs = await _rep.Change<SysOrg>().DetachedEntities.Where(t => t.EducationStage == EducationStage.SENIOR_HIGH_SCHOOL_STAGE).ToListAsync();
  87. var courseCombs = await rep.Change<NceeCourseComb>().DetachedEntities.ToListAsync();
  88. var courseCombDict = courseCombs.ToDictionary(t => t.Id, t => t);
  89. // 获取需要导入的科目列表
  90. Dictionary<int, Course> courses = [];
  91. int validCellNum = COURSE_START_INDEX;
  92. for (int gi = COURSE_START_INDEX; gi < headerRow.LastCellNum; gi++)
  93. {
  94. var cn = headerRow.GetCell(gi)?.ToString()?.Trim() ?? "";
  95. if (string.IsNullOrEmpty(cn))
  96. {
  97. continue;
  98. }
  99. courses.Add(gi, courseDict[cn]);
  100. validCellNum = gi + 1;
  101. }
  102. int rn = 1;
  103. List<NceeStudentImportDto> students = [];
  104. List<NceeScoreImportDto> scores = [];
  105. while (rows.MoveNext())
  106. {
  107. rn++;
  108. IRow row = (IRow)rows.Current;
  109. string rv = row.GetCell(0)?.ToString().Trim() ?? "";
  110. if (rv == "")
  111. {
  112. break;
  113. }
  114. NceeStudentImportDto stu = new();
  115. // 机构ID
  116. if (short.TryParse(row.GetCell(ORG_ID)?.ToString(), out short orgId))
  117. {
  118. stu.SysOrgId = orgId;
  119. }
  120. else
  121. {
  122. throw new Exception($"[{rn}]机构ID错误");
  123. }
  124. // 姓名
  125. stu.Name = row.GetCell(NAME_INDEX)?.ToString();
  126. // 考号
  127. stu.ExamNumber = row.GetCell(EXAM_NUMBER_INDEX)?.ToString();
  128. // 班号
  129. if (short.TryParse(row.GetCell(CLASS_INDEX)?.ToString(), out short cn))
  130. {
  131. stu.ClassNumber = cn;
  132. }
  133. else
  134. {
  135. throw new Exception($"[{rn}]班号错误");
  136. }
  137. // 方向ID
  138. if (short.TryParse(row.GetCell(DIRECTION_ID_INDEX)?.ToString(), out short directionId))
  139. {
  140. stu.DirectionCourseId = directionId;
  141. }
  142. //else
  143. //{
  144. // throw new Exception($"[{rn}]方向ID错误");
  145. //}
  146. // 组合ID
  147. if (short.TryParse(row.GetCell(COURSE_COMB_ID_INDEX)?.ToString(), out short courseCombId))
  148. {
  149. stu.NceeCourseCombId = courseCombId;
  150. }
  151. //else
  152. //{
  153. // throw new Exception($"[{rn}]组合ID错误");
  154. //}
  155. // 取各科成绩
  156. int sc = 0;
  157. for (int gi = COURSE_START_INDEX; gi < validCellNum; gi++)
  158. {
  159. var cell = row.GetCell(gi);
  160. if (cell == null || cell.ToString().Trim() == "")
  161. {
  162. continue;
  163. }
  164. if (!courses.ContainsKey(gi)) { continue; }
  165. var course = courses[gi];
  166. NceeScoreImportDto item = new()
  167. {
  168. NceeStudentId = stu.Id,
  169. CourseId = course.Id,
  170. };
  171. if (cell.CellType == CellType.Numeric)
  172. {
  173. item.Score = (decimal)cell.NumericCellValue;
  174. }
  175. else if (cell.CellType == CellType.Formula)
  176. {
  177. var cv = evaluator.Evaluate(cell);
  178. if (cv.CellType == CellType.Numeric)
  179. {
  180. item.Score = (decimal)cv.NumberValue;
  181. }
  182. else
  183. {
  184. continue;
  185. }
  186. }
  187. if (item.Score > 0)
  188. {
  189. if (!NceeUtil.ChooseCourses.Any(t => t == course.Id))
  190. {
  191. item.ScoreX = item.Score;
  192. }
  193. scores.Add(item);
  194. sc++;
  195. }
  196. }
  197. if (sc > 0)
  198. {
  199. students.Add(stu);
  200. }
  201. }
  202. workbook.Close();
  203. fs.Close();
  204. #endregion
  205. #region 3.处理学生
  206. // 清理学生
  207. string deleteStudentSql = $"DELETE FROM ncee_student WHERE ncee_plan_id = {nceePlanId};";
  208. await rep.SqlNonQueryAsync(deleteStudentSql);
  209. var uid = CurrentSysUserInfo.SysUserId;
  210. if (uid == 0)
  211. {
  212. uid = 1;
  213. }
  214. List<string> insertValues = [];
  215. int scount = students.Count;
  216. for (int i = 0; i < scount; i++)
  217. {
  218. var t = students[i];
  219. string dcid = "NULL";
  220. if (t.DirectionCourseId.HasValue)
  221. {
  222. dcid = t.DirectionCourseId.Value.ToString();
  223. }
  224. string nccid = "NULL";
  225. if (t.NceeCourseCombId.HasValue)
  226. {
  227. nccid = t.NceeCourseCombId.Value.ToString();
  228. }
  229. insertValues.Add($"({t.Id}, {nceePlanId}, {t.SysOrgId}, {plan.GradeId}, {t.ClassNumber}, '{t.ExamNumber}', '{t.Name}', {dcid}, {nccid}, 0, 0)");
  230. if ((i + 1) % 1000 == 0 || i == scount - 1)
  231. {
  232. string insertSql = $@"
  233. 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
  234. {string.Join(",", insertValues)}
  235. ";
  236. await rep.SqlNonQueryAsync(insertSql);
  237. insertValues.Clear();
  238. }
  239. }
  240. #endregion
  241. #region 4.批量导入
  242. // 清理成绩
  243. string deleteScoreSql = $"DELETE FROM ncee_score WHERE ncee_plan_id = {nceePlanId};";
  244. await rep.SqlNonQueryAsync(deleteScoreSql);
  245. insertValues.Clear();
  246. scount = scores.Count;
  247. for (int i = 0; i < scount; i++)
  248. {
  249. var t = scores[i];
  250. insertValues.Add($"({t.Id}, {nceePlanId}, {t.NceeStudentId}, {t.CourseId}, {t.Score}, {t.ScoreX})");
  251. if ((i + 1) % 1000 == 0 || i == scount - 1)
  252. {
  253. string insertSql = $@"
  254. INSERT INTO ncee_score(id, ncee_plan_id, ncee_student_id, course_id, score, score_x) VALUES
  255. {string.Join(",", insertValues)}
  256. ";
  257. await rep.SqlNonQueryAsync(insertSql);
  258. insertValues.Clear();
  259. }
  260. }
  261. #endregion
  262. }
  263. catch (Exception ex)
  264. {
  265. throw new Exception(ex.Message);
  266. }
  267. finally
  268. {
  269. File.Delete(filePath);
  270. }
  271. }
  272. /// <summary>
  273. /// 上传成绩(带转换分和等级,适用于六校联考)
  274. /// </summary>
  275. /// <param name="filePath"></param>
  276. /// <param name="nceePlanId"></param>
  277. /// <returns></returns>
  278. /// <exception cref="Exception"></exception>
  279. public async Task UploadWithConvertScore(string filePath, int nceePlanId)
  280. {
  281. /* ----------------------------------------------------------
  282. * 处理步骤:
  283. * 1.验证表头
  284. * 2.读取数据
  285. * 3.处理学生
  286. * 4.批量插入
  287. ---------------------------------------------------------- */
  288. try
  289. {
  290. #region 1.验证表结构
  291. using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
  292. IWorkbook workbook = ExcelUtil.GetWorkbook(filePath, fs);
  293. var sheet = workbook.GetSheetAt(0);
  294. var rows = sheet.GetRowEnumerator();
  295. var evaluator = ExcelUtil.GetEvaluator(workbook);
  296. // 少于2行验证
  297. if (sheet.LastRowNum < 2)
  298. {
  299. //"第一行应为填写说明,第二行应为标题行,请勿修改模板结构。"
  300. return;
  301. }
  302. // 读取表头
  303. rows.MoveNext();
  304. IRow headerRow = (IRow)rows.Current;
  305. int index = 0;
  306. int ORG_ID = index++;
  307. int ORG_NAME = index++;
  308. int NAME_INDEX = index++;
  309. int EXAM_NUMBER_INDEX = index++;
  310. int CLASS_INDEX = index++;
  311. int DIRECTION_INDEX = index++;
  312. int DIRECTION_ID_INDEX = index++;
  313. int COURSE_COMB_INDEX = index++;
  314. int COURSE_COMB_ID_INDEX = index++;
  315. int COURSE_START_INDEX = index;
  316. Dictionary<int, string> headers = new()
  317. {
  318. { ORG_ID, "机构ID" },
  319. { ORG_NAME, "机构" },
  320. { NAME_INDEX, "姓名" },
  321. { EXAM_NUMBER_INDEX, "考号" },
  322. { CLASS_INDEX, "班级号" },
  323. { DIRECTION_INDEX, "选择方向" },
  324. { DIRECTION_ID_INDEX, "选择方向科目ID" },
  325. { COURSE_COMB_INDEX, "选科组合" },
  326. { COURSE_COMB_ID_INDEX, "选科组合ID" },
  327. };
  328. List<string> headerErrors = [];
  329. for (int i = 0; i < COURSE_START_INDEX; i++)
  330. {
  331. if (headerRow.GetCell(i)?.ToString() != headers[i])
  332. {
  333. char letter = (char)('A' + i);
  334. headerErrors.Add(letter.ToString());
  335. }
  336. }
  337. if (headerErrors.Count != 0)
  338. {
  339. string columnErrors = string.Join("、", headerErrors);
  340. //result.ErrorMessage.Add($"第1行标题行{columnErrors}列名错误。从A列开始依次应为抽样类型、学校ID、学校、姓名、证件类型、证件号码、考号、年级、班级。");
  341. //return result;
  342. throw new Exception("列头错误");
  343. }
  344. //result.StructureCorrect = true;
  345. #endregion
  346. #region 2.读取数据
  347. var plan = await rep.Change<NceePlan>().DetachedEntities.FirstOrDefaultAsync(t => t.Id == nceePlanId) ?? throw Oops.Oh(ErrorCode.E2001, "计划");
  348. var courseDict = (await rep.Change<Course>().DetachedEntities.ToListAsync()).ToDictionary(t => t.Name);
  349. //var orgs = await _rep.Change<SysOrg>().DetachedEntities.Where(t => t.EducationStage == EducationStage.SENIOR_HIGH_SCHOOL_STAGE).ToListAsync();
  350. var courseCombs = await rep.Change<NceeCourseComb>().DetachedEntities.ToListAsync();
  351. var courseCombDict = courseCombs.ToDictionary(t => t.Id, t => t);
  352. var convertGrades = await rep.Change<NceeConvertGrade>().DetachedEntities.ToListAsync();
  353. var convertGradeDict = convertGrades.ToDictionary(t => t.Name);
  354. // 获取需要导入的科目列表
  355. Dictionary<int, NceeScoreImportCourseDto> courses = new();
  356. int validCellNum = COURSE_START_INDEX;
  357. for (int gi = COURSE_START_INDEX; gi < headerRow.LastCellNum; gi++)
  358. {
  359. var cn = headerRow.GetCell(gi)?.ToString()?.Trim() ?? "";
  360. if (string.IsNullOrEmpty(cn))
  361. {
  362. continue;
  363. }
  364. string tm = cn[^1..].ToUpper();
  365. var cnn = cn;
  366. if (tm == "X" || tm == "G")
  367. {
  368. cnn = cn[..^1];
  369. }
  370. courses.Add(gi, new()
  371. {
  372. CourseName = cn,
  373. Course = courseDict[cnn],
  374. IsRawScore = tm != "X" && tm != "G",
  375. IsConvertGrade = tm == "G",
  376. IsConvertScore = tm == "X",
  377. });
  378. validCellNum = gi + 1;
  379. }
  380. int rn = 1;
  381. List<NceeStudentImportDto> students = new();
  382. List<NceeScoreImportDto> scores = new();
  383. while (rows.MoveNext())
  384. {
  385. rn++;
  386. IRow row = (IRow)rows.Current;
  387. string rv = row.GetCell(0)?.ToString().Trim() ?? "";
  388. if (rv == "")
  389. {
  390. break;
  391. }
  392. NceeStudentImportDto stu = new();
  393. // 机构ID
  394. if (short.TryParse(row.GetCell(ORG_ID)?.ToString(), out short orgId))
  395. {
  396. stu.SysOrgId = orgId;
  397. }
  398. else
  399. {
  400. throw new Exception($"[{rn}]机构ID错误");
  401. }
  402. // 姓名
  403. stu.Name = row.GetCell(NAME_INDEX)?.ToString();
  404. // 考号
  405. stu.ExamNumber = row.GetCell(EXAM_NUMBER_INDEX)?.ToString();
  406. // 班号
  407. if (short.TryParse(row.GetCell(CLASS_INDEX)?.ToString(), out short cn))
  408. {
  409. stu.ClassNumber = cn;
  410. }
  411. else
  412. {
  413. throw new Exception($"[{rn}]班号错误");
  414. }
  415. // 方向ID
  416. if (short.TryParse(row.GetCell(DIRECTION_ID_INDEX)?.ToString(), out short directionId))
  417. {
  418. stu.DirectionCourseId = directionId;
  419. }
  420. //else
  421. //{
  422. // throw new Exception($"[{rn}]方向ID错误");
  423. //}
  424. // 组合ID
  425. if (short.TryParse(row.GetCell(COURSE_COMB_ID_INDEX)?.ToString(), out short courseCombId))
  426. {
  427. stu.NceeCourseCombId = courseCombId;
  428. }
  429. //else
  430. //{
  431. // throw new Exception($"[{rn}]组合ID错误");
  432. //}
  433. // 取各科成绩
  434. List<NceeScoreImportDto> courseScores = [];
  435. for (int gi = COURSE_START_INDEX; gi < validCellNum; gi++)
  436. {
  437. var cell = row.GetCell(gi);
  438. if (cell == null || cell.ToString().Trim() == "")
  439. {
  440. continue;
  441. }
  442. if (!courses.ContainsKey(gi)) { continue; }
  443. var course = courses[gi];
  444. NceeScoreImportDto item;
  445. if (course.IsConvertScore || course.IsConvertGrade)
  446. {
  447. item = courseScores.FirstOrDefault(t => t.CourseId == course.Course.Id);
  448. }
  449. else
  450. {
  451. item = new()
  452. {
  453. NceeStudentId = stu.Id,
  454. CourseId = course.Course.Id,
  455. };
  456. }
  457. if (course.IsConvertGrade == false)
  458. {
  459. decimal score = 0;
  460. if (cell.CellType == CellType.Numeric)
  461. {
  462. score = (decimal)cell.NumericCellValue;
  463. }
  464. else if (cell.CellType == CellType.Formula)
  465. {
  466. var cv = evaluator.Evaluate(cell);
  467. if (cv.CellType == CellType.Numeric)
  468. {
  469. score = (decimal)cv.NumberValue;
  470. }
  471. else
  472. {
  473. continue;
  474. }
  475. }
  476. if (score > 0)
  477. {
  478. if (course.IsRawScore == true)
  479. {
  480. item.Score = score;
  481. if (!NceeUtil.ChooseCourses.Any(t => t == course.Course.Id))
  482. {
  483. item.ScoreX = score;
  484. }
  485. courseScores.Add(item);
  486. }
  487. else if (course.IsConvertScore == true)
  488. {
  489. item.ScoreX = score;
  490. }
  491. }
  492. }
  493. else
  494. {
  495. var gn = cell.ToString().Trim().ToUpper();
  496. var g = convertGradeDict[gn];
  497. item.NceeConvertGradeId = g.Id;
  498. item.NceeConvertGradeName = g.Name;
  499. }
  500. }
  501. if (courseScores.Count > 0)
  502. {
  503. stu.Score = courseScores.Sum(t => t.Score);
  504. stu.ScoreX = courseScores.Sum(t => t.ScoreX);
  505. students.Add(stu);
  506. scores.AddRange(courseScores);
  507. }
  508. }
  509. workbook.Close();
  510. fs.Close();
  511. #endregion
  512. #region 3.处理学生
  513. // 清理学生
  514. string deleteStudentSql = $"DELETE FROM ncee_student WHERE ncee_plan_id = {nceePlanId};";
  515. await rep.SqlNonQueryAsync(deleteStudentSql);
  516. var uid = CurrentSysUserInfo.SysUserId;
  517. if (uid == 0)
  518. {
  519. uid = 1;
  520. }
  521. List<string> insertValues = new();
  522. int scount = students.Count;
  523. for (int i = 0; i < scount; i++)
  524. {
  525. var t = students[i];
  526. string dcid = "NULL";
  527. if (t.DirectionCourseId.HasValue)
  528. {
  529. dcid = t.DirectionCourseId.Value.ToString();
  530. }
  531. string nccid = "NULL";
  532. if (t.NceeCourseCombId.HasValue)
  533. {
  534. nccid = t.NceeCourseCombId.Value.ToString();
  535. }
  536. insertValues.Add($"({t.Id}, {nceePlanId}, {t.SysOrgId}, {plan.GradeId}, {t.ClassNumber}, '{t.ExamNumber}', '{t.Name}', {dcid}, {nccid}, {t.Score}, {t.ScoreX})");
  537. if ((i + 1) % 1000 == 0 || i == scount - 1)
  538. {
  539. string insertSql = $@"
  540. 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
  541. {string.Join(",", insertValues)}
  542. ";
  543. await rep.SqlNonQueryAsync(insertSql);
  544. insertValues.Clear();
  545. }
  546. }
  547. #endregion
  548. #region 4.批量导入
  549. // 清理成绩
  550. string deleteScoreSql = $"DELETE FROM ncee_score WHERE ncee_plan_id = {nceePlanId};";
  551. await rep.SqlNonQueryAsync(deleteScoreSql);
  552. insertValues.Clear();
  553. scount = scores.Count;
  554. for (int i = 0; i < scount; i++)
  555. {
  556. var t = scores[i];
  557. string ncgid = "NULL";
  558. if (t.NceeConvertGradeId.HasValue)
  559. {
  560. ncgid = t.NceeConvertGradeId.Value.ToString();
  561. }
  562. insertValues.Add($"({t.Id}, {nceePlanId}, {t.NceeStudentId}, {t.CourseId}, {ncgid}, '{t.NceeConvertGradeName}', {t.Score}, {t.ScoreX})");
  563. if ((i + 1) % 1000 == 0 || i == scount - 1)
  564. {
  565. string insertSql = $@"
  566. 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
  567. {string.Join(",", insertValues)}
  568. ";
  569. await rep.SqlNonQueryAsync(insertSql);
  570. insertValues.Clear();
  571. }
  572. }
  573. #endregion
  574. }
  575. catch (Exception ex)
  576. {
  577. throw new Exception(ex.Message);
  578. }
  579. finally
  580. {
  581. File.Delete(filePath);
  582. }
  583. }
  584. /// <summary>
  585. /// 上传未选科原始成绩(适用于高一未选科)
  586. /// </summary>
  587. /// <param name="filePath"></param>
  588. /// <param name="nceePlanId"></param>
  589. /// <returns></returns>
  590. /// <exception cref="Exception"></exception>
  591. public async Task UploadNoDirectionCourse(string filePath, int nceePlanId)
  592. {
  593. /* ----------------------------------------------------------
  594. * 处理步骤:
  595. * 1.验证表头
  596. * 2.读取数据
  597. * 3.处理学生
  598. * 4.批量插入
  599. ---------------------------------------------------------- */
  600. try
  601. {
  602. #region 1.验证表结构
  603. using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
  604. IWorkbook workbook = ExcelUtil.GetWorkbook(filePath, fs);
  605. var sheet = workbook.GetSheetAt(0);
  606. var rows = sheet.GetRowEnumerator();
  607. var evaluator = ExcelUtil.GetEvaluator(workbook);
  608. // 少于2行验证
  609. if (sheet.LastRowNum < 2)
  610. {
  611. //"第一行应为填写说明,第二行应为标题行,请勿修改模板结构。"
  612. return;
  613. }
  614. // 读取表头
  615. rows.MoveNext();
  616. IRow headerRow = (IRow)rows.Current;
  617. int index = 0;
  618. int ORG_ID = index++;
  619. int ORG_NAME = index++;
  620. int NAME_INDEX = index++;
  621. int EXAM_NUMBER_INDEX = index++;
  622. int CLASS_INDEX = index++;
  623. int COURSE_START_INDEX = index;
  624. Dictionary<int, string> headers = new()
  625. {
  626. { ORG_ID, "机构ID" },
  627. { ORG_NAME, "机构" },
  628. { NAME_INDEX, "姓名" },
  629. { EXAM_NUMBER_INDEX, "考号" },
  630. { CLASS_INDEX, "班级号" },
  631. };
  632. List<string> headerErrors = [];
  633. for (int i = 0; i < COURSE_START_INDEX; i++)
  634. {
  635. if (headerRow.GetCell(i)?.ToString() != headers[i])
  636. {
  637. char letter = (char)('A' + i);
  638. headerErrors.Add(letter.ToString());
  639. }
  640. }
  641. if (headerErrors.Count != 0)
  642. {
  643. string columnErrors = string.Join("、", headerErrors);
  644. //result.ErrorMessage.Add($"第1行标题行{columnErrors}列名错误。从A列开始依次应为抽样类型、学校ID、学校、姓名、证件类型、证件号码、考号、年级、班级。");
  645. //return result;
  646. throw new Exception("列头错误");
  647. }
  648. //result.StructureCorrect = true;
  649. #endregion
  650. #region 2.读取数据
  651. var plan = await rep.Change<NceePlan>().DetachedEntities.FirstOrDefaultAsync(t => t.Id == nceePlanId) ?? throw Oops.Oh(ErrorCode.E2001, "计划");
  652. var courseDict = (await rep.Change<Course>().DetachedEntities.ToListAsync()).ToDictionary(t => t.Name);
  653. // 获取需要导入的科目列表
  654. Dictionary<int, Course> courses = [];
  655. int validCellNum = COURSE_START_INDEX;
  656. for (int gi = COURSE_START_INDEX; gi < headerRow.LastCellNum; gi++)
  657. {
  658. var cn = headerRow.GetCell(gi)?.ToString()?.Trim() ?? "";
  659. if (string.IsNullOrEmpty(cn))
  660. {
  661. continue;
  662. }
  663. courses.Add(gi, courseDict[cn]);
  664. validCellNum = gi + 1;
  665. }
  666. int rn = 1;
  667. List<NceeStudentImportDto> students = [];
  668. List<NceeScoreImportDto> scores = [];
  669. while (rows.MoveNext())
  670. {
  671. rn++;
  672. IRow row = (IRow)rows.Current;
  673. string rv = row.GetCell(0)?.ToString().Trim() ?? "";
  674. if (rv == "")
  675. {
  676. break;
  677. }
  678. NceeStudentImportDto stu = new();
  679. // 机构ID
  680. if (short.TryParse(row.GetCell(ORG_ID)?.ToString(), out short orgId))
  681. {
  682. stu.SysOrgId = orgId;
  683. }
  684. else
  685. {
  686. throw new Exception($"[{rn}]机构ID错误");
  687. }
  688. // 姓名
  689. stu.Name = row.GetCell(NAME_INDEX)?.ToString();
  690. // 考号
  691. stu.ExamNumber = row.GetCell(EXAM_NUMBER_INDEX)?.ToString();
  692. // 班号
  693. if (short.TryParse(row.GetCell(CLASS_INDEX)?.ToString(), out short cn))
  694. {
  695. stu.ClassNumber = cn;
  696. }
  697. else
  698. {
  699. throw new Exception($"[{rn}]班号错误");
  700. }
  701. // 取各科成绩
  702. List<NceeScoreImportDto> courseScores = [];
  703. for (int gi = COURSE_START_INDEX; gi < validCellNum; gi++)
  704. {
  705. var cell = row.GetCell(gi);
  706. if (cell == null || cell.ToString().Trim() == "")
  707. {
  708. continue;
  709. }
  710. if (!courses.ContainsKey(gi)) { continue; }
  711. var course = courses[gi];
  712. NceeScoreImportDto item = new()
  713. {
  714. NceeStudentId = stu.Id,
  715. CourseId = course.Id,
  716. };
  717. decimal score = 0;
  718. if (cell.CellType == CellType.Numeric)
  719. {
  720. score = (decimal)cell.NumericCellValue;
  721. }
  722. else if (cell.CellType == CellType.Formula)
  723. {
  724. var cv = evaluator.Evaluate(cell);
  725. if (cv.CellType == CellType.Numeric)
  726. {
  727. score = (decimal)cv.NumberValue;
  728. }
  729. else
  730. {
  731. continue;
  732. }
  733. }
  734. if (score > 0)
  735. {
  736. item.Score = score;
  737. item.ScoreX = score;
  738. courseScores.Add(item);
  739. }
  740. }
  741. if (courseScores.Count > 0)
  742. {
  743. stu.Score = courseScores.Sum(t => t.Score);
  744. stu.ScoreX = courseScores.Sum(t => t.ScoreX);
  745. students.Add(stu);
  746. scores.AddRange(courseScores);
  747. }
  748. }
  749. workbook.Close();
  750. fs.Close();
  751. #endregion
  752. #region 3.处理学生
  753. // 清理学生
  754. string deleteStudentSql = $"DELETE FROM ncee_student WHERE ncee_plan_id = {nceePlanId};";
  755. await rep.SqlNonQueryAsync(deleteStudentSql);
  756. var uid = CurrentSysUserInfo.SysUserId;
  757. if (uid == 0)
  758. {
  759. uid = 1;
  760. }
  761. List<string> insertValues = new();
  762. int scount = students.Count;
  763. for (int i = 0; i < scount; i++)
  764. {
  765. var t = students[i];
  766. insertValues.Add($"({t.Id}, {nceePlanId}, {t.SysOrgId}, {plan.GradeId}, {t.ClassNumber}, '{t.ExamNumber}', '{t.Name}', 99, 0, {t.Score}, {t.ScoreX})");
  767. if ((i + 1) % 1000 == 0 || i == scount - 1)
  768. {
  769. string insertSql = $@"
  770. 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
  771. {string.Join(",", insertValues)}
  772. ";
  773. await rep.SqlNonQueryAsync(insertSql);
  774. insertValues.Clear();
  775. }
  776. }
  777. #endregion
  778. #region 4.批量导入
  779. // 清理成绩
  780. string deleteScoreSql = $"DELETE FROM ncee_score WHERE ncee_plan_id = {nceePlanId};";
  781. await rep.SqlNonQueryAsync(deleteScoreSql);
  782. insertValues.Clear();
  783. scount = scores.Count;
  784. for (int i = 0; i < scount; i++)
  785. {
  786. var t = scores[i];
  787. insertValues.Add($"({t.Id}, {nceePlanId}, {t.NceeStudentId}, {t.CourseId}, NULL, '', {t.Score}, {t.ScoreX})");
  788. if ((i + 1) % 1000 == 0 || i == scount - 1)
  789. {
  790. string insertSql = $@"
  791. 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
  792. {string.Join(",", insertValues)}
  793. ";
  794. await rep.SqlNonQueryAsync(insertSql);
  795. insertValues.Clear();
  796. }
  797. }
  798. #endregion
  799. }
  800. catch (Exception ex)
  801. {
  802. throw new Exception(ex.Message);
  803. }
  804. finally
  805. {
  806. File.Delete(filePath);
  807. }
  808. }
  809. /// <summary>
  810. /// 执行模拟划线
  811. /// </summary>
  812. /// <param name="nceePlanId"></param>
  813. /// <returns></returns>
  814. public async Task Execute(int nceePlanId)
  815. {
  816. var nceePlan = await rep.Change<NceePlan>().FirstOrDefaultAsync(t => t.Id == nceePlanId) ?? throw Oops.Oh(ErrorCode.E2001);
  817. var nceePlanConfig = JSON.Deserialize<NceePlanConfig>(nceePlan.Config);
  818. // 执行分数转换
  819. if (nceePlanConfig.ConvertEnabled)
  820. {
  821. await ExecuteScoreConvert(nceePlanId);
  822. }
  823. // 更新学生排名
  824. await ExecuteUpdateOrder(nceePlanId);
  825. // 执行划线
  826. await ExecuteLine(nceePlanId, nceePlanConfig);
  827. }
  828. #region 私有方法
  829. /// <summary>
  830. /// 执行划线
  831. /// </summary>
  832. /// <param name="nceePlanId"></param>
  833. /// <param name="config"></param>
  834. /// <returns></returns>
  835. private async Task ExecuteLine(int nceePlanId, NceePlanConfig config)
  836. {
  837. var baseLines = await rep.Change<NceeBaseLine>().Where(t => t.NceePlanId == nceePlanId).OrderBy(t => t.NceeLineLevel).ToListAsync();
  838. // 单科有效分
  839. List<NceeCourseLineScore> courseLineScores = [];
  840. #region 计算总有效分(通过比例计算)
  841. if (config.CalcTotalLineScoreEnabled)
  842. {
  843. foreach (var line in baseLines)
  844. {
  845. // 计算总有效分
  846. var lineScoreX = await rep.SqlScalarAsync<decimal>(@$"
  847. SELECT MIN(score_x) AS score_x
  848. FROM
  849. (
  850. SELECT ROW_NUMBER() OVER(ORDER BY score_x DESC) AS rn, score_x
  851. FROM ncee_student
  852. WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId
  853. ) AS T1
  854. WHERE T1.rn <= (SELECT COUNT(1) FROM ncee_student WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId) * @lineRate
  855. ", new { NceePlanId = nceePlanId, line.DirectionCourseId, line.LineRate });
  856. line.LineScoreX = lineScoreX;
  857. }
  858. await rep.Change<NceeBaseLine>().UpdateNowAsync(baseLines);
  859. }
  860. #endregion
  861. #region 计算单科有效分
  862. if (config.CalcCourseLineScoreEnabled)
  863. {
  864. // 1.总分排序,合并单科独立排序
  865. // 2.取总分上线分对应行的单科成绩为有效分
  866. foreach (var line in baseLines)
  867. {
  868. if (!config.DirectionUnseleted)
  869. {
  870. // 计算单科有效分
  871. var courseLineScoreX = await rep.SqlQueryAsync<NceeCourseLineScoreCalcDto>($@"
  872. SELECT
  873. MIN(T1.yuwen_score_x) AS yuwen_score_x, -- 语文
  874. MIN(T1.shuxue_score_x) AS shuxue_score_x, -- 数学
  875. MIN(T1.yingyu_score_x) AS yingyu_score_x, -- 英语
  876. MIN(T1.fangxiang_score_x) AS fangxiang_score_x, -- 方向(物理或历史)
  877. MIN(T1.zonghe_score_x) AS zonghe_score_x -- 综合
  878. FROM
  879. (
  880. SELECT T1.rn,
  881. T2.score_x AS yuwen_score_x,
  882. T3.score_x AS shuxue_score_x,
  883. T4.score_x AS yingyu_score_x,
  884. T5.score_x AS fangxiang_score_x,
  885. T6.score_x AS zonghe_score_x,
  886. 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
  887. FROM
  888. (
  889. SELECT ROW_NUMBER() OVER(ORDER BY score_x DESC) AS rn
  890. FROM ncee_student AS T1
  891. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId
  892. ) AS T1
  893. LEFT JOIN
  894. (
  895. SELECT ROW_NUMBER() OVER(ORDER BY T2.score_x DESC) AS rn, T2.score_x
  896. FROM ncee_student AS T1
  897. JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  898. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id = 1
  899. ) AS T2 ON T1.rn = T2.rn
  900. LEFT JOIN
  901. (
  902. SELECT ROW_NUMBER() OVER(ORDER BY T2.score_x DESC) AS rn, T2.score_x
  903. FROM ncee_student AS T1
  904. JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  905. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id = 2
  906. ) AS T3 ON T1.rn = T3.rn
  907. LEFT JOIN
  908. (
  909. SELECT ROW_NUMBER() OVER(ORDER BY T2.score_x DESC) AS rn, T2.score_x
  910. FROM ncee_student AS T1
  911. JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  912. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id = 3
  913. ) AS T4 ON T1.rn = T4.rn
  914. LEFT JOIN
  915. (
  916. SELECT ROW_NUMBER() OVER(ORDER BY T2.score_x DESC) AS rn, T2.score_x
  917. FROM ncee_student AS T1
  918. JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  919. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id = @directionCourseId
  920. ) AS T5 ON T1.rn = T5.rn
  921. LEFT JOIN
  922. (
  923. SELECT ROW_NUMBER() OVER(ORDER BY T1.score_x DESC) AS rn, t1.score_x
  924. FROM
  925. (
  926. SELECT T2.ncee_student_id, SUM(T2.score_x) AS score_x
  927. FROM ncee_student AS T1
  928. JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  929. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id IN(5, 6, 7, 9)
  930. GROUP BY T2.ncee_student_id
  931. ) AS T1
  932. ) AS T6 ON T1.rn = T6.rn
  933. ) AS T1
  934. WHERE T1.score_x >= @totalLineScoreX
  935. ", new { NceePlanId = nceePlanId, line.DirectionCourseId, TotalLineScoreX = line.LineScoreX });
  936. var cline = courseLineScoreX.FirstOrDefault();
  937. if (cline != null)
  938. {
  939. courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = CourseConst.YU_WEN, LineScoreX = cline.YuwenScoreX });
  940. courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = CourseConst.SHU_XUE, LineScoreX = cline.ShuxueScoreX });
  941. courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = CourseConst.YING_YU, LineScoreX = cline.YingyuScoreX });
  942. courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = line.DirectionCourseId, LineScoreX = cline.FangxiangScoreX });
  943. courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = CourseConst.ZONG_HE, LineScoreX = cline.ZongheScoreX });
  944. }
  945. }
  946. else
  947. {
  948. List<string> minFields = [];
  949. List<string> scoreFields = [];
  950. List<string> totalScore = [];
  951. List<string> courseSelects = [];
  952. for (short c = 1; c < 10; c++)
  953. {
  954. minFields.Add($"MIN(T1.score_{c}) AS score_{c}");
  955. scoreFields.Add($"T{c}.score AS score_{c}");
  956. totalScore.Add($"IFNULL(T{c}.score, 0)");
  957. courseSelects.Add(@$"
  958. LEFT JOIN
  959. (
  960. SELECT ROW_NUMBER() OVER(ORDER BY T2.score DESC) AS rn, T2.score
  961. FROM ncee_student AS T1
  962. JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  963. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.course_id = {c}
  964. ) AS T{c} ON T0.rn = T{c}.rn
  965. ");
  966. }
  967. // 计算单科有效分
  968. var courseLineScoreX = await rep.SqlQueryAsync($@"
  969. SELECT
  970. {string.Join(", ", minFields)}
  971. FROM
  972. (
  973. SELECT
  974. T0.rn,
  975. {string.Join(", ", scoreFields)},
  976. {string.Join(" + ", totalScore)} AS score
  977. FROM
  978. (
  979. SELECT ROW_NUMBER() OVER(ORDER BY score DESC) AS rn
  980. FROM ncee_student AS T1
  981. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId
  982. ) AS T0
  983. {string.Join("", courseSelects)}
  984. ) AS T1
  985. WHERE T1.score >= @totalLineScoreX
  986. ", new { NceePlanId = nceePlanId, line.DirectionCourseId, TotalLineScoreX = line.LineScoreX });
  987. if (courseLineScoreX.Rows.Count > 0)
  988. {
  989. var dr = courseLineScoreX.Rows[0];
  990. for (short c = 1; c < 10; c++)
  991. {
  992. courseLineScores.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = c, LineScoreX = (decimal)dr[$"score_{c}"] });
  993. }
  994. }
  995. }
  996. }
  997. await rep.Change<NceeCourseLineScore>().Where(t => t.NceePlanId == nceePlanId).ExecuteDeleteAsync();
  998. List<NceeCourseLineScore> totalLines = [];
  999. foreach (var line in baseLines)
  1000. {
  1001. totalLines.Add(new() { NceePlanId = nceePlanId, DirectionCourseId = line.DirectionCourseId, NceeLineLevel = line.NceeLineLevel, CourseId = 100, LineScoreX = line.LineScoreX });
  1002. }
  1003. await rep.Change<NceeCourseLineScore>().InsertNowAsync(totalLines);
  1004. await rep.Change<NceeCourseLineScore>().InsertNowAsync(courseLineScores);
  1005. }
  1006. else
  1007. {
  1008. courseLineScores = await rep.Change<NceeCourseLineScore>().Where(t => t.NceePlanId == nceePlanId).ToListAsync();
  1009. }
  1010. #endregion
  1011. #region 计算总分上线
  1012. // 清除数据
  1013. await rep.Change<NceeLineTotal>().Where(t => t.NceePlanId == nceePlanId).ExecuteDeleteAsync();
  1014. // 总分划线
  1015. foreach (var line in baseLines)
  1016. {
  1017. // 整体 - 方向
  1018. await rep.SqlNonQueryAsync($@"
  1019. INSERT INTO ncee_line_total(type, ncee_plan_id, ncee_line_level, direction_course_id, grade_id, line_count, total_count, line_rate)
  1020. SELECT {(short)NceeDataScopeType.TOTAL}, @nceePlanId, @nceeLineLevel, T1.*, T1.line_count / T1.total_count AS line_rate
  1021. FROM
  1022. (
  1023. SELECT
  1024. T1.direction_course_id,
  1025. T1.grade_id,
  1026. COUNT(1) AS line_count,
  1027. (
  1028. SELECT COUNT(1) AS total_count
  1029. FROM ncee_student
  1030. WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId AND score_x > 0
  1031. ) AS total_count
  1032. FROM ncee_student AS T1
  1033. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T1.score_x >= @lineScoreX
  1034. GROUP BY T1.direction_course_id, T1.grade_id
  1035. ) AS T1
  1036. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX });
  1037. // 机构 - 方向
  1038. await rep.SqlNonQueryAsync($@"
  1039. 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)
  1040. SELECT {(short)NceeDataScopeType.ORG}, @nceePlanId, @nceeLineLevel, T1.*, T1.line_count / T1.total_count AS line_rate
  1041. FROM
  1042. (
  1043. SELECT
  1044. T1.direction_course_id,
  1045. T1.sys_org_id,
  1046. T1.grade_id,
  1047. COUNT(1) AS line_count,
  1048. T2.total_count
  1049. FROM ncee_student AS T1
  1050. JOIN
  1051. (
  1052. SELECT sys_org_id, COUNT(1) AS total_count
  1053. FROM ncee_student
  1054. WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId AND score_x > 0
  1055. GROUP BY sys_org_id
  1056. ) AS T2 ON T1.sys_org_id = T2.sys_org_id
  1057. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T1.score_x >= @lineScoreX
  1058. GROUP BY T1.direction_course_id, T1.sys_org_id, T1.grade_id
  1059. ) AS T1
  1060. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX });
  1061. // 机构 - 方向 - 组合
  1062. await rep.SqlNonQueryAsync($@"
  1063. 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)
  1064. SELECT {(short)NceeDataScopeType.COMB}, @nceePlanId, @nceeLineLevel, T1.*, T1.line_count / T1.total_count AS line_rate
  1065. FROM
  1066. (
  1067. SELECT
  1068. T1.direction_course_id,
  1069. T1.ncee_course_comb_id,
  1070. T1.sys_org_id,
  1071. T1.grade_id,
  1072. COUNT(1) AS line_count,
  1073. T2.total_count
  1074. FROM ncee_student AS T1
  1075. JOIN
  1076. (
  1077. SELECT ncee_course_comb_id, sys_org_id, COUNT(1) AS total_count
  1078. FROM ncee_student
  1079. WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId AND score_x > 0
  1080. GROUP BY ncee_course_comb_id, sys_org_id
  1081. ) AS T2 ON T1.sys_org_id = T2.sys_org_id
  1082. 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
  1083. GROUP BY T1.direction_course_id, T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id
  1084. ) AS T1
  1085. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX });
  1086. // 机构 - 班级 - 方向 - 组合
  1087. await rep.SqlNonQueryAsync($@"
  1088. 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)
  1089. SELECT {(short)NceeDataScopeType.CLASS}, @nceePlanId, @nceeLineLevel, T1.*, T1.line_count / T1.total_count AS line_rate
  1090. FROM
  1091. (
  1092. SELECT
  1093. T1.direction_course_id,
  1094. T1.ncee_course_comb_id,
  1095. T1.sys_org_id,
  1096. T1.grade_id,
  1097. T1.class_number,
  1098. COUNT(1) AS line_count,
  1099. T2.total_count
  1100. FROM ncee_student AS T1
  1101. JOIN
  1102. (
  1103. SELECT ncee_course_comb_id, sys_org_id, class_number, COUNT(1) AS total_count
  1104. FROM ncee_student
  1105. WHERE ncee_plan_id = @nceePlanId AND direction_course_id = @directionCourseId AND score_x > 0
  1106. GROUP BY ncee_course_comb_id, sys_org_id, class_number
  1107. ) AS T2 ON T1.sys_org_id = T2.sys_org_id
  1108. 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
  1109. GROUP BY T1.direction_course_id, T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number
  1110. ) AS T1
  1111. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX });
  1112. }
  1113. #endregion
  1114. #region 计算科目有效分上线
  1115. // 清除数据
  1116. await rep.Change<NceeLineCourse>().Where(t => t.NceePlanId == nceePlanId).ExecuteDeleteAsync();
  1117. // 总分划线
  1118. foreach (var line in baseLines)
  1119. {
  1120. var courseLines = courseLineScores.Where(t => t.DirectionCourseId == line.DirectionCourseId && t.NceeLineLevel == line.NceeLineLevel).ToList();
  1121. foreach (var courseLine in courseLines)
  1122. {
  1123. string inCourses = courseLine.CourseId.ToString();
  1124. if (courseLine.CourseId == CourseConst.ZONG_HE)
  1125. {
  1126. inCourses = "5, 6, 7, 9";
  1127. }
  1128. // 单上线:整体 - 方向
  1129. await rep.SqlNonQueryAsync($@"
  1130. 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)
  1131. SELECT {(short)NceeDataScopeType.TOTAL}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 0
  1132. FROM
  1133. (
  1134. SELECT
  1135. T1.grade_id,
  1136. COUNT(1) AS line_count,
  1137. (
  1138. SELECT COUNT(1) AS total_count
  1139. FROM
  1140. (
  1141. SELECT DISTINCT T1.grade_id, T2.ncee_student_id
  1142. FROM ncee_student AS T1
  1143. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1144. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1145. GROUP BY T1.grade_id, T2.ncee_student_id
  1146. ) AS T1
  1147. ) AS total_count
  1148. FROM
  1149. (
  1150. SELECT T1.grade_id, T2.ncee_student_id, SUM(T2.score_x) AS course_score_x
  1151. FROM ncee_student AS T1
  1152. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1153. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1154. GROUP BY T1.grade_id, T2.ncee_student_id
  1155. ) AS T1
  1156. WHERE T1.course_score_x >= @courseLineScoreX
  1157. GROUP BY T1.grade_id
  1158. ) AS T1
  1159. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
  1160. // 双上线:整体 - 方向
  1161. await rep.SqlNonQueryAsync($@"
  1162. 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)
  1163. SELECT {(short)NceeDataScopeType.TOTAL}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 1
  1164. FROM
  1165. (
  1166. SELECT
  1167. T1.grade_id,
  1168. COUNT(1) AS line_count,
  1169. (
  1170. SELECT COUNT(1) AS total_count
  1171. FROM
  1172. (
  1173. SELECT DISTINCT T1.grade_id, T2.ncee_student_id
  1174. FROM ncee_student AS T1
  1175. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1176. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1177. GROUP BY T1.grade_id, T2.ncee_student_id
  1178. ) AS T1
  1179. ) AS total_count
  1180. FROM
  1181. (
  1182. SELECT T1.grade_id, T2.ncee_student_id, MAX(T1.score_x) AS score_x, SUM(T2.score_x) AS course_score_x
  1183. FROM ncee_student AS T1
  1184. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1185. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1186. GROUP BY T1.grade_id, T2.ncee_student_id
  1187. ) AS T1
  1188. WHERE T1.score_x >= @lineScoreX AND T1.course_score_x >= @courseLineScoreX
  1189. GROUP BY T1.grade_id
  1190. ) AS T1
  1191. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
  1192. // 单上线:机构 - 方向
  1193. await rep.SqlNonQueryAsync($@"
  1194. 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)
  1195. SELECT {(short)NceeDataScopeType.ORG}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 0
  1196. FROM
  1197. (
  1198. SELECT
  1199. T1.sys_org_id,
  1200. T1.grade_id,
  1201. COUNT(1) AS line_count,
  1202. T2.total_count
  1203. FROM
  1204. (
  1205. SELECT T1.sys_org_id, T1.grade_id, T2.ncee_student_id, SUM(T2.score_x) AS course_score_x
  1206. FROM ncee_student AS T1
  1207. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1208. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1209. GROUP BY T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1210. ) AS T1
  1211. JOIN
  1212. (
  1213. SELECT T1.sys_org_id, COUNT(1) AS total_count
  1214. FROM
  1215. (
  1216. SELECT DISTINCT T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1217. FROM ncee_student AS T1
  1218. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1219. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1220. GROUP BY T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1221. ) AS T1
  1222. GROUP BY T1.sys_org_id
  1223. ) AS T2 ON T1.sys_org_id = T2.sys_org_id
  1224. WHERE T1.course_score_x >= @courseLineScoreX
  1225. GROUP BY T1.sys_org_id, T1.grade_id
  1226. ) AS T1
  1227. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
  1228. // 双上线:机构 - 方向
  1229. await rep.SqlNonQueryAsync($@"
  1230. 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)
  1231. SELECT {(short)NceeDataScopeType.ORG}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 1
  1232. FROM
  1233. (
  1234. SELECT
  1235. T1.sys_org_id,
  1236. T1.grade_id,
  1237. COUNT(1) AS line_count,
  1238. T2.total_count
  1239. FROM
  1240. (
  1241. 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
  1242. FROM ncee_student AS T1
  1243. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1244. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1245. GROUP BY T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1246. ) AS T1
  1247. JOIN
  1248. (
  1249. SELECT T1.sys_org_id, COUNT(1) AS total_count
  1250. FROM
  1251. (
  1252. SELECT DISTINCT T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1253. FROM ncee_student AS T1
  1254. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1255. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1256. GROUP BY T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1257. ) AS T1
  1258. GROUP BY T1.sys_org_id
  1259. ) AS T2 ON T1.sys_org_id = T2.sys_org_id
  1260. WHERE T1.score_x >= @lineScoreX AND T1.course_score_x >= @courseLineScoreX
  1261. GROUP BY T1.sys_org_id, T1.grade_id
  1262. ) AS T1
  1263. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
  1264. // 单上线:机构 - 方向 - 组合
  1265. await rep.SqlNonQueryAsync($@"
  1266. 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)
  1267. SELECT {(short)NceeDataScopeType.COMB}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 0
  1268. FROM
  1269. (
  1270. SELECT
  1271. T1.ncee_course_comb_id,
  1272. T1.sys_org_id,
  1273. T1.grade_id,
  1274. COUNT(1) AS line_count,
  1275. T2.total_count
  1276. FROM
  1277. (
  1278. 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
  1279. FROM ncee_student AS T1
  1280. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1281. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1282. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1283. ) AS T1
  1284. JOIN
  1285. (
  1286. SELECT T1.ncee_course_comb_id, T1.sys_org_id, COUNT(1) AS total_count
  1287. FROM
  1288. (
  1289. SELECT DISTINCT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1290. FROM ncee_student AS T1
  1291. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1292. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1293. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1294. ) AS T1
  1295. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id
  1296. ) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.ncee_course_comb_id = T2.ncee_course_comb_id
  1297. WHERE T1.course_score_x >= @courseLineScoreX
  1298. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id
  1299. ) AS T1
  1300. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
  1301. // 双上线:机构 - 方向 - 组合
  1302. await rep.SqlNonQueryAsync($@"
  1303. 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)
  1304. SELECT {(short)NceeDataScopeType.COMB}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 1
  1305. FROM
  1306. (
  1307. SELECT
  1308. T1.ncee_course_comb_id,
  1309. T1.sys_org_id,
  1310. T1.grade_id,
  1311. COUNT(1) AS line_count,
  1312. T2.total_count
  1313. FROM
  1314. (
  1315. 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
  1316. FROM ncee_student AS T1
  1317. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1318. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1319. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1320. ) AS T1
  1321. JOIN
  1322. (
  1323. SELECT T1.ncee_course_comb_id, T1.sys_org_id, COUNT(1) AS total_count
  1324. FROM
  1325. (
  1326. SELECT DISTINCT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1327. FROM ncee_student AS T1
  1328. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1329. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1330. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T2.ncee_student_id
  1331. ) AS T1
  1332. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id
  1333. ) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.ncee_course_comb_id = T2.ncee_course_comb_id
  1334. WHERE T1.score_x >= @lineScoreX AND T1.course_score_x >= @courseLineScoreX
  1335. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id
  1336. ) AS T1
  1337. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
  1338. // 机构 - 班级 - 方向 - 组合
  1339. await rep.SqlNonQueryAsync($@"
  1340. 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)
  1341. SELECT {(short)NceeDataScopeType.CLASS}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 0
  1342. FROM
  1343. (
  1344. SELECT
  1345. T1.ncee_course_comb_id,
  1346. T1.sys_org_id,
  1347. T1.grade_id,
  1348. T1.class_number,
  1349. COUNT(1) AS line_count,
  1350. T2.total_count
  1351. FROM
  1352. (
  1353. 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
  1354. FROM ncee_student AS T1
  1355. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1356. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1357. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
  1358. ) AS T1
  1359. JOIN
  1360. (
  1361. SELECT T1.ncee_course_comb_id, T1.sys_org_id, T1.class_number, COUNT(1) AS total_count
  1362. FROM
  1363. (
  1364. SELECT DISTINCT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
  1365. FROM ncee_student AS T1
  1366. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1367. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1368. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
  1369. ) AS T1
  1370. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.class_number
  1371. ) 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
  1372. WHERE T1.course_score_x >= @courseLineScoreX
  1373. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number
  1374. ) AS T1
  1375. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
  1376. // 机构 - 班级 - 方向 - 组合
  1377. await rep.SqlNonQueryAsync($@"
  1378. 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)
  1379. SELECT {(short)NceeDataScopeType.CLASS}, @nceePlanId, @nceeLineLevel, @directionCourseId, @courseId, T1.*, T1.line_count / T1.total_count AS line_rate, 1
  1380. FROM
  1381. (
  1382. SELECT
  1383. T1.ncee_course_comb_id,
  1384. T1.sys_org_id,
  1385. T1.grade_id,
  1386. T1.class_number,
  1387. COUNT(1) AS line_count,
  1388. T2.total_count
  1389. FROM
  1390. (
  1391. 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
  1392. FROM ncee_student AS T1
  1393. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1394. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1395. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
  1396. ) AS T1
  1397. JOIN
  1398. (
  1399. SELECT T1.ncee_course_comb_id, T1.sys_org_id, T1.class_number, COUNT(1) AS total_count
  1400. FROM
  1401. (
  1402. SELECT DISTINCT T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
  1403. FROM ncee_student AS T1
  1404. LEFT JOIN ncee_score AS T2 ON T1.id = T2.ncee_student_id
  1405. WHERE T1.ncee_plan_id = @nceePlanId AND T1.direction_course_id = @directionCourseId AND T2.score > 0 AND T2.course_id IN({inCourses})
  1406. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number, T2.ncee_student_id
  1407. ) AS T1
  1408. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.class_number
  1409. ) 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
  1410. WHERE T1.score_x >= @lineScoreX AND T1.course_score_x >= @courseLineScoreX
  1411. GROUP BY T1.ncee_course_comb_id, T1.sys_org_id, T1.grade_id, T1.class_number
  1412. ) AS T1
  1413. ", new { NceePlanId = nceePlanId, line.NceeLineLevel, line.DirectionCourseId, line.LineScoreX, courseLine.CourseId, CourseLineScoreX = courseLine.LineScoreX });
  1414. }
  1415. }
  1416. #endregion
  1417. }
  1418. /// <summary>
  1419. /// 执行分数转换
  1420. /// </summary>
  1421. /// <param name="nceePlanId"></param>
  1422. /// <returns></returns>
  1423. private async Task ExecuteScoreConvert(int nceePlanId)
  1424. {
  1425. await rep.Change<NceeConvertRange>().Where(t => t.NceePlanId == nceePlanId).ExecuteDeleteAsync();
  1426. var convertGrades = await rep.Change<NceeConvertGrade>().DetachedEntities.OrderBy(t => t.Sequence).ToListAsync();
  1427. var convertGradeDict = convertGrades.ToDictionary(t => t.Id, t => t);
  1428. // 分科转换
  1429. foreach (var courseId in NceeUtil.ChooseCourses)
  1430. {
  1431. var scores = await rep.DetachedEntities.Where(t => t.NceeStudent.NceePlanId == nceePlanId && t.CourseId == courseId && t.Score > 0).OrderByDescending(t => t.Score).ToListAsync();
  1432. if (scores.Count == 0)
  1433. {
  1434. continue;
  1435. }
  1436. var convertRanges = GetConvertRange(nceePlanId, courseId, convertGrades, scores);
  1437. // 更新转换区间
  1438. await rep.Change<NceeConvertRange>().Where(t => t.NceePlanId == nceePlanId && t.CourseId == courseId).ExecuteDeleteAsync();
  1439. await rep.Change<NceeConvertRange>().InsertNowAsync(convertRanges);
  1440. // 更新转换分
  1441. List<string> replaceValues = [];
  1442. int cscount = scores.Count;
  1443. for (int i = 0; i < cscount; i++)
  1444. {
  1445. var s = scores[i];
  1446. var cr = convertRanges.FirstOrDefault(t => s.Score >= t.MinScore && s.Score <= t.MaxScore);
  1447. var cg = convertGradeDict[cr.NceeConvertGradeId];
  1448. var scoreX = GetScoreX(s.Score, cg, cr);
  1449. replaceValues.Add($"({s.Id}, {nceePlanId}, {s.NceeStudentId}, {s.CourseId}, {s.Score}, {scoreX}, {cr.NceeConvertGradeId}, '{cg.Name}')");
  1450. if ((i + 1) % 1000 == 0 || i == cscount - 1)
  1451. {
  1452. string replaceSql = $@"
  1453. 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
  1454. {string.Join(",", replaceValues)}
  1455. ";
  1456. await rep.SqlNonQueryAsync(replaceSql);
  1457. replaceValues.Clear();
  1458. }
  1459. }
  1460. }
  1461. // 更新总分
  1462. await rep.SqlNonQueryAsync($@"
  1463. -- 更新总分
  1464. UPDATE ncee_student AS T1
  1465. JOIN
  1466. (
  1467. SELECT ncee_student_id, SUM(score) AS score, SUM(score_x) AS score_x
  1468. FROM ncee_score
  1469. WHERE ncee_plan_id = @nceePlanId
  1470. GROUP BY ncee_student_id
  1471. ) AS T2 ON T1.id = T2.ncee_student_id
  1472. SET T1.score = T2.score, T1.score_x = T2.score_x
  1473. WHERE T1.ncee_plan_id = @nceePlanId
  1474. ;", new { NceePlanId = nceePlanId });
  1475. }
  1476. /// <summary>
  1477. /// 更新排名(在整体中的排名和在机构内的排名)
  1478. /// </summary>
  1479. /// <param name="nceePlanId"></param>
  1480. /// <returns></returns>
  1481. private async Task ExecuteUpdateOrder(int nceePlanId)
  1482. {
  1483. await rep.SqlNonQueryAsync($@"
  1484. UPDATE ncee_student AS T1
  1485. JOIN
  1486. (
  1487. SELECT id,
  1488. RANK() OVER(PARTITION BY direction_course_id ORDER BY score DESC) AS order_in_total,
  1489. RANK() OVER(PARTITION BY direction_course_id ORDER BY score_x DESC) AS order_in_total_x,
  1490. RANK() OVER(PARTITION BY direction_course_id, sys_org_id ORDER BY score DESC) AS order_in_org,
  1491. RANK() OVER(PARTITION BY direction_course_id, sys_org_id ORDER BY score_x DESC) AS order_in_org_x
  1492. FROM ncee_student
  1493. WHERE ncee_plan_id = @nceePlanId
  1494. ) AS T2 ON T1.id = T2.id
  1495. SET T1.order_in_total = T2.order_in_total,
  1496. T1.order_in_total_x = T2.order_in_total_x,
  1497. T1.order_in_org = T2.order_in_org,
  1498. T1.order_in_org_x = T2.order_in_org_x
  1499. ;", new { NceePlanId = nceePlanId });
  1500. }
  1501. /// <summary>
  1502. /// 获取转换区间
  1503. /// </summary>
  1504. /// <param name="nceePlanId"></param>
  1505. /// <param name="courseId"></param>
  1506. /// <param name="convertGrades"></param>
  1507. /// <param name="nceeScores"></param>
  1508. /// <returns></returns>
  1509. private static List<NceeConvertRange> GetConvertRange(int nceePlanId, short courseId, List<NceeConvertGrade> convertGrades, List<NceeScore> nceeScores)
  1510. {
  1511. int scount = nceeScores.Count;
  1512. var totalMaxScore = nceeScores.Select(t => t.Score).Max();
  1513. var totalMinScore = nceeScores.Select(t => t.Score).Min();
  1514. var cgs = convertGrades.OrderBy(t => t.Id).ToList();
  1515. var scores = nceeScores.OrderByDescending(t => t.Score).ToList();
  1516. List<NceeConvertRange> ncrs = [];
  1517. decimal lastMinScore = decimal.MaxValue;
  1518. foreach (var cg in cgs)
  1519. {
  1520. NceeConvertRange range = new()
  1521. {
  1522. NceePlanId = nceePlanId,
  1523. NceeConvertGradeId = cg.Id,
  1524. CourseId = courseId,
  1525. };
  1526. var i = (int)Math.Min(Math.Floor(cg.EndRate * scount), scount - 1);
  1527. if (cg.BeginRate == 0)
  1528. {
  1529. range.MaxScore = totalMaxScore;
  1530. }
  1531. else
  1532. {
  1533. range.MaxScore = scores.Where(t => t.Score < lastMinScore).Select(t => t.Score).Max();
  1534. }
  1535. if (cg.EndRate == 1)
  1536. {
  1537. range.MinScore = totalMinScore;
  1538. }
  1539. else
  1540. {
  1541. range.MinScore = scores[i].Score;
  1542. }
  1543. lastMinScore = range.MinScore;
  1544. ncrs.Add(range);
  1545. }
  1546. return ncrs;
  1547. }
  1548. /// <summary>
  1549. /// 获取转换分
  1550. /// </summary>
  1551. /// <param name="score"></param>
  1552. /// <param name="convertGrade"></param>
  1553. /// <param name="convertRange"></param>
  1554. /// <returns></returns>
  1555. private static decimal GetScoreX(decimal score, NceeConvertGrade convertGrade, NceeConvertRange convertRange)
  1556. {
  1557. // (Y2 - Y) / (Y- Y1) = (X2 - X) / (X - X1)
  1558. // Y1,Y2为原始分区间下限和上限
  1559. // X1,X2为转换分区间下限和上限
  1560. // Y为原始分
  1561. // X为转换分
  1562. //// X = ((Y - Y1) * X2 + (Y2 - Y) * X1) / (Y2 - Y1)
  1563. //var y = score;
  1564. //var y1 = convertRange.MinScore;
  1565. //var y2 = convertRange.MaxScore;
  1566. //var x1 = convertGrade.MinScore;
  1567. //var x2 = convertGrade.MaxScore;
  1568. //var x = ((y - y1) * x2 + (y2 - y) * x1) / (y2 - y1);
  1569. //return x;
  1570. // a = Y2 - Y
  1571. var a = (convertRange.MaxScore - score);
  1572. // b = Y - Y1
  1573. var b = (score - convertRange.MinScore);
  1574. return Math.Round((b * convertGrade.MaxScore + a * convertGrade.MinScore) / (a + b));
  1575. }
  1576. #endregion
  1577. }