ExamScoreImportService.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. using Furion.ClayObject.Extensions;
  2. using Furion.DatabaseAccessor.Extensions;
  3. using NPOI.SS.UserModel;
  4. using YBEE.EQM.Core;
  5. namespace YBEE.EQM.Application;
  6. /// <summary>
  7. /// 学生成绩导入服务
  8. /// </summary>
  9. public class ExamScoreImportService : IExamScoreImportService, ITransient
  10. {
  11. private readonly IRepository<ExamScore> _rep;
  12. private readonly ISchoolClassService _schoolClassService;
  13. private readonly IExamGradeService _examGradeService;
  14. public ExamScoreImportService(IRepository<ExamScore> rep, ISchoolClassService schoolClassService, IExamGradeService examGradeService)
  15. {
  16. _rep = rep;
  17. _schoolClassService = schoolClassService;
  18. _examGradeService = examGradeService;
  19. }
  20. /// <summary>
  21. /// 批量导入前期未上报学生名单的各科成绩(初始化)
  22. /// </summary>
  23. /// <param name="filePath"></param>
  24. /// <param name="examPlanId"></param>
  25. /// <returns></returns>
  26. public async Task UploadImportWithoutStudentTotalScore(string filePath, int examPlanId)
  27. {
  28. /* ----------------------------------------------------------
  29. * 处理步骤:
  30. * 1.验证表头
  31. * 2.读取数据
  32. * 3.处理班级
  33. * 4.处理学生
  34. * 5.批量插入
  35. ---------------------------------------------------------- */
  36. try
  37. {
  38. #region 1.验证表结构
  39. using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
  40. IWorkbook workbook = ExcelUtil.GetWorkbook(filePath, fs);
  41. var sheet = workbook.GetSheetAt(0);
  42. var rows = sheet.GetRowEnumerator();
  43. // 少于2行验证
  44. if (sheet.LastRowNum < 2)
  45. {
  46. //"第一行应为填写说明,第二行应为标题行,请勿修改模板结构。"
  47. return;
  48. }
  49. // 读取表头
  50. rows.MoveNext();
  51. IRow headerRow = (IRow)rows.Current;
  52. int index = 0;
  53. int SAMPLE_TYPE_INDEX = index++;
  54. int SCHOOL_ID_INDEX = index++;
  55. int SCHOOL_NAME_INDEX = index++;
  56. int SCHOOL_BID_INDEX = index++;
  57. int SCHOOL_BNAME_INDEX = index++;
  58. int NAME_INDEX = index++;
  59. int CERT_TYPE_INDEX = index++;
  60. int ID_NUM_INDEX = index++;
  61. int EXAM_NUMBER_INDEX = index++;
  62. int COURSE_COMB_INDEX = index++;
  63. int GRADE_INDEX = index++;
  64. int CLASS_INDEX = index++;
  65. int COURSE_START_INDEX = index;
  66. Dictionary<int, string> headers = new()
  67. {
  68. { SAMPLE_TYPE_INDEX, "抽样类型" },
  69. { SCHOOL_ID_INDEX, "学校ID" },
  70. { SCHOOL_NAME_INDEX, "学校" },
  71. { SCHOOL_BID_INDEX, "校区ID" },
  72. { SCHOOL_BNAME_INDEX, "校区" },
  73. { NAME_INDEX, "姓名" },
  74. { CERT_TYPE_INDEX, "证件类型" },
  75. { ID_NUM_INDEX, "证件号码" },
  76. { EXAM_NUMBER_INDEX, "考号" },
  77. { COURSE_COMB_INDEX, "选科组合" },
  78. { GRADE_INDEX, "年级" },
  79. { CLASS_INDEX, "班级" },
  80. };
  81. List<string> headerErrors = new();
  82. for (int i = 0; i < COURSE_START_INDEX; i++)
  83. {
  84. if (headerRow.GetCell(i)?.ToString() != headers[i])
  85. {
  86. char letter = (char)('A' + i);
  87. headerErrors.Add(letter.ToString());
  88. }
  89. }
  90. if (headerErrors.Any())
  91. {
  92. string columnErrors = string.Join("、", headerErrors);
  93. //result.ErrorMessage.Add($"第1行标题行{columnErrors}列名错误。从A列开始依次应为抽样类型、学校ID、学校、姓名、证件类型、证件号码、考号、年级、班级。");
  94. //return result;
  95. return;
  96. }
  97. //result.StructureCorrect = true;
  98. #endregion
  99. #region 2.读取数据
  100. var examPlan = await _rep.Change<ExamPlan>().DetachedEntities.FirstOrDefaultAsync(t => t.Id == examPlanId) ?? throw Oops.Oh(ErrorCode.E2001, "监测计划");
  101. var examGradeDict = (await _examGradeService.GetListByExamPlanId(examPlanId)).ToDictionary(t => t.Grade.GradeNumber);
  102. var courseDict = (await _rep.Change<Course>().DetachedEntities.ToListAsync()).ToDictionary(t => t.Name);
  103. // 获取需要导入的科目列表
  104. Dictionary<int, Course> courses = new();
  105. for (int gi = COURSE_START_INDEX; gi < headerRow.LastCellNum; gi++)
  106. {
  107. var cn = headerRow.GetCell(gi).ToString() ?? "";
  108. if (string.IsNullOrEmpty(cn))
  109. {
  110. continue;
  111. }
  112. courses.Add(gi, courseDict[cn]);
  113. }
  114. int rn = 1;
  115. List<ExamScoreImportDto> sourceItems = new();
  116. while (rows.MoveNext())
  117. {
  118. rn++;
  119. IRow row = (IRow)rows.Current;
  120. string rv = row.GetCell(0)?.ToString().Trim() ?? "";
  121. if (rv == "")
  122. {
  123. break;
  124. }
  125. for (int gi = COURSE_START_INDEX; gi < headerRow.LastCellNum; gi++)
  126. {
  127. var course = courses[gi];
  128. var sbid = row.GetCell(SCHOOL_BID_INDEX)?.NumericCellValue;
  129. var ccid = row.GetCell(COURSE_COMB_INDEX)?.NumericCellValue;
  130. ExamScoreImportDto item = new()
  131. {
  132. RowNumber = rn,
  133. SampleType = (ExamSampleType)row.GetCell(SAMPLE_TYPE_INDEX).NumericCellValue,
  134. SysOrgId = (short)row.GetCell(SCHOOL_ID_INDEX).NumericCellValue,
  135. SysOrgBranchId = sbid > 0 ? (short)sbid : null,
  136. StudentName = StringUtil.ClearWhite(row.GetCell(NAME_INDEX)?.ToString() ?? ""),
  137. CertificateType = (CertificateType)row.GetCell(CERT_TYPE_INDEX).NumericCellValue,
  138. IdNumber = StringUtil.ClearIdNumber(row.GetCell(ID_NUM_INDEX)?.ToString() ?? ""),
  139. ExamNumber = row.GetCell(EXAM_NUMBER_INDEX)?.ToString() ?? "",
  140. GradeNumber = (short)row.GetCell(GRADE_INDEX).NumericCellValue,
  141. ClassNumber = (short)row.GetCell(CLASS_INDEX).NumericCellValue,
  142. CourseId = course.Id,
  143. NceeCourseCombId = ccid > 0 ? (short)ccid : null,
  144. };
  145. string scoreStr = row.GetCell(gi)?.ToString() ?? "";
  146. if (decimal.TryParse(scoreStr, out decimal score))
  147. {
  148. item.Score = score;
  149. }
  150. else if (scoreStr.Contains('特') || scoreStr.Contains('缺'))
  151. {
  152. item.IsExcluded = true;
  153. }
  154. if (item.IdNumber.Length == 18)
  155. {
  156. if (int.TryParse(item.IdNumber.AsSpan(16, 1), out int gn))
  157. {
  158. item.Gender = (short)(gn % 2 == 0 ? 2 : 1);
  159. }
  160. }
  161. var eg = examGradeDict[item.GradeNumber];
  162. item.ExamGradeId = eg.Id;
  163. item.GradeId = eg.GradeId;
  164. item.GradeBeginYear = eg.GradeBeginYear;
  165. item.GradeEndYear = eg.GradeEndYear;
  166. item.SchoolClassId = _schoolClassService.GetSchoolClassId(examPlan.EducationStage, item.SysOrgId, eg.GradeBeginYear, item.ClassNumber);
  167. sourceItems.Add(item);
  168. }
  169. }
  170. workbook.Close();
  171. fs.Close();
  172. #endregion
  173. #region 3.处理班级
  174. var scs = sourceItems.GroupBy(t => t.SchoolClassId).Select(t => new BatchInsertSchoolClassInput
  175. {
  176. Id = t.Key,
  177. SysOrgId = t.FirstOrDefault().SysOrgId,
  178. SysOrgBranchId = t.FirstOrDefault().SysOrgBranchId,
  179. EducationStage = examPlan.EducationStage,
  180. EducationYears = examPlan.EducationYears,
  181. ClassNumber = t.FirstOrDefault().ClassNumber,
  182. GradeBeginYear = t.FirstOrDefault().GradeBeginYear,
  183. GradeEndYear = t.FirstOrDefault().GradeEndYear,
  184. }).Distinct().ToList();
  185. // 插入没有的班级
  186. await _schoolClassService.BatchInsert(scs);
  187. #endregion
  188. #region 4.处理学生
  189. // 清理学生
  190. string deleteStudentSql = $"DELETE FROM exam_student WHERE exam_plan_id = {examPlanId};";
  191. await _rep.SqlNonQueryAsync(deleteStudentSql);
  192. var uid = CurrentSysUserInfo.SysUserId;
  193. if (uid == 0)
  194. {
  195. uid = 1;
  196. }
  197. var stus = sourceItems.GroupBy(t => t.RowNumber).Select(t => t.FirstOrDefault()).ToList();
  198. List<string> insertValues = new();
  199. int scount = stus.Count;
  200. for (int i = 0; i < scount; i++)
  201. {
  202. var t = stus[i];
  203. string sobid = "NULL";
  204. if (t.SysOrgBranchId.HasValue)
  205. {
  206. sobid = t.SysOrgBranchId.ToString();
  207. }
  208. insertValues.Add($"({examPlanId}, {t.SysOrgId}, {sobid}, {t.ExamGradeId}, {t.GradeId}, {t.SchoolClassId}, {t.ClassNumber}, '{t.ExamNumber}', '{t.StudentName}', {(short)t.CertificateType}, '{t.IdNumber}', {t.Gender}, {uid}, CURRENT_TIMESTAMP, 0)");
  209. if ((i + 1) % 1000 == 0 || i == scount - 1)
  210. {
  211. string insertSql = $@"
  212. INSERT INTO exam_student(exam_plan_id, sys_org_id, sys_org_branch_id, exam_grade_id, grade_id, school_class_id, class_number, exam_number, `name`, certificate_type, id_number, gender, create_sys_user_id, create_time, is_deleted) VALUES
  213. {string.Join(",", insertValues)}
  214. ";
  215. await _rep.SqlNonQueryAsync(insertSql);
  216. insertValues.Clear();
  217. }
  218. }
  219. #endregion
  220. #region 5.批量导入
  221. // 清理成绩
  222. string deleteScoreSql = $"DELETE FROM exam_score WHERE exam_plan_id = {examPlanId};";
  223. await _rep.SqlNonQueryAsync(deleteScoreSql);
  224. List<string> selects = new();
  225. scount = sourceItems.Count;
  226. for (int i = 0; i < scount; i++)
  227. {
  228. var t = sourceItems[i];
  229. string sobid = "NULL";
  230. if (t.SysOrgBranchId.HasValue)
  231. {
  232. sobid = t.SysOrgBranchId.ToString();
  233. }
  234. string ccid = "NULL";
  235. if (t.NceeCourseCombId.HasValue)
  236. {
  237. ccid = t.NceeCourseCombId.ToString();
  238. }
  239. var ied = t.IsExcluded ? 1 : 0;
  240. selects.Add($@"
  241. SELECT {(short)t.SampleType} est, {t.SysOrgId} soid, {sobid} as sobid, {t.GradeId} gid, {examPlan.SemesterId} smid, {t.SchoolClassId} scid, {t.ClassNumber} cn, '{t.ExamNumber}' en, {ccid} ccid, {t.CourseId} cid, {t.Score} s, {ied} ied ");
  242. if ((i + 1) % 500 == 0 || i == scount - 1)
  243. {
  244. string insertSql = $@"
  245. INSERT INTO exam_score(exam_plan_id, education_stage, exam_sample_type, sys_org_id, sys_org_branch_id, grade_id, semester_id, school_class_id, class_number, exam_student_id, ncee_course_comb_id, course_id, score, is_excluded)
  246. SELECT {examPlanId}, {(short)examPlan.EducationStage}, T1.est, T1.soid, T1.sobid, T1.gid, T1.smid, T1.scid, T1.cn, T2.id, T1.ccid, T1.cid, T1.s, T1.ied
  247. FROM
  248. ({string.Join("UNION ALL", selects)}
  249. ) AS T1
  250. JOIN (SELECT id, school_class_id, exam_number FROM exam_student WHERE exam_plan_id = {examPlanId}) AS T2
  251. ON T1.scid = T2.school_class_id AND T1.en = T2.exam_number
  252. ";
  253. await _rep.SqlNonQueryAsync(insertSql);
  254. selects.Clear();
  255. }
  256. }
  257. #endregion
  258. }
  259. catch (Exception ex)
  260. {
  261. throw new Exception(ex.Message);
  262. }
  263. finally
  264. {
  265. File.Delete(filePath);
  266. }
  267. }
  268. /// <summary>
  269. /// 批量导入学生总成绩
  270. /// </summary>
  271. /// <param name="filePath"></param>
  272. /// <param name="examPlanId"></param>
  273. /// <returns></returns>
  274. public async Task UploadImportStudentTotalScore(string filePath, int examPlanId)
  275. {
  276. /* ----------------------------------------------------------
  277. * 处理步骤:
  278. * 1.验证表头
  279. * 2.读取数据
  280. * 3.处理班级
  281. * 4.批量插入
  282. ---------------------------------------------------------- */
  283. try
  284. {
  285. #region 1.验证表结构
  286. using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
  287. IWorkbook workbook = ExcelUtil.GetWorkbook(filePath, fs);
  288. var sheet = workbook.GetSheetAt(0);
  289. var rows = sheet.GetRowEnumerator();
  290. // 少于2行验证
  291. if (sheet.LastRowNum < 2)
  292. {
  293. //"第一行应为填写说明,第二行应为标题行,请勿修改模板结构。"
  294. return;
  295. }
  296. // 读取表头
  297. rows.MoveNext();
  298. IRow headerRow = (IRow)rows.Current;
  299. int index = 0;
  300. int SAMPLE_TYPE_INDEX = index++;
  301. int SCHOOL_ID_INDEX = index++;
  302. int SCHOOL_NAME_INDEX = index++;
  303. int SCHOOL_BID_INDEX = index++;
  304. int SCHOOL_BNAME_INDEX = index++;
  305. int NAME_INDEX = index++;
  306. int CERT_TYPE_INDEX = index++;
  307. int ID_NUM_INDEX = index++;
  308. int EXAM_NUMBER_INDEX = index++;
  309. int COURSE_COMB_INDEX = index++;
  310. int GRADE_INDEX = index++;
  311. int CLASS_INDEX = index++;
  312. int COURSE_START_INDEX = index;
  313. Dictionary<int, string> headers = new()
  314. {
  315. { SAMPLE_TYPE_INDEX, "抽样类型" },
  316. { SCHOOL_ID_INDEX, "学校ID" },
  317. { SCHOOL_NAME_INDEX, "学校" },
  318. { SCHOOL_BID_INDEX, "校区ID" },
  319. { SCHOOL_BNAME_INDEX, "校区" },
  320. { NAME_INDEX, "姓名" },
  321. { CERT_TYPE_INDEX, "证件类型" },
  322. { ID_NUM_INDEX, "证件号码" },
  323. { EXAM_NUMBER_INDEX, "考号" },
  324. { COURSE_COMB_INDEX, "选科组合" },
  325. { GRADE_INDEX, "年级" },
  326. { CLASS_INDEX, "班级" },
  327. };
  328. List<string> headerErrors = new();
  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.Any())
  338. {
  339. string columnErrors = string.Join("、", headerErrors);
  340. //result.ErrorMessage.Add($"第1行标题行{columnErrors}列名错误。从A列开始依次应为抽样类型、学校ID、学校、姓名、证件类型、证件号码、考号、年级、班级。");
  341. //return result;
  342. return;
  343. }
  344. //result.StructureCorrect = true;
  345. #endregion
  346. #region 2.读取数据
  347. var examPlan = await _rep.Change<ExamPlan>().DetachedEntities.FirstOrDefaultAsync(t => t.Id == examPlanId) ?? throw Oops.Oh(ErrorCode.E2001, "监测计划");
  348. var examGradeDict = (await _examGradeService.GetListByExamPlanId(examPlanId)).ToDictionary(t => t.Grade.GradeNumber);
  349. var courseDict = (await _rep.Change<Course>().DetachedEntities.ToListAsync()).ToDictionary(t => t.Name);
  350. var examCourses = await _rep.Change<ExamCourse>().DetachedEntities.Where(t => t.ExamPlanId == examPlanId).Select(t => new { t.GradeId, t.CourseId }).ToListAsync();
  351. // 获取需要导入的科目列表
  352. Dictionary<int, Course> courses = new();
  353. for (int gi = COURSE_START_INDEX; gi < headerRow.LastCellNum; gi++)
  354. {
  355. var cn = headerRow.GetCell(gi).ToString() ?? "";
  356. if (string.IsNullOrEmpty(cn))
  357. {
  358. continue;
  359. }
  360. courses.Add(gi, courseDict[cn]);
  361. }
  362. int rn = 1;
  363. List<ExamScoreImportDto> sourceItems = new();
  364. while (rows.MoveNext())
  365. {
  366. rn++;
  367. IRow row = (IRow)rows.Current;
  368. string rv = row.GetCell(0)?.ToString().Trim() ?? "";
  369. if (rv == "")
  370. {
  371. break;
  372. }
  373. var gradeNumber = (short)row.GetCell(GRADE_INDEX).NumericCellValue;
  374. for (int gi = COURSE_START_INDEX; gi < headerRow.LastCellNum; gi++)
  375. {
  376. var course = courses[gi];
  377. var eg = examGradeDict[gradeNumber];
  378. // 跳过未监测科目
  379. if (!examCourses.Any(t => t.GradeId == eg.GradeId && t.CourseId == course.Id))
  380. {
  381. continue;
  382. }
  383. var sbid = row.GetCell(SCHOOL_BID_INDEX)?.NumericCellValue;
  384. var ccid = row.GetCell(COURSE_COMB_INDEX)?.NumericCellValue;
  385. ExamScoreImportDto item = new()
  386. {
  387. RowNumber = rn,
  388. SampleType = (ExamSampleType)row.GetCell(SAMPLE_TYPE_INDEX).NumericCellValue,
  389. SysOrgId = (short)row.GetCell(SCHOOL_ID_INDEX).NumericCellValue,
  390. SysOrgBranchId = sbid > 0 ? (short)sbid : null,
  391. StudentName = StringUtil.ClearWhite(row.GetCell(NAME_INDEX)?.ToString() ?? ""),
  392. CertificateType = (CertificateType)row.GetCell(CERT_TYPE_INDEX).NumericCellValue,
  393. IdNumber = StringUtil.ClearIdNumber(row.GetCell(ID_NUM_INDEX)?.ToString() ?? ""),
  394. ExamNumber = row.GetCell(EXAM_NUMBER_INDEX)?.ToString() ?? "",
  395. GradeNumber = gradeNumber,
  396. ClassNumber = (short)row.GetCell(CLASS_INDEX).NumericCellValue,
  397. CourseId = course.Id,
  398. NceeCourseCombId = ccid > 0 ? (short)ccid : null,
  399. };
  400. string scoreStr = row.GetCell(gi)?.ToString() ?? "";
  401. if (decimal.TryParse(scoreStr, out decimal score))
  402. {
  403. item.Score = score;
  404. }
  405. else if (scoreStr.Contains('特') || scoreStr.Contains('缺'))
  406. {
  407. item.IsExcluded = true;
  408. }
  409. if (item.IdNumber.Length == 18)
  410. {
  411. if (int.TryParse(item.IdNumber.AsSpan(16, 1), out int gn))
  412. {
  413. item.Gender = (short)(gn % 2 == 0 ? 2 : 1);
  414. }
  415. }
  416. item.ExamGradeId = eg.Id;
  417. item.GradeId = eg.GradeId;
  418. item.GradeBeginYear = eg.GradeBeginYear;
  419. item.GradeEndYear = eg.GradeEndYear;
  420. item.SchoolClassId = _schoolClassService.GetSchoolClassId(examPlan.EducationStage, item.SysOrgId, eg.GradeBeginYear, item.ClassNumber);
  421. sourceItems.Add(item);
  422. }
  423. }
  424. workbook.Close();
  425. fs.Close();
  426. #endregion
  427. #region 3.处理班级
  428. var scs = sourceItems.GroupBy(t => t.SchoolClassId).Select(t => new BatchInsertSchoolClassInput
  429. {
  430. Id = t.Key,
  431. SysOrgId = t.FirstOrDefault().SysOrgId,
  432. SysOrgBranchId = t.FirstOrDefault().SysOrgBranchId,
  433. EducationStage = examPlan.EducationStage,
  434. EducationYears = examPlan.EducationYears,
  435. ClassNumber = t.FirstOrDefault().ClassNumber,
  436. GradeBeginYear = t.FirstOrDefault().GradeBeginYear,
  437. GradeEndYear = t.FirstOrDefault().GradeEndYear,
  438. }).Distinct().ToList();
  439. // 插入没有的班级
  440. await _schoolClassService.BatchInsert(scs);
  441. #endregion
  442. #region 4.批量导入
  443. // 清理成绩
  444. string deleteScoreSql = $"DELETE FROM exam_score WHERE exam_plan_id = {examPlanId};";
  445. await _rep.SqlNonQueryAsync(deleteScoreSql);
  446. List<string> selects = new();
  447. var scount = sourceItems.Count;
  448. for (int i = 0; i < scount; i++)
  449. {
  450. var t = sourceItems[i];
  451. string sobid = "NULL";
  452. if (t.SysOrgBranchId.HasValue)
  453. {
  454. sobid = t.SysOrgBranchId.ToString();
  455. }
  456. string ccid = "NULL";
  457. if (t.NceeCourseCombId.HasValue)
  458. {
  459. ccid = t.NceeCourseCombId.ToString();
  460. }
  461. var ied = t.IsExcluded ? 1 : 0;
  462. selects.Add($@"
  463. SELECT {(short)t.SampleType} est, {t.SysOrgId} soid, {sobid} as sobid, {t.GradeId} gid, {examPlan.SemesterId} smid, {t.SchoolClassId} scid, {t.ClassNumber} cn, '{t.ExamNumber}' en, {ccid} ccid, {t.CourseId} cid, {t.Score} s, {ied} ied ");
  464. if ((i + 1) % 500 == 0 || i == scount - 1)
  465. {
  466. string insertSql = $@"
  467. SET @examSampleId = (SELECT MAX(id) FROM exam_sample WHERE exam_plan_id = {examPlanId} AND is_selected = 1);
  468. INSERT INTO exam_score(exam_plan_id, education_stage, exam_sample_type, sys_org_id, sys_org_branch_id, grade_id, semester_id, school_class_id, class_number, exam_student_id, ncee_course_comb_id, course_id, score, is_excluded)
  469. SELECT {examPlanId}, {(short)examPlan.EducationStage}, T1.est, T1.soid, T1.sobid, T1.gid, T1.smid, T1.scid, T1.cn, T2.id, T1.ccid, T1.cid, T1.s, T1.ied
  470. FROM
  471. ({string.Join("UNION ALL", selects)}
  472. ) AS T1
  473. JOIN (SELECT exam_number, exam_student_id AS id FROM exam_sample_student WHERE exam_sample_id = @examSampleId) AS T2
  474. ON T1.en = T2.exam_number;
  475. ";
  476. await _rep.SqlNonQueryAsync(insertSql);
  477. selects.Clear();
  478. }
  479. }
  480. #endregion
  481. #region 5.计算总分和分段
  482. await $@"
  483. -- 更新各科成绩分段
  484. UPDATE exam_score AS T1
  485. JOIN
  486. (
  487. SELECT T1.id, T1.grade_id, T1.course_id, get_exam_score_range_id(T2.exam_score_range_type, T1.score) AS exam_score_range_id
  488. FROM exam_score AS T1
  489. JOIN exam_course AS T2 ON T1.exam_plan_id = T2.exam_plan_id AND T1.grade_id = T2.grade_id AND T1.course_id = T2.course_id
  490. WHERE T1.exam_plan_id = {examPlanId}
  491. ) AS T2 ON T1.id = T2.id
  492. SET T1.exam_score_range_id = T2.exam_score_range_id
  493. WHERE T1.exam_plan_id = {examPlanId};
  494. -- 更新总成绩和分段
  495. DELETE FROM exam_score_total WHERE exam_plan_id = {examPlanId};
  496. INSERT INTO exam_score_total(
  497. exam_plan_id,
  498. education_stage,
  499. exam_sample_type,
  500. sys_org_id,
  501. sys_org_branch_id,
  502. grade_id, semester_id,
  503. school_class_id,
  504. class_number,
  505. exam_student_id,
  506. ncee_course_comb_id,
  507. course_count,
  508. score,
  509. exam_score_range_id,
  510. is_excluded
  511. )
  512. SELECT {examPlanId}, T1.*, get_exam_score_range_id(T2.exam_score_range_type, T1.score) AS exam_score_range_id, 0
  513. FROM
  514. (
  515. SELECT
  516. education_stage,
  517. exam_sample_type,
  518. sys_org_id,
  519. sys_org_branch_id,
  520. grade_id, semester_id,
  521. school_class_id,
  522. class_number,
  523. exam_student_id,
  524. ncee_course_comb_id,
  525. COUNT(1) AS course_count,
  526. SUM(IFNULL(score, 0)) AS score
  527. FROM exam_score
  528. WHERE exam_plan_id = {examPlanId}
  529. GROUP BY education_stage, exam_sample_type, sys_org_id, sys_org_branch_id, grade_id, semester_id, school_class_id, class_number, exam_student_id, ncee_course_comb_id
  530. ) AS T1
  531. JOIN
  532. (
  533. SELECT grade_id, exam_score_range_type FROM exam_grade WHERE exam_plan_id = {examPlanId}
  534. ) AS T2 ON T1.grade_id = T2.grade_id;
  535. ".SetCommandTimeout(6000).SqlNonQueryAsync();
  536. #endregion
  537. }
  538. catch (Exception ex)
  539. {
  540. throw new Exception(ex.Message);
  541. }
  542. finally
  543. {
  544. File.Delete(filePath);
  545. }
  546. }
  547. }