LessonRecordController.cs 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  1. using Azure.Storage.Blobs.Models;
  2. using DocumentFormat.OpenXml.Drawing.Charts;
  3. using DocumentFormat.OpenXml.Spreadsheet;
  4. using HTEX.Lib.ETL.Lesson;
  5. using MathNet.Numerics.Distributions;
  6. using Microsoft.AspNetCore.Mvc;
  7. using Microsoft.Azure.Cosmos;
  8. using Microsoft.Extensions.Logging;
  9. using StackExchange.Redis;
  10. using System.Collections.Concurrent;
  11. using System.Collections.Generic;
  12. using System.Diagnostics;
  13. using System.Globalization;
  14. using System.Reflection;
  15. using System.Text.Json;
  16. using System.Text.RegularExpressions;
  17. using System.Xml;
  18. using TEAMModelOS.SDK;
  19. using TEAMModelOS.SDK.DI;
  20. using TEAMModelOS.SDK.Extension;
  21. using TEAMModelOS.SDK.Helper.Common.FileHelper;
  22. using TEAMModelOS.SDK.Models;
  23. using TEAMModelOS.SDK.Models.Cosmos.BI;
  24. using TEAMModelOS.SDK.Models.Cosmos;
  25. using TEAMModelOS.SDK.Models.Cosmos.OpenEntity;
  26. using static TEAMModelOS.SDK.Models.Service.SystemService;
  27. namespace HTEX.DataETL.Controllers
  28. {
  29. [ApiController]
  30. [Route("lesson-record")]
  31. public class LessonRecordController : ControllerBase
  32. {
  33. private readonly ILogger<LessonRecordController> _logger;
  34. private readonly AzureCosmosFactory _azureCosmos;
  35. private readonly AzureStorageFactory _azureStorage;
  36. private readonly IConfiguration _configuration;
  37. private readonly IWebHostEnvironment _webHostEnvironment;
  38. private readonly DingDing _dingDing;
  39. private readonly AzureRedisFactory _azureRedis;
  40. public LessonRecordController(ILogger<LessonRecordController> logger, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage , IConfiguration configuration, IWebHostEnvironment environment,DingDing dingDing,AzureRedisFactory azureRedis )
  41. {
  42. _logger = logger;
  43. _azureCosmos = azureCosmos;
  44. _azureStorage = azureStorage;
  45. _configuration = configuration;
  46. _webHostEnvironment = environment;
  47. _dingDing = dingDing;
  48. _azureRedis = azureRedis;
  49. }
  50. [HttpPost("schools")]
  51. public async Task<IActionResult> Schools(JsonElement json)
  52. {
  53. List<string> ids = new List<string> { "cdscxx",
  54. "sdsyxq",
  55. "cdsxxx",
  56. "cdssz",
  57. "cdsshx",
  58. "ptszx",
  59. "cdwwsz",
  60. "csdswz",
  61. "cdfczx",
  62. "sdsy",
  63. "qyszgh",
  64. "sdsydq",
  65. "sslzxq",
  66. "cd37z",
  67. "cdqysz",
  68. "cd11z",
  69. "xhlxx",
  70. "cdpxjj",
  71. "xcfxqy",
  72. "csdswx",
  73. "thgjxx",
  74. "cdwwsx",
  75. "cdsjy",
  76. "cdsxwy",
  77. "cdsxzq",
  78. "cdsxmd",
  79. "cdsxcf",
  80. "cdsxqh",
  81. "cdsyxx",
  82. "cdsxx",
  83. "sxgkxx",
  84. "cdqbxx",
  85. "qyszfx",
  86. "cdpxxq",
  87. "cdpxlz",
  88. "cdpx",
  89. "cdkhxx",
  90. "cdhmxx",
  91. "cdjsxx",
  92. "cdhhxx",
  93. "cdhygj",
  94. "hygjqb",
  95. "cdglxx",
  96. "cddpxx",
  97. "cddcg",
  98. "cdctzm",
  99. "cdctxx",
  100. "cdchxx",
  101. "cdctxq",
  102. "sdsyqb",
  103. "sslzsx",
  104. "sslzjs",
  105. "cdjsxc",
  106. "cdjsxb",
  107. "yfsxwy",
  108. "sdyzhy",
  109. "yxmdfs",
  110. "cdcgxc",
  111. "cdcgxa" };
  112. foreach (string id in ids) {
  113. var res = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<Student>("select value c from c ", $"Base-{id}");
  114. if (res.list.IsNotEmpty())
  115. {
  116. var change= res.list.FindAll(x => x.graduate==1);
  117. if (change.IsNotEmpty())
  118. {
  119. foreach (var item in change)
  120. {
  121. item.graduate=0;
  122. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(item, new PartitionKey(item.code));
  123. }
  124. }
  125. }
  126. }
  127. return Ok(new { });
  128. }
  129. [HttpPost("process-lesson")]
  130. public async Task<IActionResult> ProcessLesson(JsonElement json)
  131. {
  132. string scope = "";
  133. string tmdid = "";
  134. string lessonId;
  135. string school = null;
  136. string tbname = Constant.Teacher;
  137. string lcode = string.Empty;
  138. string blobname;
  139. var client = _azureCosmos.GetCosmosClient();
  140. scope = $"private";
  141. tmdid = $"6712127960";
  142. lessonId = $"648770551606808576";
  143. blobname = $"{tmdid}";
  144. lcode = $"LessonRecord";
  145. tbname = "Teacher";
  146. LessonRecord oldlessonRecord = null;
  147. LessonRecord lessonRecord = null;
  148. ResponseMessage response = await client.GetContainer(Constant.TEAMModelOS, tbname).ReadItemStreamAsync(lessonId, new PartitionKey(lcode));
  149. if (response.StatusCode == System.Net.HttpStatusCode.OK)
  150. {
  151. var doc = JsonDocument.Parse(response.Content);
  152. lessonRecord = doc.RootElement.ToObject<LessonRecord>();
  153. oldlessonRecord = doc.RootElement.ToObject<LessonRecord>();
  154. }
  155. else
  156. {
  157. lessonRecord = null;
  158. }
  159. //读取TimeLine.json
  160. List<int> PickupMemberIds = new List<int>();
  161. TimeLineData timeLineData = new TimeLineData();
  162. try
  163. {
  164. BlobDownloadResult timeLineBlobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{lessonId}/IES/TimeLine.json").DownloadContentAsync();
  165. timeLineData = timeLineBlobDownload.Content.ToObjectFromJson<TimeLineData>();
  166. lessonRecord.hitaClientCmpCount = timeLineData.events.Where(z => !string.IsNullOrWhiteSpace(z.WrkCmpSrcType) && z.WrkCmpSrcType.Equals("HitaClientCmp")).Count();
  167. //lessonRecord.collateTaskCount = lessonRecord.hitaClientCmpCount;
  168. List<TimeLineEvent> timeLineEvents = timeLineData.events.FindAll(z => !string.IsNullOrWhiteSpace(z.Event) && z.Event.Equals("PickupResult"));
  169. if (timeLineEvents.IsNotEmpty())
  170. {
  171. foreach (var timeLineEvent in timeLineEvents)
  172. {
  173. var memberIds = timeLineEvent.PickupMemberId.ToObject<List<int>>();
  174. PickupMemberIds.AddRange(memberIds);
  175. }
  176. }
  177. }
  178. catch (Exception ex)
  179. {
  180. if (!ex.Message.Contains("The specified blob does not exist"))
  181. {
  182. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},TimeLine.json转换异常,{ex.Message}{ex.StackTrace},{lessonRecord.id}", GroupNames.成都开发測試群組);
  183. }
  184. }
  185. //读取Task.json
  186. ///Event 过滤类型 : 'WrkSpaceLoad', 'WrkCmp' 文件:Task.json 根据clientWorks 中的seatID 匹配base.json 中的 student
  187. List<TaskData> taskDatas = new List<TaskData>();
  188. try
  189. {
  190. BlobDownloadResult taskBlobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{lessonId}/IES/Task.json").DownloadContentAsync();
  191. taskDatas = taskBlobDownload.Content.ToObjectFromJson<List<TaskData>>();
  192. }
  193. catch (Exception ex)
  194. {
  195. if (!ex.Message.Contains("The specified blob does not exist"))
  196. {
  197. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},Task.json转换异常,{ex.Message}{ex.StackTrace},{lessonRecord.id}", GroupNames.成都开发測試群組);
  198. }
  199. }
  200. //读取互评信息
  201. //Event 过滤类型 'RatingStart'
  202. //smartRateSummary.mutualSummary.mutualType 互评【All(每人多件评分) Two(随机分配互评) Self(自评)】 smartRateSummary.meteor_VoteSummary 投票
  203. //读取IRS.json
  204. List<SmartRatingData> smartRatingDatas = new List<SmartRatingData>();
  205. try
  206. {
  207. BlobDownloadResult smartRatingBlobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{lessonId}/IES/IRS.json").DownloadContentAsync();
  208. smartRatingDatas = smartRatingBlobDownload.Content.ToObjectFromJson<List<SmartRatingData>>();
  209. }
  210. catch (Exception ex)
  211. {
  212. if (!ex.Message.Contains("The specified blob does not exist"))
  213. {
  214. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IRS.json转换异常,{ex.Message}{ex.StackTrace},{lessonRecord.id}", GroupNames.成都开发測試群組);
  215. }
  216. }
  217. //读取互动信息
  218. //Event 过滤类型 'PopQuesLoad', 'ReAtmpAnsStrt', 'BuzrAns','BuzrLoad'
  219. //TimeLine.json 中找到对应类型,根据Pgid 去 IRS.json 中找到对应数据,从clientAnswers 的下标对应 base.json 中的 student 找到对应学生信息 clientAnswers.length > 1 则表示有二次作答
  220. //读取IRS.json
  221. List<IRSData> irsDatas = new List<IRSData>();
  222. try
  223. {
  224. BlobDownloadResult irsBlobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{lessonId}/IES/IRS.json").DownloadContentAsync();
  225. irsDatas = irsBlobDownload.Content.ToObjectFromJson<List<IRSData>>();
  226. }
  227. catch (Exception ex)
  228. {
  229. if (!ex.Message.Contains("The specified blob does not exist"))
  230. {
  231. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IRS.json转换异常,{ex.Message}{ex.StackTrace},{lessonRecord.id}", GroupNames.成都开发測試群組);
  232. }
  233. }
  234. //读取协作信息
  235. ///Event 过滤类型 'CoworkLoad'
  236. //TimeLine.json 中找到对应类型,根据Pgid 去 Cowork.json 中找到对应数据
  237. List<CoworkData> coworkDatas = new List<CoworkData>();
  238. try
  239. {
  240. BlobDownloadResult irsBlobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{lessonId}/IES/Cowork.json").DownloadContentAsync();
  241. coworkDatas = irsBlobDownload.Content.ToObjectFromJson<List<CoworkData>>();
  242. }
  243. catch (Exception ex)
  244. {
  245. if (!ex.Message.Contains("The specified blob does not exist"))
  246. {
  247. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IRS.json转换异常,{ex.Message}{ex.StackTrace},{lessonRecord.id}", GroupNames.成都开发測試群組);
  248. }
  249. }
  250. //苏格拉底文件信息
  251. //Sokrates/SokratesRecords.json
  252. List<TimeLineEvent> sokratesDatas = new List<TimeLineEvent>();
  253. try
  254. {
  255. BlobDownloadResult irsBlobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{lessonId}/Sokrates/SokratesRecords.json").DownloadContentAsync();
  256. sokratesDatas = irsBlobDownload.Content.ToObjectFromJson<List<TimeLineEvent>>();
  257. }
  258. catch (Exception ex)
  259. {
  260. if (!ex.Message.Contains("The specified blob does not exist"))
  261. {
  262. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IRS.json转换异常,{ex.Message}{ex.StackTrace},{lessonRecord.id}", GroupNames.成都开发測試群組);
  263. }
  264. }
  265. //读取base.json信息
  266. //如果有更新 则去读取/{lessonId}/IES/base.json
  267. List<LocalStudent> studentLessonDatas = new List<LocalStudent>();
  268. LessonBase lessonBase = null;
  269. try
  270. {
  271. // await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},课堂id:{lessonId} 收到更新", GroupNames.醍摩豆服務運維群組);
  272. BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{lessonId}/IES/base.json").DownloadContentAsync();
  273. //attendState
  274. string basejson = baseblobDownload.Content.ToString().Replace("\"Uncall\"", "0").Replace("Uncall", "0");
  275. try
  276. {
  277. lessonBase = basejson.ToObject<LessonBase>();
  278. }
  279. catch (Exception ex)
  280. {
  281. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},base.json转换异常,{ex.Message}{ex.StackTrace}{basejson},{lessonRecord.id}", GroupNames.成都开发測試群組);
  282. //lessonBase = baseblobDownload.Content.ToObjectFromJson<LessonBase>();
  283. }
  284. //await _dingDing.SendBotMsg($"课例记录文件base.json:{lessonBase.ToJsonString()}", GroupNames.成都开发測試群組);
  285. if (lessonBase != null && lessonBase.summary != null)
  286. {
  287. var baseData = LessonETLService.GetBaseData(lessonBase!);
  288. studentLessonDatas= baseData.studentLessonDatas;
  289. //lessonRecord.name = lessonBase.summary.activityName;
  290. lessonRecord.attendCount = lessonBase.summary.attendCount;
  291. lessonRecord.clientCount = lessonBase.summary.clientCount;
  292. lessonRecord.attendRate = lessonBase.summary.attendRate;
  293. lessonRecord.groupCount = lessonBase.summary.groupCount;
  294. lessonRecord.collateTaskCount = lessonBase.summary.collateTaskCount;
  295. lessonRecord.hitaClientCmpCount = lessonBase.summary.collateTaskCount + lessonRecord.hitaClientCmpCount;
  296. lessonRecord.collateCount = lessonBase.summary.collateCount;
  297. lessonRecord.pushCount = lessonBase.summary.pushCount;
  298. lessonRecord.totalPoint = lessonBase.summary.totalPoint;
  299. lessonRecord.examQuizCount = lessonBase.summary.examQuizCount;
  300. lessonRecord.interactionCount = lessonBase.summary.interactionCount;
  301. lessonRecord.examPointRate = lessonBase.summary.examPointRate;
  302. lessonRecord.clientInteractionCount = lessonBase.summary.clientInteractionCount;
  303. lessonRecord.clientInteractionAverge = lessonBase.summary.clientInteractionAverge;
  304. lessonRecord.examCount = lessonBase.summary.examCount;
  305. lessonRecord.totalInteractPoint = lessonBase.summary.totalInteractPoint;
  306. lessonRecord.learningCategory = lessonBase.summary.learningCategory;
  307. if (lessonRecord.learningCategory == null)
  308. {
  309. lessonRecord.learningCategory = new LearningCategory();
  310. }
  311. if (lessonRecord.hitaClientCmpCount > 0)
  312. {
  313. lessonRecord.learningCategory.cooperation = 1;
  314. }
  315. if (!string.IsNullOrWhiteSpace(lessonRecord.school))
  316. {
  317. lessonBase.student.ForEach(x =>
  318. {
  319. if (string.IsNullOrWhiteSpace(x.school))
  320. {
  321. x.school = lessonRecord.school;
  322. }
  323. });
  324. }
  325. //计算TP灯
  326. {
  327. int T = -1;
  328. int P = -1;
  329. if (lessonRecord.clientInteractionAverge <= 0)
  330. {
  331. T = 0;
  332. }
  333. else if (lessonRecord.clientInteractionAverge > 0 && lessonRecord.clientInteractionAverge < 2)
  334. // else if (lessonRecord.clientInteractionAverge >= 1 && lessonRecord.clientInteractionAverge <= 2)
  335. {
  336. T = 1;
  337. }
  338. else
  339. {
  340. T = 2;
  341. }
  342. //if (lessonRecord.examCount > 0)
  343. //{
  344. // //有评测次数大于0则P是直接绿灯
  345. // P = 2;
  346. //}
  347. //else {
  348. //}
  349. int a = lessonRecord.hitaClientCmpCount;
  350. int b = lessonRecord.pushCount;
  351. int c = lessonRecord.examCount;
  352. switch (true)
  353. {
  354. case bool when T == 0:
  355. P = 0;
  356. break;
  357. case bool when T == 1 || T == 2:
  358. if (a == 0 && b == 0 && c == 0)
  359. {
  360. P = 0;
  361. }
  362. else if ((a > 0 && b > 0) || (a > 0 && c > 0) || (b > 0 && c > 0))
  363. {
  364. P = 2;
  365. }
  366. else
  367. {
  368. P = 1;
  369. }
  370. break;
  371. }
  372. lessonRecord.tLevel = T;
  373. lessonRecord.pLevel = P;
  374. }
  375. //LessonStudentRecord lessonStudentRecord = new LessonStudentRecord
  376. //{
  377. // clientSummaryList = lessonBase.report.clientSummaryList,
  378. // students = lessonBase.student,
  379. // name = lessonRecord.name,
  380. // school = lessonRecord.school,
  381. // id = lessonRecord.id,
  382. // scope = lessonRecord.scope,
  383. // tmdid = lessonRecord.tmdid,
  384. // code = "LessonStudentRecord",
  385. // pk = "LessonStudentRecord",
  386. // courseId =lessonRecord.courseId,
  387. // groupIds= lessonRecord.groupIds,
  388. // periodId = lessonRecord.periodId,
  389. // subjectId = lessonRecord.subjectId,
  390. //};
  391. //await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS,Constant.Student).UpsertItemAsync<LessonStudentRecord>(lessonStudentRecord, new PartitionKey("LessonStudentRecord"));
  392. }
  393. //有上传 base.josn.
  394. lessonRecord.upload = 1;
  395. // await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},课堂id:{lessonId} 更新完成", GroupNames.醍摩豆服務運維群組);
  396. //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},课堂id:{lessonId} blob刷新完成!", GroupNames.醍摩豆服務運維群組);
  397. List<ExamData> examDatas = new List<ExamData>();
  398. if (lessonBase!=null && lessonBase.student!=null)
  399. {
  400. string owner = lessonRecord.scope.Equals("school") ? lessonRecord.school : lessonRecord.tmdid;
  401. examDatas = await LessonETLService.GetExamInfo(lessonRecord, timeLineData, _azureStorage, owner);
  402. sokratesDatas= sokratesDatas.IsNotEmpty() ? sokratesDatas : timeLineData!=null ? timeLineData.events : new List<TimeLineEvent>();
  403. }
  404. LessonLocal lessonLocal = new LessonLocal()
  405. {
  406. lessonBase=lessonBase,
  407. timeLineData= timeLineData,
  408. lessonRecord= lessonRecord,
  409. taskDatas= taskDatas,
  410. smartRatingDatas= smartRatingDatas,
  411. irsDatas= irsDatas,
  412. coworkDatas= coworkDatas,
  413. examDatas=examDatas,
  414. sokratesDatas= sokratesDatas,
  415. studentLessonDatas=studentLessonDatas
  416. };
  417. try
  418. {
  419. if (lessonRecord.duration>0)
  420. {
  421. var location = "China";
  422. var studatas = LessonETLService.GenStudentLessonData(lessonLocal, Constant.objectiveTypes);
  423. string owner = lessonRecord.scope.Equals("school") ? lessonRecord.school : lessonRecord.tmdid;
  424. if (location.Equals("China", StringComparison.OrdinalIgnoreCase))
  425. {
  426. List<School> schools = new List<School>();
  427. List<StudentSemesterRecord> studentSemesterRecords = new List<StudentSemesterRecord>();
  428. List<OverallEducation> overallEducations = new List<OverallEducation>();
  429. List<Student> studentsBase = new List<Student>();
  430. List<StudentSemesterRecord> students = new List<StudentSemesterRecord>();
  431. LessonDataAnalysisModel lessonDataAnalysis = null;
  432. bool exists = await _azureStorage.GetBlobContainerClient("0-public").GetBlobClient($"/lesson/analysis/analysis-model.json").ExistsAsync();
  433. if (exists)
  434. {
  435. BlobDownloadResult blobDownload = await _azureStorage.GetBlobContainerClient("0-public").GetBlobClient($"/lesson/analysis/analysis-model.json").DownloadContentAsync();
  436. lessonDataAnalysis = blobDownload.Content.ToObjectFromJson<LessonDataAnalysisModel>();
  437. string studentSql = $"select value c from c where c.id in ({string.Join(",", lessonLocal.studentLessonDatas.Select(x => $"'{x.id}'"))})";
  438. var studentResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<Student>(studentSql, $"Base-{school}");
  439. if (studentResults.list.IsNotEmpty())
  440. {
  441. studentsBase.AddRange(studentResults.list);
  442. }
  443. School schoolBase = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(school, new PartitionKey("Base"));
  444. schools.Add(schoolBase);
  445. string? periodId = !string.IsNullOrWhiteSpace(lessonLocal.lessonRecord.periodId) ? lessonLocal.lessonRecord.periodId : schoolBase.period.FirstOrDefault()?.id;
  446. var period = schoolBase.period.Find(x => x.id.Equals(periodId));
  447. var semester = SchoolService.GetSemester(period, lessonLocal.lessonRecord.startTime);
  448. string code = $"StudentSemesterRecord-{schoolBase.id}";
  449. string studentSemesterRecordSql = $"select value c from c where c.stuid in ({string.Join(",", lessonLocal.studentLessonDatas.Select(x => $"'{x.id}'"))}) and c.semesterId='{semester.currSemester.id}' and c.studyYear={semester.studyYear}";
  450. var studentSemesterRecordResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<StudentSemesterRecord>(studentSemesterRecordSql, code);
  451. if (studentSemesterRecordResults.list.IsNotEmpty())
  452. {
  453. studentSemesterRecords.AddRange(studentSemesterRecordResults.list);
  454. }
  455. string overallEducationSql = $"select value c from c where c.studentId in ({string.Join(",", lessonLocal.studentLessonDatas.Select(x => $"'{x.id}'"))}) and c.semesterId='{semester.currSemester.id}' and c.year={semester.studyYear}";
  456. var overallEducationResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<OverallEducation>(overallEducationSql, $"OverallEducation-{schoolBase.id}");
  457. if (overallEducationResults.list.IsNotEmpty())
  458. {
  459. overallEducations.AddRange(overallEducationResults.list);
  460. }
  461. var studata = LessonETLService.DoStudentLessonDataV2(Constant.objectiveTypes, lessonLocal, location, studentSemesterRecords, overallEducations, lessonDataAnalysis, studentsBase, schools);
  462. await Parallel.ForEachAsync(studentSemesterRecords, async (studentSemester, cancellationToken) =>
  463. {
  464. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(studentSemester, new PartitionKey(studentSemester.code));
  465. });
  466. await Parallel.ForEachAsync(overallEducations, async (overallEducation, cancellationToken) =>
  467. {
  468. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(overallEducation, partitionKey: new PartitionKey(overallEducation.code));
  469. string key = $"OverallEducation:{overallEducation.schoolCode}:{overallEducation.periodId}:{overallEducation.year}:{overallEducation.semesterId}:{overallEducation?.classId}";
  470. await _azureRedis.GetRedisClient(8).HashSetAsync(key, overallEducation.studentId, overallEducation.ToJsonString());
  471. await _azureRedis.GetRedisClient(8).KeyExpireAsync(key, new TimeSpan(180 *24, 0, 0));
  472. });
  473. await _azureStorage.GetBlobContainerClient(owner).UploadFileByContainer(studata.studentLessonDatas.ToJsonString(), "records", $"{lessonRecord.id}/student-analysis.json");
  474. XmlDocument xmlDocument = new XmlDocument();
  475. var runtimePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  476. xmlDocument.Load($"{runtimePath}\\summary.xml");
  477. PropertyInfo[] properties = typeof(StudentLessonItem).GetProperties();
  478. List<string> summaryes = new List<string>();
  479. for (int i = 0; i < properties.Length; i++)
  480. {
  481. string summary = Regex.Replace(LessonETLService.GetPropertySummary(properties[i], xmlDocument), @"\s+", "");
  482. summaryes.Add(summary);
  483. }
  484. await LessonETLService.ExportToExcelAzureBlob(studata.lessonItems, _azureStorage, owner, $"{lessonRecord.id}/student-analysis.xlsx", xmlDocument, summaryes, properties);
  485. }
  486. }
  487. else
  488. {
  489. await _azureStorage.GetBlobContainerClient(owner).UploadFileByContainer(studatas.studentLessonDatas.ToJsonString(), "records", $"{lessonRecord.id}/student-analysis.json");
  490. }
  491. // 使用当前文化设置的日历
  492. CultureInfo cultureInfo = CultureInfo.CurrentCulture;
  493. Calendar calendar = cultureInfo.Calendar;
  494. //表示如果一年的第一个星期至少有4天在同一年,则该星期被视为第一周,DayOfWeek.Monday和DayOfWeek.Sunday分别表示一周的第一天是星期一或星期日。
  495. var week = calendar.GetWeekOfYear(DateTime.Now, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
  496. string key = $"LessonWeekly:{lessonRecord.scope}:{DateTime.Now.Year}-{week}";
  497. _azureRedis.GetRedisClient(8).HashSet(key, $"{lessonRecord.tmdid}:{lessonRecord.id}",
  498. new LessonWeek
  499. {
  500. week=week,
  501. id = lessonRecord.id,
  502. cid=lessonRecord.courseId,
  503. sid= lessonRecord.subjectId,
  504. school=lessonRecord.school,
  505. gid= lessonRecord.groupIds?.FirstOrDefault(),
  506. //pid= lessonRecord.periodId,
  507. scope= lessonRecord.scope,
  508. }.ToJsonString()
  509. );
  510. await _azureRedis.GetRedisClient(8).KeyExpireAsync(key, TimeSpan.FromDays(10));
  511. }
  512. }
  513. catch (Exception ex)
  514. {
  515. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}处理学生课中数据发生异常,{lessonId}\n{ex.Message}\n{ex.StackTrace}\n\n{lessonRecord.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
  516. }
  517. }
  518. catch (Exception ex) { }
  519. return Ok();
  520. }
  521. [HttpPost("process-local")]
  522. public async Task<IActionResult> ProcessLocal(JsonElement json)
  523. {
  524. List<StudentLessonData> studentLessonDatas = new List<StudentLessonData>();
  525. string? id = json.GetProperty("id").GetString();
  526. if (!string.IsNullOrWhiteSpace(id))
  527. {
  528. string? lessonPath = _configuration.GetValue<string>("LessonPath");
  529. string? path = $"{lessonPath}\\locals\\{id}";
  530. var files = FileHelper.ListAllFiles(path);
  531. // var sampleJson =System.IO. File.ReadAllTextAsync(path);
  532. LessonBase? lessonBase = null;
  533. List<LocalStudent> localStudents = new List<LocalStudent>();
  534. List<TaskData> taskDatas = new List<TaskData>();
  535. List<SmartRatingData> smartRatingDatas = new List<SmartRatingData>();
  536. List<IRSData> irsDatas = new List<IRSData>();
  537. List<CoworkData> coworkDatas = new List<CoworkData>();
  538. List<ExamData> examDatas = new List<ExamData>();
  539. TimeLineData? timeLineData = null;
  540. foreach (var item in files)
  541. {
  542. if (item.Contains("IES\\base.json"))
  543. {
  544. string jsons = await System.IO.File.ReadAllTextAsync(item);
  545. jsons = jsons.Replace("\"Uncall\"", "0").Replace("Uncall", "0");
  546. lessonBase = jsons.ToObject<LessonBase>();
  547. var data = LessonETLService.GetBaseData(lessonBase);
  548. localStudents = data.studentLessonDatas;
  549. }
  550. if (item.Contains("IES\\TimeLine.json"))
  551. {
  552. string jsons = await System.IO.File.ReadAllTextAsync(item);
  553. timeLineData = jsons.ToObject<TimeLineData>();
  554. }
  555. if (item.Contains("IES\\Task.json"))
  556. {
  557. string jsons = await System.IO.File.ReadAllTextAsync(item);
  558. taskDatas = jsons.ToObject<List<TaskData>>();
  559. }
  560. if (item.Contains("IES\\SmartRating.json"))
  561. {
  562. string jsons = await System.IO.File.ReadAllTextAsync(item);
  563. smartRatingDatas = jsons.ToObject<List<SmartRatingData>>();
  564. }
  565. if (item.Contains("IES\\IRS.json"))
  566. {
  567. string jsons = await System.IO.File.ReadAllTextAsync(item);
  568. irsDatas = jsons.ToObject<List<IRSData>>();
  569. }
  570. if (item.Contains("IES\\Cowork.json"))
  571. {
  572. string jsons = await System.IO.File.ReadAllTextAsync(item);
  573. coworkDatas = jsons.ToObject<List<CoworkData>>();
  574. }
  575. try
  576. {
  577. if (item.Contains($"\\{id}\\Exam\\") && item.EndsWith("Exam.json"))
  578. {
  579. string examsFile = item;
  580. if (examsFile.EndsWith("Exam.json"))
  581. {
  582. ExamData? examData = null;
  583. string jsons = await System.IO.File.ReadAllTextAsync(item);
  584. jsons = jsons.Replace("\"publish\": \"0\"", "\"publish\": 0").Replace("\"publish\": \"1\"", "\"publish\": 1");
  585. examData = jsons.ToObject<ExamData>();
  586. if (examData != null && examData.exam.papers.IsNotEmpty())
  587. {
  588. string paperId = examData.exam.papers.First().id;
  589. string paperPath = $"{path}\\ExamPaper\\{paperId}\\index.json";
  590. string jsonp = await System.IO.File.ReadAllTextAsync(paperPath);
  591. LessonPaper lessonPaper = jsonp.ToObject<LessonPaper>();
  592. examData.paper = lessonPaper;
  593. examDatas.Add(examData);
  594. }
  595. }
  596. }
  597. }
  598. catch (Exception ex)
  599. {
  600. _logger.LogError(ex, ex.Message);
  601. }
  602. }
  603. if (lessonBase!=null && timeLineData!=null)
  604. {
  605. studentLessonDatas = localStudents.ToJsonString().ToObject<List<StudentLessonData>>();
  606. studentLessonDatas = LessonETLService.GetBaseInfo(lessonBase!, studentLessonDatas, id);
  607. studentLessonDatas = LessonETLService.GetIRSData(lessonBase, timeLineData, irsDatas, studentLessonDatas, examDatas, id);
  608. studentLessonDatas = LessonETLService.GetCoworkData(lessonBase, timeLineData, coworkDatas, studentLessonDatas, id);
  609. studentLessonDatas = LessonETLService.GetExamData(lessonBase, timeLineData, examDatas, studentLessonDatas, Constant.objectiveTypes, id);
  610. studentLessonDatas = LessonETLService.GetSmartRatingData(lessonBase, timeLineData, smartRatingDatas, studentLessonDatas, id);
  611. studentLessonDatas = LessonETLService.GetTaskData(lessonBase, timeLineData, taskDatas, studentLessonDatas, id);
  612. var pickupData = LessonETLService.GetPickupData(lessonBase, timeLineData, studentLessonDatas, id);
  613. studentLessonDatas= pickupData.studentLessonDatas;
  614. var codeBools= LessonETLService.GetCodeBools(studentLessonDatas);
  615. await System.IO.File.WriteAllTextAsync(Path.Combine(path, $"student-analysis.json"), studentLessonDatas.ToJsonString());
  616. string jsons = await System.IO.File.ReadAllTextAsync($"{lessonPath}\\analysis\\analysis-model.json");
  617. LessonDataAnalysisModel lessonDataAnalysis = jsons.ToObject<LessonDataAnalysisModel>();
  618. var studentLessons = LessonETLService.ProcessStudentDataV2(studentLessonDatas, lessonDataAnalysis,codeBools);
  619. XmlDocument xmlDocument = new XmlDocument();
  620. var runtimePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  621. xmlDocument.Load($"{runtimePath}\\summary.xml");
  622. await LessonETLService.ExportToExcelLocal(studentLessons, $"{path}\\analysis.xlsx", xmlDocument);
  623. }
  624. }
  625. return Ok();
  626. }
  627. /// <summary>
  628. ///
  629. /// </summary>
  630. /// <param name="json"></param>
  631. /// <returns></returns>
  632. [HttpPost("process-history-students")]
  633. public async Task<IActionResult> ProcessHistoryStudents(JsonElement json)
  634. {
  635. string? lessonBasePath = _configuration.GetValue<string>("LessonPath");
  636. string? pathLessons = $"{lessonBasePath}\\lessons";
  637. string? pathAnalysis = $"{lessonBasePath}\\analysis";
  638. string jsons = await System.IO.File.ReadAllTextAsync($"{pathAnalysis}\\analysis-model.json");
  639. LessonDataAnalysisModel lessonDataAnalysis = jsons.ToObject<LessonDataAnalysisModel>();
  640. List<string> filesLessons = FileHelper.ListAllFiles(pathLessons, "-local.json");
  641. List<string> filesStudata = FileHelper.ListAllFiles(pathLessons, "-sdata.json");
  642. var runtimePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  643. XmlDocument xmlDocument = new XmlDocument();
  644. xmlDocument.Load($"{runtimePath}\\summary.xml");
  645. List<School> schools = new List<School>();
  646. // await Parallel.ForEachAsync(filesLessons, async (fileLesson, _) =>
  647. List<string> localIds = new List<string>();
  648. foreach (var file in filesLessons)
  649. {
  650. string lessonId = file.Split("\\").Last().Replace("-local.json", "");
  651. localIds.Add(lessonId);
  652. }
  653. List<LessonLocal> lessonLocals = new List<LessonLocal>();
  654. List<LessonRecord> lessonRecords = new List<LessonRecord>();
  655. string recordsPtah = $"{lessonBasePath}\\records\\records.json";
  656. long stime = 0;//2023-09-01 00:00:00
  657. long etime = 0;//2024-11-13 23:59:59
  658. //if (System.IO.File.Exists(recordsPtah))
  659. //{
  660. // string jsonData = await System.IO.File.ReadAllTextAsync(recordsPtah);
  661. // lessonRecords= jsonData.ToObject<List<LessonRecord>>();
  662. // stime= lessonRecords.Max(x => x.startTime);
  663. // etime= lessonRecords.Max(x => x.startTime);
  664. //}
  665. if (stime==0)
  666. {
  667. stime = 1693497600000;//2023-09-01 00:00:00
  668. }
  669. if (etime==0)
  670. {
  671. etime = 1731513599000;//2024-11-13 23:59:59
  672. }
  673. List<LessonLocal> locals= await LessonETLService.FixLocalData(localIds, _azureCosmos, _azureStorage, pathLessons, stime, etime);
  674. if (locals.IsNotEmpty())
  675. {
  676. lessonLocals.AddRange(locals);
  677. }
  678. int u = 0;
  679. Parallel.ForEach(filesLessons, file =>
  680. {
  681. string jsonp = System.IO.File.ReadAllText(file);
  682. var lessonLocal = jsonp.ToObject<LessonLocal>();
  683. if (lessonLocal.lessonBase!=null && lessonLocal.lessonBase.student.IsNotEmpty())
  684. {
  685. lessonLocals.Add(lessonLocal);
  686. }
  687. else
  688. {
  689. System.IO.File.Delete(file);
  690. System.IO.File.Delete(file.Replace("-local.json", "-count.json"));
  691. u++;
  692. }
  693. });
  694. List<string> ignore = new List<string>() { "PgJump", "PgRcv", "PgAdd" };
  695. if (lessonLocals.IsNotEmpty())
  696. {
  697. lessonRecords=lessonLocals.Where(x => x.lessonRecord.scope.Equals("school")).Select(x =>x.lessonRecord).ToList();
  698. }
  699. if (lessonRecords.IsNotEmpty())
  700. {
  701. await System.IO.File.WriteAllTextAsync(recordsPtah, lessonRecords.ToJsonString());
  702. List<StudentSemesterRecord> studentSemesterRecords= new List<StudentSemesterRecord>();
  703. List<OverallEducation> overallEducations= new List<OverallEducation>();
  704. List<Student> studentsBase = new List<Student>();
  705. string schoolPtah = $"{lessonBasePath}\\schools\\school.json";
  706. if (System.IO.File.Exists(schoolPtah))
  707. {
  708. string jsonData = await System.IO.File.ReadAllTextAsync(schoolPtah);
  709. schools= jsonData.ToObject<List<School>>();
  710. }
  711. var schoolGroup = lessonLocals.Where(x => !string.IsNullOrWhiteSpace(x.lessonRecord?.school)).GroupBy(x => x.lessonRecord?.school).Select(x => new { key = x.Key, list = x.ToList() });
  712. var newschoolIds = schoolGroup.Select(x=>x.key).ExceptBy(schools.Select(x => x.id), x => x);
  713. if (newschoolIds!=null && newschoolIds.Count()>0)
  714. {
  715. string schoolSql = $"select value c from c where c.id in ({string.Join(",", schoolGroup.Select(x => $"'{x.key}'"))})";
  716. var schoolResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<School>(schoolSql, "Base");
  717. if (schoolResults.list.IsNotEmpty())
  718. {
  719. schools.AddRange(schoolResults.list);
  720. }
  721. }
  722. await System.IO.File.WriteAllTextAsync($"{lessonBasePath}\\schools\\school.json", schools.ToJsonString());
  723. foreach (var group in schoolGroup)
  724. {
  725. string students_path = $"{lessonBasePath}\\students\\{group.key}\\students.json";
  726. string records_path = $"{lessonBasePath}\\students\\{group.key}\\records.json";
  727. string overall_path = $"{lessonBasePath}\\students\\{group.key}\\overall.json";
  728. if (!Directory.Exists($"{lessonBasePath}\\students\\{group.key}"))
  729. {
  730. Directory.CreateDirectory($"{lessonBasePath}\\students\\{group.key}");
  731. }
  732. var studentIds = group.list.SelectMany(x => x.studentLessonDatas).Where(x=>!string.IsNullOrWhiteSpace(x.id)).Select(x => x.id).Distinct();
  733. List<Student> schoolStudent = new List<Student>();
  734. if (System.IO.File.Exists(students_path))
  735. {
  736. string jsonData = await System.IO.File.ReadAllTextAsync(students_path);
  737. schoolStudent= jsonData.ToObject<List<Student>>();
  738. studentsBase.AddRange(schoolStudent);
  739. }
  740. var newIds= studentIds.ExceptBy(schoolStudent.Where(x=>x.schoolId.Equals(group.key)).Select(x=>x.id),x=>x);
  741. if (newIds!=null && newIds.Count()>0)
  742. {
  743. string studentSql = $"select value c from c where c.id in ({string.Join(",", newIds.Select(x => $"'{x}'"))})";
  744. var studentResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<Student>(studentSql, $"Base-{group.key}");
  745. if (studentResults.list.IsNotEmpty())
  746. {
  747. schoolStudent.AddRange(studentResults.list);
  748. studentsBase.AddRange(studentResults.list);
  749. }
  750. }
  751. await System.IO.File.WriteAllTextAsync(students_path, schoolStudent.ToJsonString());
  752. List<StudentSemesterRecord> schoolStudentSemesterRecords=new List<StudentSemesterRecord>();
  753. if (System.IO.File.Exists(records_path))
  754. {
  755. string jsonData = await System.IO.File.ReadAllTextAsync(records_path);
  756. schoolStudentSemesterRecords= jsonData.ToObject<List<StudentSemesterRecord>>();
  757. studentSemesterRecords.AddRange(schoolStudentSemesterRecords);
  758. }
  759. var newstuIds = studentIds.ExceptBy(studentSemesterRecords.Where(x => x.school.Equals(group.key)).Select(x => x.stuid), x => x);
  760. if (newstuIds!=null && newstuIds.Count()>0)
  761. {
  762. string studentSemesterRecordSql = $"select value c from c where c.stuid in ({string.Join(",", newstuIds.Distinct().Select(x => $"'{x}'"))}) and c.studyYear>=2023";
  763. var studentSemesterRecordResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<StudentSemesterRecord>(studentSemesterRecordSql, $"StudentSemesterRecord-{group.key}");
  764. if (studentSemesterRecordResults.list.IsNotEmpty())
  765. {
  766. schoolStudentSemesterRecords.AddRange(studentSemesterRecordResults.list);
  767. studentSemesterRecords.AddRange(studentSemesterRecordResults.list);
  768. }
  769. }
  770. await System.IO.File.WriteAllTextAsync(records_path, schoolStudentSemesterRecords.ToJsonString());
  771. List<OverallEducation> schoolOverallEducations = new List<OverallEducation>();
  772. if (System.IO.File.Exists(overall_path))
  773. {
  774. string jsonData = await System.IO.File.ReadAllTextAsync(overall_path);
  775. schoolOverallEducations= jsonData.ToObject<List<OverallEducation>>();
  776. overallEducations.AddRange(schoolOverallEducations);
  777. }
  778. var newstuoIds = studentIds.ExceptBy(schoolOverallEducations.Where(x => x.schoolCode.Equals(group.key)).Select(x => x.studentId), x => x);
  779. if (newstuIds!=null && newstuIds.Count()>0)
  780. {
  781. string overallEducationSql = $"select value c from c where c.studentId in ({string.Join(",", newstuoIds.Select(x => $"'{x}'"))}) and c.year>=2023";
  782. var overallEducationResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<OverallEducation>(overallEducationSql, $"OverallEducation-{group.key}");
  783. if (overallEducationResults.list.IsNotEmpty())
  784. {
  785. schoolOverallEducations.AddRange(overallEducationResults.list);
  786. overallEducations.AddRange(overallEducationResults.list);
  787. }
  788. }
  789. await System.IO.File.WriteAllTextAsync(overall_path, schoolOverallEducations.ToJsonString());
  790. }
  791. //List<(string id,string owner, List<StudentLessonData> studentLessonData)> studentLessonDatas= new List<(string id, string owner, List<StudentLessonData>)>();
  792. ConcurrentQueue<LessonStudentResult> lessonItems = new ConcurrentQueue<LessonStudentResult>();
  793. int v = 0;
  794. Parallel.ForEach(filesStudata, file =>
  795. {
  796. string jsonp = System.IO.File.ReadAllText(file);
  797. var studentResult = jsonp.ToObject<LessonStudentResult>();
  798. lessonItems.Enqueue(studentResult);
  799. v++;
  800. });
  801. int n = 0;
  802. lessonLocals= lessonLocals.ExceptBy(lessonItems.Select(x => x.id), y => y.lessonRecord.id).ToList();
  803. Parallel.ForEach(lessonLocals, (item, con) =>
  804. {
  805. try
  806. {
  807. var studata = LessonETLService.DoStudentLessonDataV2(Constant.objectiveTypes, item, "China", studentSemesterRecords, overallEducations, lessonDataAnalysis, studentsBase, schools);
  808. if (studata.codeBools.FindAll(x => x.value).IsNotEmpty())
  809. {
  810. string owner = item.lessonRecord.scope.Equals("school") ? item.lessonRecord.school : item.lessonRecord.tmdid;
  811. //studentLessonDatas.Add((item.lessonRecord.id, owner, studata.studentLessonDatas));
  812. LessonStudentResult result = new LessonStudentResult { id= item.lessonRecord.id, owner= owner, studentLessons= studata.lessonItems, codeBools= studata.codeBools, lessonDatas= studata.studentLessonDatas };
  813. string yearMonthPath = DateTimeOffset.FromUnixTimeMilliseconds(item.lessonRecord.startTime).ToString("yyyyMM");
  814. System.IO.File.WriteAllText($"{pathLessons}\\MM{yearMonthPath}\\{item.lessonRecord!.id}-sdata.json", item.ToJsonString());
  815. lessonItems.Enqueue(result);
  816. }
  817. }
  818. catch (Exception ex)
  819. {
  820. Console.WriteLine($"{ex.Message},{ex.StackTrace}");
  821. throw new Exception(ex.Message, ex);
  822. }
  823. n++;
  824. });
  825. foreach (var group in schoolGroup)
  826. {
  827. string students_path = $"{lessonBasePath}\\students\\{group.key}\\students.json";
  828. string records_path = $"{lessonBasePath}\\students\\{group.key}\\records.json";
  829. string overall_path = $"{lessonBasePath}\\students\\{group.key}\\overall.json";
  830. if (!Directory.Exists($"{lessonBasePath}\\students\\{group.key}"))
  831. {
  832. Directory.CreateDirectory($"{lessonBasePath}\\students\\{group.key}");
  833. }
  834. var schoolStudent = studentsBase.FindAll(x => x.schoolId.Equals(group.key));
  835. var schoolStudentSemesterRecords= studentSemesterRecords.FindAll(x => x.school.Equals(group.key));
  836. var schoolOverallEducations = overallEducations.FindAll(x => x.schoolCode.Equals(group.key));
  837. await System.IO.File.WriteAllTextAsync(students_path, schoolStudent.ToJsonString());
  838. await System.IO.File.WriteAllTextAsync(records_path, schoolStudentSemesterRecords.ToJsonString());
  839. await System.IO.File.WriteAllTextAsync(overall_path, schoolOverallEducations.ToJsonString());
  840. }
  841. int m = 0;
  842. var grpdata = studentSemesterRecords.GroupBy(x => x.code).Select(x => new { key = x.Key, list = x.ToList() });
  843. foreach (var group in grpdata)
  844. {
  845. var pages = group.list.Page(100);
  846. foreach (var page in pages)
  847. {
  848. List<Task<ItemResponse<StudentSemesterRecord>>> list = new();
  849. foreach (var studentSemester in page)
  850. {
  851. list.Add(_azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(studentSemester, new PartitionKey(studentSemester.code))) ;
  852. m++;
  853. }
  854. await Task.WhenAll(list);
  855. }
  856. }
  857. int k = 0;
  858. var gpover = overallEducations.GroupBy(x => x.code).Select(x => new { key = x.Key, list = x.ToList() });
  859. foreach (var item in gpover)
  860. {
  861. var pages = item.list.Page(100);
  862. foreach (var page in pages)
  863. {
  864. List<Task<ItemResponse<OverallEducation>>> list = new();
  865. foreach (var overallEducation in page)
  866. {
  867. list.Add(_azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(overallEducation, partitionKey: new PartitionKey(overallEducation.code)));
  868. //string key = $"OverallEducation:{overallEducation.schoolCode}:{overallEducation.periodId}:{overallEducation.year}:{overallEducation.semesterId}:{overallEducation?.classId}";
  869. //await _azureRedis.GetRedisClient(8).HashSetAsync(key, overallEducation.studentId, overallEducation.ToJsonString());
  870. //await _azureRedis.GetRedisClient(8).KeyExpireAsync(key, new TimeSpan(180 *24, 0, 0));
  871. }
  872. await Task.WhenAll(list);
  873. }
  874. }
  875. int p = 0;
  876. // 获取类的属性
  877. PropertyInfo[] properties = typeof(StudentLessonItem).GetProperties();
  878. List<string> summaryes= new List<string>();
  879. for (int i = 0; i < properties.Length; i++)
  880. {
  881. string summary = Regex.Replace(LessonETLService.GetPropertySummary(properties[i], xmlDocument), @"\s+", "");
  882. summaryes.Add(summary);
  883. }
  884. await Parallel.ForEachAsync(lessonItems, async (lessonItem, _) => {
  885. await _azureStorage.GetBlobContainerClient(lessonItem.owner).UploadFileByContainer(lessonItem.lessonDatas.ToJsonString(), "records", $"{lessonItem.id}/student-analysis.json");
  886. await LessonETLService.ExportToExcelAzureBlob(lessonItem.studentLessons, _azureStorage, lessonItem.owner, $"{lessonItem.id}/student-analysis.xlsx", xmlDocument, summaryes, properties);
  887. p++;
  888. });
  889. return Ok(new { p, m, k,n,u});
  890. }
  891. return Ok(new {});
  892. }
  893. /// <summary>
  894. /// 课例数据ETL处理过程
  895. /// </summary>
  896. /// <param name="json"></param>
  897. /// <returns></returns>
  898. [HttpPost("process-history")]
  899. public async Task<IActionResult> ProcessHistory(JsonElement json)
  900. {
  901. Stopwatch stopwatch= new Stopwatch();
  902. List<string> localIds = new List<string>();
  903. string? lessonBasePath = _configuration.GetValue<string>("LessonPath");
  904. string? pathLessons = $"{lessonBasePath}\\lessons";
  905. string? pathAnalysis = $"{lessonBasePath}\\analysis";
  906. var filesLessons = FileHelper.ListAllFiles(pathLessons);
  907. foreach (var file in filesLessons)
  908. {
  909. if (file.EndsWith("-local.json"))
  910. {
  911. string lessonId = file.Split("\\").Last().Replace("-local.json", "");
  912. localIds.Add(lessonId);
  913. }
  914. }
  915. bool loadLocal = true;
  916. var filesAnalysis = FileHelper.ListAllFiles(pathAnalysis);
  917. long stime = 1693497600000;//2023-09-01 00:00:00
  918. bool force = false;
  919. if ((json.TryGetProperty("force", out JsonElement _force)&& _force.ValueKind.Equals(JsonValueKind.True)))
  920. {
  921. force= _force.GetBoolean();
  922. }
  923. if (force)
  924. {
  925. List<LessonDataAnalysisMonth> lessonDataAnalysisMonths = new List<LessonDataAnalysisMonth>();
  926. foreach (var file in filesAnalysis)
  927. {
  928. //读取每月的数据
  929. if (file.EndsWith("-m-analysis.json"))
  930. {
  931. string jsons = await System.IO.File.ReadAllTextAsync(file);
  932. LessonDataAnalysisMonth lessonDataAnalysis = jsons.ToObject<LessonDataAnalysisMonth>();
  933. lessonDataAnalysisMonths.Add(lessonDataAnalysis);
  934. }
  935. }
  936. if (lessonDataAnalysisMonths.IsNotEmpty())
  937. {
  938. var maxUpdateTime = lessonDataAnalysisMonths.Max(x => x.updateTime);
  939. if (maxUpdateTime>0)
  940. {
  941. //更新周期是一周
  942. if (DateTimeOffset.Now.ToUnixTimeMilliseconds()- maxUpdateTime>604800000)
  943. {
  944. stime=maxUpdateTime;
  945. loadLocal =true;
  946. }
  947. else
  948. {
  949. stime=maxUpdateTime;
  950. loadLocal=false;
  951. }
  952. }
  953. }
  954. }
  955. // if (loadLocal ||force)
  956. {
  957. List<string> ignore = new List<string>() { "PgJump", "PgRcv", "PgAdd" };
  958. await LessonETLService.FixLocalData(localIds, _azureCosmos, _azureStorage, pathLessons, stime, DateTimeOffset.Now.ToUnixTimeMilliseconds());
  959. List<TechCount> techCounts = new List<TechCount>();
  960. filesLessons = FileHelper.ListAllFiles(pathLessons, "-local.json");
  961. List<LessonLocal> lessonLocals = new List<LessonLocal>();
  962. int u = 0;
  963. if (force)
  964. {
  965. stopwatch.Start();
  966. Parallel.ForEach(filesLessons, file =>
  967. {
  968. string jsonp = System.IO.File.ReadAllText(file);
  969. var lessonLocal = jsonp.ToObject<LessonLocal>();
  970. if (lessonLocal.lessonBase!=null && lessonLocal.lessonBase.student.IsNotEmpty())
  971. {
  972. lessonLocals.Add(lessonLocal);
  973. }
  974. else
  975. {
  976. System.IO.File.Delete(file);
  977. System.IO.File.Delete(file.Replace("-local.json", "-count.json"));
  978. u++;
  979. }
  980. });
  981. stopwatch.Stop();
  982. }
  983. _logger.LogInformation($"Loaded {lessonLocals.Count} lessons in {stopwatch.Elapsed.TotalSeconds} seconds");
  984. int index = 0;
  985. await Parallel.ForEachAsync(filesLessons, async (item, _) => {
  986. TechCount techCount= await LessonETLService.GetTeachCount(_azureCosmos, item, pathLessons, ignore, Constant.objectiveTypes, _azureStorage, force, lessonLocals);
  987. if (techCount != null) {
  988. techCounts.Add(techCount);
  989. }
  990. index++;
  991. });
  992. long newest = lessonLocals.Max(x=>x.lessonRecord.startTime);
  993. await LessonETLService.GenAnalysisData(pathAnalysis, newest, techCounts,_azureStorage);
  994. }
  995. return Ok(new { });
  996. }
  997. }
  998. }