LessonRecordController.cs 31 KB

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