LessonRecordController.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. using DocumentFormat.OpenXml.Drawing.Charts;
  2. using DocumentFormat.OpenXml.Spreadsheet;
  3. using HTEX.Lib.ETL.Lesson;
  4. using MathNet.Numerics.Distributions;
  5. using Microsoft.AspNetCore.Mvc;
  6. using Microsoft.Azure.Cosmos;
  7. using Microsoft.Extensions.Logging;
  8. using StackExchange.Redis;
  9. using System.Collections.Concurrent;
  10. using System.Collections.Generic;
  11. using System.Diagnostics;
  12. using System.Reflection;
  13. using System.Text.Json;
  14. using System.Text.RegularExpressions;
  15. using System.Xml;
  16. using TEAMModelOS.SDK;
  17. using TEAMModelOS.SDK.DI;
  18. using TEAMModelOS.SDK.Extension;
  19. using TEAMModelOS.SDK.Helper.Common.FileHelper;
  20. using TEAMModelOS.SDK.Models;
  21. using TEAMModelOS.SDK.Models.Cosmos.Common;
  22. using TEAMModelOS.SDK.Models.Cosmos.OpenEntity;
  23. namespace HTEX.DataETL.Controllers
  24. {
  25. [ApiController]
  26. [Route("lesson-record")]
  27. public class LessonRecordController : ControllerBase
  28. {
  29. private readonly ILogger<LessonRecordController> _logger;
  30. private readonly AzureCosmosFactory _azureCosmos;
  31. private readonly AzureStorageFactory _azureStorage;
  32. private readonly IConfiguration _configuration;
  33. private readonly IWebHostEnvironment _webHostEnvironment;
  34. private readonly DingDing _dingDing;
  35. private readonly AzureRedisFactory _azureRedis;
  36. public LessonRecordController(ILogger<LessonRecordController> logger, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage , IConfiguration configuration, IWebHostEnvironment environment,DingDing dingDing,AzureRedisFactory azureRedis )
  37. {
  38. _logger = logger;
  39. _azureCosmos = azureCosmos;
  40. _azureStorage = azureStorage;
  41. _configuration = configuration;
  42. _webHostEnvironment = environment;
  43. _dingDing = dingDing;
  44. _azureRedis = azureRedis;
  45. }
  46. [HttpPost("process-local")]
  47. public async Task<IActionResult> ProcessLocal(JsonElement json)
  48. {
  49. List<StudentLessonData> studentLessonDatas = new List<StudentLessonData>();
  50. string? id = json.GetProperty("id").GetString();
  51. if (!string.IsNullOrWhiteSpace(id))
  52. {
  53. string? lessonPath = _configuration.GetValue<string>("LessonPath");
  54. string? path = $"{lessonPath}\\locals\\{id}";
  55. var files = FileHelper.ListAllFiles(path);
  56. // var sampleJson =System.IO. File.ReadAllTextAsync(path);
  57. LessonBase? lessonBase = null;
  58. List<LocalStudent> localStudents = new List<LocalStudent>();
  59. List<TaskData> taskDatas = new List<TaskData>();
  60. List<SmartRatingData> smartRatingDatas = new List<SmartRatingData>();
  61. List<IRSData> irsDatas = new List<IRSData>();
  62. List<CoworkData> coworkDatas = new List<CoworkData>();
  63. List<ExamData> examDatas = new List<ExamData>();
  64. TimeLineData? timeLineData = null;
  65. foreach (var item in files)
  66. {
  67. if (item.Contains("IES\\base.json"))
  68. {
  69. string jsons = await System.IO.File.ReadAllTextAsync(item);
  70. jsons = jsons.Replace("\"Uncall\"", "0").Replace("Uncall", "0");
  71. lessonBase = jsons.ToObject<LessonBase>();
  72. var data = LessonETLService.GetBaseData(lessonBase);
  73. localStudents = data.studentLessonDatas;
  74. }
  75. if (item.Contains("IES\\TimeLine.json"))
  76. {
  77. string jsons = await System.IO.File.ReadAllTextAsync(item);
  78. timeLineData = jsons.ToObject<TimeLineData>();
  79. }
  80. if (item.Contains("IES\\Task.json"))
  81. {
  82. string jsons = await System.IO.File.ReadAllTextAsync(item);
  83. taskDatas = jsons.ToObject<List<TaskData>>();
  84. }
  85. if (item.Contains("IES\\SmartRating.json"))
  86. {
  87. string jsons = await System.IO.File.ReadAllTextAsync(item);
  88. smartRatingDatas = jsons.ToObject<List<SmartRatingData>>();
  89. }
  90. if (item.Contains("IES\\IRS.json"))
  91. {
  92. string jsons = await System.IO.File.ReadAllTextAsync(item);
  93. irsDatas = jsons.ToObject<List<IRSData>>();
  94. }
  95. if (item.Contains("IES\\Cowork.json"))
  96. {
  97. string jsons = await System.IO.File.ReadAllTextAsync(item);
  98. coworkDatas = jsons.ToObject<List<CoworkData>>();
  99. }
  100. try
  101. {
  102. if (item.Contains($"\\{id}\\Exam\\") && item.EndsWith("Exam.json"))
  103. {
  104. string examsFile = item;
  105. if (examsFile.EndsWith("Exam.json"))
  106. {
  107. ExamData? examData = null;
  108. string jsons = await System.IO.File.ReadAllTextAsync(item);
  109. jsons = jsons.Replace("\"publish\": \"0\"", "\"publish\": 0").Replace("\"publish\": \"1\"", "\"publish\": 1");
  110. examData = jsons.ToObject<ExamData>();
  111. if (examData != null && examData.exam.papers.IsNotEmpty())
  112. {
  113. string paperId = examData.exam.papers.First().id;
  114. string paperPath = $"{path}\\ExamPaper\\{paperId}\\index.json";
  115. string jsonp = await System.IO.File.ReadAllTextAsync(paperPath);
  116. LessonPaper lessonPaper = jsonp.ToObject<LessonPaper>();
  117. examData.paper = lessonPaper;
  118. examDatas.Add(examData);
  119. }
  120. }
  121. }
  122. }
  123. catch (Exception ex)
  124. {
  125. _logger.LogError(ex, ex.Message);
  126. }
  127. }
  128. if (lessonBase!=null && timeLineData!=null)
  129. {
  130. studentLessonDatas = localStudents.ToJsonString().ToObject<List<StudentLessonData>>();
  131. studentLessonDatas = LessonETLService.GetBaseInfo(lessonBase!, studentLessonDatas, id);
  132. studentLessonDatas = LessonETLService.GetIRSData(lessonBase, timeLineData, irsDatas, studentLessonDatas, examDatas, id);
  133. studentLessonDatas = LessonETLService.GetCoworkData(lessonBase, timeLineData, coworkDatas, studentLessonDatas, id);
  134. studentLessonDatas = LessonETLService.GetExamData(lessonBase, timeLineData, examDatas, studentLessonDatas, Constant.objectiveTypes, id);
  135. studentLessonDatas = LessonETLService.GetSmartRatingData(lessonBase, timeLineData, smartRatingDatas, studentLessonDatas, id);
  136. studentLessonDatas = LessonETLService.GetTaskData(lessonBase, timeLineData, taskDatas, studentLessonDatas, id);
  137. var pickupData = LessonETLService.GetPickupData(lessonBase, timeLineData, studentLessonDatas, id);
  138. studentLessonDatas= pickupData.studentLessonDatas;
  139. var codeBools= LessonETLService.GetCodeBools(studentLessonDatas);
  140. await System.IO.File.WriteAllTextAsync(Path.Combine(path, $"student-analysis.json"), studentLessonDatas.ToJsonString());
  141. string jsons = await System.IO.File.ReadAllTextAsync($"{lessonPath}\\analysis\\analysis-model.json");
  142. LessonDataAnalysisModel lessonDataAnalysis = jsons.ToObject<LessonDataAnalysisModel>();
  143. var studentLessons = LessonETLService.ProcessStudentDataV2(studentLessonDatas, lessonDataAnalysis,codeBools);
  144. XmlDocument xmlDocument = new XmlDocument();
  145. var runtimePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  146. xmlDocument.Load($"{runtimePath}\\summary.xml");
  147. await LessonETLService.ExportToExcelLocal(studentLessons, $"{path}\\analysis.xlsx", xmlDocument);
  148. }
  149. }
  150. return Ok();
  151. }
  152. /// <summary>
  153. ///
  154. /// </summary>
  155. /// <param name="json"></param>
  156. /// <returns></returns>
  157. [HttpPost("process-fix-history-students")]
  158. public async Task<IActionResult> ProcessFixHistoryStudents(JsonElement json)
  159. {
  160. string? pathAnalysis = $"F:\\lesson-local\\analysis";
  161. try
  162. {
  163. string jsons = await System.IO.File.ReadAllTextAsync($"F:\\lesson-local\\analysis\\analysis-model.json");
  164. var s = JsonSerializer.Deserialize<LessonDataAnalysisModel>(jsons);
  165. LessonDataAnalysisModel lessonDataAnalysis = JsonDocument.Parse(jsons).RootElement.ToObject<LessonDataAnalysisModel>();
  166. var per = LessonETLService.GetPersent(lessonDataAnalysis.irs, 2);
  167. }
  168. catch (Exception ex)
  169. {
  170. Console.WriteLine(ex.ToString());
  171. }
  172. return Ok();
  173. }
  174. /// <summary>
  175. ///
  176. /// </summary>
  177. /// <param name="json"></param>
  178. /// <returns></returns>
  179. [HttpPost("process-history-students")]
  180. public async Task<IActionResult> ProcessHistoryStudents(JsonElement json)
  181. {
  182. string? lessonBasePath = _configuration.GetValue<string>("LessonPath");
  183. string? pathLessons = $"{lessonBasePath}\\lessons";
  184. string? pathAnalysis = $"{lessonBasePath}\\analysis";
  185. string jsons = await System.IO.File.ReadAllTextAsync($"{pathAnalysis}\\analysis-model.json");
  186. LessonDataAnalysisModel lessonDataAnalysis = jsons.ToObject<LessonDataAnalysisModel>();
  187. List<string> filesLessons = FileHelper.ListAllFiles(pathLessons, "-local.json");
  188. var runtimePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  189. XmlDocument xmlDocument = new XmlDocument();
  190. xmlDocument.Load($"{runtimePath}\\summary.xml");
  191. List<School> schools = new List<School>();
  192. // await Parallel.ForEachAsync(filesLessons, async (fileLesson, _) =>
  193. List<string> localIds = new List<string>();
  194. foreach (var file in filesLessons)
  195. {
  196. string lessonId = file.Split("\\").Last().Replace("-local.json", "");
  197. localIds.Add(lessonId);
  198. }
  199. List<LessonRecord> lessonRecords = new List<LessonRecord>();
  200. string recordsPtah = $"{lessonBasePath}\\records\\records.json";
  201. long stime = 0;//2023-09-01 00:00:00
  202. long etime = 0;//2024-11-13 23:59:59
  203. if (System.IO.File.Exists(recordsPtah))
  204. {
  205. string jsonData = await System.IO.File.ReadAllTextAsync(recordsPtah);
  206. lessonRecords= jsonData.ToObject<List<LessonRecord>>();
  207. stime= lessonRecords.Max(x => x.startTime);
  208. etime= lessonRecords.Max(x => x.startTime);
  209. }
  210. if (stime==0)
  211. {
  212. stime = 1693497600000;//2023-09-01 00:00:00
  213. }
  214. if (etime==0)
  215. {
  216. etime = 1731513599000;//2024-11-13 23:59:59
  217. }
  218. var resultSchools = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
  219. .GetList<LessonRecord>($"SELECT value c FROM c where ( c.analysis>=0 or IS_DEFINED(c.analysis) = false ) and c.startTime>{stime} and c.startTime<{etime} and c.expire<=0 and c.status<>404 and c.duration>300 and c.pk='LessonRecord' ");
  220. List<string> ignore = new List<string>() { "PgJump", "PgRcv", "PgAdd" };
  221. int index = 0;
  222. if (resultSchools.list.IsNotEmpty())
  223. {
  224. lessonRecords.AddRange(resultSchools.list);
  225. }
  226. if (lessonRecords.IsNotEmpty())
  227. {
  228. await System.IO.File.WriteAllTextAsync(recordsPtah, lessonRecords.ToJsonString());
  229. List<StudentSemesterRecord> studentSemesterRecords= new List<StudentSemesterRecord>();
  230. List<OverallEducation> overallEducations= new List<OverallEducation>();
  231. List<Student> studentsBase = new List<Student>();
  232. List<LessonLocal>lessonLocals = new List<LessonLocal>();
  233. foreach (var lessonRecord in lessonRecords)
  234. {
  235. var item = await LessonETLService.GetLessonLocal(lessonRecord, localIds, _azureStorage, pathLessons);
  236. lessonLocals.Add(item);
  237. string yearMonthPath = DateTimeOffset.FromUnixTimeMilliseconds(item.lessonRecord.startTime).ToString("yyyyMM");
  238. await System.IO.File.WriteAllTextAsync($"{pathLessons}\\MM{yearMonthPath}\\{item.lessonRecord!.id}-local.json", item.ToJsonString());
  239. index++;
  240. }
  241. string schoolPtah = $"{lessonBasePath}\\schools\\school.json";
  242. if (System.IO.File.Exists(schoolPtah))
  243. {
  244. string jsonData = await System.IO.File.ReadAllTextAsync(schoolPtah);
  245. schools= jsonData.ToObject<List<School>>();
  246. }
  247. var schoolGroup = lessonLocals.Where(x => !string.IsNullOrWhiteSpace(x.lessonRecord?.school)).GroupBy(x => x.lessonRecord?.school).Select(x => new { key = x.Key, list = x.ToList() });
  248. var newschoolIds = schoolGroup.Select(x=>x.key).ExceptBy(schools.Select(x => x.id), x => x);
  249. if (newschoolIds!=null && newschoolIds.Count()>0)
  250. {
  251. string schoolSql = $"select value c from c where c.id in ({string.Join(",", schoolGroup.Select(x => $"'{x.key}'"))})";
  252. var schoolResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<School>(schoolSql, "Base");
  253. if (schoolResults.list.IsNotEmpty())
  254. {
  255. schools.AddRange(schoolResults.list);
  256. }
  257. }
  258. await System.IO.File.WriteAllTextAsync($"{lessonBasePath}\\schools\\school.json", schools.ToJsonString());
  259. foreach (var group in schoolGroup)
  260. {
  261. string students_path = $"{lessonBasePath}\\students\\{group.key}\\students.json";
  262. string records_path = $"{lessonBasePath}\\students\\{group.key}\\records.json";
  263. string overall_path = $"{lessonBasePath}\\students\\{group.key}\\overall.json";
  264. if (!Directory.Exists($"{lessonBasePath}\\students\\{group.key}"))
  265. {
  266. Directory.CreateDirectory($"{lessonBasePath}\\students\\{group.key}");
  267. }
  268. var studentIds = group.list.SelectMany(x => x.studentLessonDatas).Where(x=>!string.IsNullOrWhiteSpace(x.id)).Select(x => x.id).Distinct();
  269. List<Student> schoolStudent = new List<Student>();
  270. if (System.IO.File.Exists(students_path))
  271. {
  272. string jsonData = await System.IO.File.ReadAllTextAsync(students_path);
  273. schoolStudent= jsonData.ToObject<List<Student>>();
  274. studentsBase.AddRange(schoolStudent);
  275. }
  276. var newIds= studentIds.ExceptBy(schoolStudent.Where(x=>x.schoolId.Equals(group.key)).Select(x=>x.id),x=>x);
  277. if (newIds!=null && newIds.Count()>0)
  278. {
  279. string studentSql = $"select value c from c where c.id in ({string.Join(",", newIds.Select(x => $"'{x}'"))})";
  280. var studentResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<Student>(studentSql, $"Base-{group.key}");
  281. if (studentResults.list.IsNotEmpty())
  282. {
  283. schoolStudent.AddRange(studentResults.list);
  284. studentsBase.AddRange(studentResults.list);
  285. }
  286. }
  287. await System.IO.File.WriteAllTextAsync(students_path, schoolStudent.ToJsonString());
  288. List<StudentSemesterRecord> schoolStudentSemesterRecords=new List<StudentSemesterRecord>();
  289. if (System.IO.File.Exists(records_path))
  290. {
  291. string jsonData = await System.IO.File.ReadAllTextAsync(records_path);
  292. schoolStudentSemesterRecords= jsonData.ToObject<List<StudentSemesterRecord>>();
  293. studentSemesterRecords.AddRange(schoolStudentSemesterRecords);
  294. }
  295. var newstuIds = studentIds.ExceptBy(studentSemesterRecords.Where(x => x.school.Equals(group.key)).Select(x => x.stuid), x => x);
  296. if (newstuIds!=null && newstuIds.Count()>0)
  297. {
  298. string studentSemesterRecordSql = $"select value c from c where c.stuid in ({string.Join(",", newstuIds.Distinct().Select(x => $"'{x}'"))}) and c.studyYear>=2023";
  299. var studentSemesterRecordResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<StudentSemesterRecord>(studentSemesterRecordSql, $"StudentSemesterRecord-{group.key}");
  300. if (studentSemesterRecordResults.list.IsNotEmpty())
  301. {
  302. schoolStudentSemesterRecords.AddRange(studentSemesterRecordResults.list);
  303. studentSemesterRecords.AddRange(studentSemesterRecordResults.list);
  304. }
  305. }
  306. await System.IO.File.WriteAllTextAsync(records_path, schoolStudentSemesterRecords.ToJsonString());
  307. List<OverallEducation> schoolOverallEducations = new List<OverallEducation>();
  308. if (System.IO.File.Exists(overall_path))
  309. {
  310. string jsonData = await System.IO.File.ReadAllTextAsync(overall_path);
  311. schoolOverallEducations= jsonData.ToObject<List<OverallEducation>>();
  312. overallEducations.AddRange(schoolOverallEducations);
  313. }
  314. var newstuoIds = studentIds.ExceptBy(schoolOverallEducations.Where(x => x.schoolCode.Equals(group.key)).Select(x => x.studentId), x => x);
  315. if (newstuIds!=null && newstuIds.Count()>0)
  316. {
  317. string overallEducationSql = $"select value c from c where c.studentId in ({string.Join(",", newstuoIds.Select(x => $"'{x}'"))}) and c.year>=2023";
  318. var overallEducationResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<OverallEducation>(overallEducationSql, $"OverallEducation-{group.key}");
  319. if (overallEducationResults.list.IsNotEmpty())
  320. {
  321. schoolOverallEducations.AddRange(overallEducationResults.list);
  322. overallEducations.AddRange(overallEducationResults.list);
  323. }
  324. }
  325. await System.IO.File.WriteAllTextAsync(overall_path, schoolOverallEducations.ToJsonString());
  326. }
  327. //List<(string id,string owner, List<StudentLessonData> studentLessonData)> studentLessonDatas= new List<(string id, string owner, List<StudentLessonData>)>();
  328. ConcurrentQueue<(string id, string owner, List<StudentLessonItem> studentLessons,List<CodeBool> codeBools, List<StudentLessonData> studentLessonData)> lessonItems = new ConcurrentQueue<(string id, string owner, List<StudentLessonItem> studentLessons, List<CodeBool> codeBools, List<StudentLessonData> studentLessonData)>();
  329. int n = 0;
  330. Parallel.ForEach(lessonLocals, (item, con) =>
  331. {
  332. try
  333. {
  334. var studata = LessonETLService.DoStudentLessonDataV2(Constant.objectiveTypes, item, "China", studentSemesterRecords, overallEducations, lessonDataAnalysis, studentsBase, schools);
  335. if (studata.codeBools.FindAll(x => x.value).IsNotEmpty())
  336. {
  337. string owner = item.lessonRecord.scope.Equals("school") ? item.lessonRecord.school : item.lessonRecord.tmdid;
  338. //studentLessonDatas.Add((item.lessonRecord.id, owner, studata.studentLessonDatas));
  339. lessonItems.Append((item.lessonRecord.id, owner, studata.lessonItems, studata.codeBools, studata.studentLessonDatas));
  340. }
  341. }
  342. catch (Exception ex)
  343. {
  344. Console.WriteLine($"{ex.Message},{ex.StackTrace}");
  345. throw new Exception(ex.Message, ex);
  346. }
  347. n++;
  348. });
  349. foreach (var group in schoolGroup)
  350. {
  351. string students_path = $"{lessonBasePath}\\students\\{group.key}\\students.json";
  352. string records_path = $"{lessonBasePath}\\students\\{group.key}\\records.json";
  353. string overall_path = $"{lessonBasePath}\\students\\{group.key}\\overall.json";
  354. if (!Directory.Exists($"{lessonBasePath}\\students\\{group.key}"))
  355. {
  356. Directory.CreateDirectory($"{lessonBasePath}\\students\\{group.key}");
  357. }
  358. var schoolStudent = studentsBase.FindAll(x => x.schoolId.Equals(group.key));
  359. var schoolStudentSemesterRecords= studentSemesterRecords.FindAll(x => x.school.Equals(group.key));
  360. var schoolOverallEducations = overallEducations.FindAll(x => x.schoolCode.Equals(group.key));
  361. await System.IO.File.WriteAllTextAsync(students_path, schoolStudent.ToJsonString());
  362. await System.IO.File.WriteAllTextAsync(records_path, schoolStudentSemesterRecords.ToJsonString());
  363. await System.IO.File.WriteAllTextAsync(overall_path, schoolOverallEducations.ToJsonString());
  364. }
  365. int m = 0;
  366. var grpdata = studentSemesterRecords.GroupBy(x => x.code).Select(x => new { key = x.Key, list = x.ToList() });
  367. foreach (var group in grpdata)
  368. {
  369. var pages = group.list.Page(200);
  370. foreach (var page in pages)
  371. {
  372. List<Task<ItemResponse<StudentSemesterRecord>>> list = new();
  373. foreach (var studentSemester in page)
  374. {
  375. list.Add(_azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(studentSemester, new PartitionKey(studentSemester.code))) ;
  376. m++;
  377. }
  378. await Task.WhenAll(list);
  379. }
  380. }
  381. int k = 0;
  382. var gpover = overallEducations.GroupBy(x => x.code).Select(x => new { key = x.Key, list = x.ToList() });
  383. foreach (var item in gpover)
  384. {
  385. var pages = item.list.Page(200);
  386. foreach (var page in pages)
  387. {
  388. List<Task<ItemResponse<OverallEducation>>> list = new();
  389. foreach (var overallEducation in page)
  390. {
  391. list.Add(_azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(overallEducation, partitionKey: new PartitionKey(overallEducation.code)));
  392. //string key = $"OverallEducation:{overallEducation.schoolCode}:{overallEducation.periodId}:{overallEducation.year}:{overallEducation.semesterId}:{overallEducation?.classId}";
  393. //await _azureRedis.GetRedisClient(8).HashSetAsync(key, overallEducation.studentId, overallEducation.ToJsonString());
  394. //await _azureRedis.GetRedisClient(8).KeyExpireAsync(key, new TimeSpan(180 *24, 0, 0));
  395. }
  396. await Task.WhenAll(list);
  397. }
  398. }
  399. int p = 0;
  400. // 获取类的属性
  401. PropertyInfo[] properties = typeof(StudentLessonItem).GetProperties();
  402. List<string> summaryes= new List<string>();
  403. for (int i = 0; i < properties.Length; i++)
  404. {
  405. string summary = Regex.Replace(LessonETLService.GetPropertySummary(properties[i], xmlDocument), @"\s+", "");
  406. summaryes.Add(summary);
  407. }
  408. await Parallel.ForEachAsync(lessonItems, async (lessonItem, _) => {
  409. await _azureStorage.GetBlobContainerClient(lessonItem.owner).UploadFileByContainer(lessonItem.studentLessonData.ToJsonString(), "records", $"{lessonItem.id}/student-analysis.json");
  410. await LessonETLService.ExportToExcelAzureBlob(lessonItem.studentLessons, _azureStorage, lessonItem.owner, $"{lessonItem.id}/student-analysis.xlsx", xmlDocument, summaryes, properties);
  411. p++;
  412. });
  413. }
  414. return Ok();
  415. }
  416. /// <summary>
  417. /// 课例数据ETL处理过程
  418. /// </summary>
  419. /// <param name="json"></param>
  420. /// <returns></returns>
  421. [HttpPost("process-history")]
  422. public async Task<IActionResult> ProcessHistory(JsonElement json)
  423. {
  424. Stopwatch stopwatch= new Stopwatch();
  425. List<string> localIds = new List<string>();
  426. string? lessonBasePath = _configuration.GetValue<string>("LessonPath");
  427. string? pathLessons = $"{lessonBasePath}\\lessons";
  428. string? pathAnalysis = $"{lessonBasePath}\\analysis";
  429. var filesLessons = FileHelper.ListAllFiles(pathLessons);
  430. foreach (var file in filesLessons)
  431. {
  432. if (file.EndsWith("-local.json"))
  433. {
  434. string lessonId = file.Split("\\").Last().Replace("-local.json", "");
  435. localIds.Add(lessonId);
  436. }
  437. }
  438. bool loadLocal = true;
  439. var filesAnalysis = FileHelper.ListAllFiles(pathAnalysis);
  440. long stime = 1693497600000;//2023-09-01 00:00:00
  441. bool force = false;
  442. if ((json.TryGetProperty("force", out JsonElement _force)&& _force.ValueKind.Equals(JsonValueKind.True)))
  443. {
  444. force= _force.GetBoolean();
  445. }
  446. if (force)
  447. {
  448. List<LessonDataAnalysisMonth> lessonDataAnalysisMonths = new List<LessonDataAnalysisMonth>();
  449. foreach (var file in filesAnalysis)
  450. {
  451. //读取每月的数据
  452. if (file.EndsWith("-m-analysis.json"))
  453. {
  454. string jsons = await System.IO.File.ReadAllTextAsync(file);
  455. LessonDataAnalysisMonth lessonDataAnalysis = jsons.ToObject<LessonDataAnalysisMonth>();
  456. lessonDataAnalysisMonths.Add(lessonDataAnalysis);
  457. }
  458. }
  459. if (lessonDataAnalysisMonths.IsNotEmpty())
  460. {
  461. var maxUpdateTime = lessonDataAnalysisMonths.Max(x => x.updateTime);
  462. if (maxUpdateTime>0)
  463. {
  464. //更新周期是一周
  465. if (DateTimeOffset.Now.ToUnixTimeMilliseconds()- maxUpdateTime>604800000)
  466. {
  467. stime=maxUpdateTime;
  468. loadLocal =true;
  469. }
  470. else
  471. {
  472. stime=maxUpdateTime;
  473. loadLocal=false;
  474. }
  475. }
  476. }
  477. }
  478. // if (loadLocal ||force)
  479. {
  480. List<string> ignore = new List<string>() { "PgJump", "PgRcv", "PgAdd" };
  481. await LessonETLService.FixLocalData(localIds, _azureCosmos, _azureStorage, pathLessons, stime, DateTimeOffset.Now.ToUnixTimeMilliseconds());
  482. List<TechCount> techCounts = new List<TechCount>();
  483. filesLessons = FileHelper.ListAllFiles(pathLessons, "-local.json");
  484. stopwatch.Start();
  485. List<LessonLocal> lessonLocals = new List<LessonLocal>();
  486. Parallel.ForEach(filesLessons, file =>
  487. {
  488. string jsonp = System.IO.File.ReadAllText(file);
  489. var lessonLocal = jsonp.ToObject<LessonLocal>();
  490. lessonLocals.Add(lessonLocal);
  491. });
  492. stopwatch.Stop();
  493. _logger.LogInformation($"Loaded {lessonLocals.Count} lessons in {stopwatch.Elapsed.TotalSeconds} seconds");
  494. await Parallel.ForEachAsync(filesLessons, async (item, _) => {
  495. TechCount techCount= await LessonETLService.GetTeachCount(_azureCosmos, item, pathLessons, ignore, Constant.objectiveTypes, _azureStorage, force);
  496. if (techCount != null) {
  497. techCounts.Add(techCount);
  498. }
  499. });
  500. long newest = lessonLocals.Max(x=>x.lessonRecord.startTime);
  501. await LessonETLService.GenAnalysisData(pathAnalysis, newest, techCounts,_azureStorage);
  502. }
  503. return Ok(new { });
  504. }
  505. }
  506. }