LessonRecordController.cs 32 KB

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