LessonRecordController.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. using DocumentFormat.OpenXml.Office2010.Excel;
  2. using HTEX.Lib.ETL;
  3. using HTEX.Lib.ETL.Lesson;
  4. using Microsoft.AspNetCore.Mvc;
  5. using Microsoft.Azure.Cosmos;
  6. using Microsoft.OData.UriParser;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Runtime.InteropServices;
  10. using System.Text.Json;
  11. using System.Xml;
  12. using TEAMModelOS.SDK;
  13. using TEAMModelOS.SDK.DI;
  14. using TEAMModelOS.SDK.Extension;
  15. using TEAMModelOS.SDK.Helper.Common.FileHelper;
  16. using TEAMModelOS.SDK.Models;
  17. using TEAMModelOS.SDK.Models.Cosmos.BI;
  18. using TEAMModelOS.SDK.Models.Cosmos.OpenEntity;
  19. namespace HTEX.DataETL.Controllers
  20. {
  21. [ApiController]
  22. [Route("lesson-record")]
  23. public class LessonRecordController : ControllerBase
  24. {
  25. private readonly ILogger<LessonRecordController> _logger;
  26. private readonly AzureCosmosFactory _azureCosmos;
  27. private readonly AzureStorageFactory _azureStorage;
  28. private readonly IConfiguration _configuration;
  29. private readonly IWebHostEnvironment _webHostEnvironment;
  30. public LessonRecordController(ILogger<LessonRecordController> logger, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage
  31. , IConfiguration configuration, IWebHostEnvironment environment)
  32. {
  33. _logger = logger;
  34. _azureCosmos = azureCosmos;
  35. _azureStorage = azureStorage;
  36. _configuration = configuration;
  37. _webHostEnvironment = environment;
  38. }
  39. [HttpPost("process-local")]
  40. public async Task<IActionResult> ProcessLocal(JsonElement json)
  41. {
  42. List<StudentLessonData> studentLessonDatas = new List<StudentLessonData>();
  43. string? id = json.GetProperty("id").GetString();
  44. if (!string.IsNullOrWhiteSpace(id))
  45. {
  46. string? lessonPath= _configuration.GetValue<string>("LessonPath");
  47. string? path = $"{lessonPath}\\locals\\{id}";
  48. var files = FileHelper.ListAllFiles(path);
  49. // var sampleJson =System.IO. File.ReadAllTextAsync(path);
  50. LessonBase? lessonBase = null;
  51. List<LocalStudent> localStudents = new List<LocalStudent>();
  52. List<TaskData> taskDatas = new List<TaskData>();
  53. List<SmartRatingData> smartRatingDatas = new List<SmartRatingData>();
  54. List<IRSData> irsDatas = new List<IRSData>();
  55. List<CoworkData> coworkDatas = new List<CoworkData>();
  56. List<ExamData> examDatas = new List<ExamData>();
  57. TimeLineData? timeLineData = null;
  58. foreach (var item in files)
  59. {
  60. if (item.Contains("IES\\base.json"))
  61. {
  62. string jsons = await System.IO.File.ReadAllTextAsync(item);
  63. jsons = jsons.Replace("\"Uncall\"", "0").Replace("Uncall", "0");
  64. lessonBase = jsons.ToObject<LessonBase>();
  65. var data = LessonETLService.GetBaseData(lessonBase);
  66. localStudents = data.studentLessonDatas;
  67. }
  68. if (item.Contains("IES\\TimeLine.json"))
  69. {
  70. string jsons = await System.IO.File.ReadAllTextAsync(item);
  71. timeLineData = jsons.ToObject<TimeLineData>();
  72. }
  73. if (item.Contains("IES\\Task.json"))
  74. {
  75. string jsons = await System.IO.File.ReadAllTextAsync(item);
  76. taskDatas = jsons.ToObject<List<TaskData>>();
  77. }
  78. if (item.Contains("IES\\SmartRating.json"))
  79. {
  80. string jsons = await System.IO.File.ReadAllTextAsync(item);
  81. smartRatingDatas = jsons.ToObject<List<SmartRatingData>>();
  82. }
  83. if (item.Contains("IES\\IRS.json"))
  84. {
  85. string jsons = await System.IO.File.ReadAllTextAsync(item);
  86. irsDatas = jsons.ToObject<List<IRSData>>();
  87. }
  88. if (item.Contains("IES\\Cowork.json"))
  89. {
  90. string jsons = await System.IO.File.ReadAllTextAsync(item);
  91. coworkDatas = jsons.ToObject<List<CoworkData>>();
  92. }
  93. try
  94. {
  95. if (item.Contains($"\\{id}\\Exam\\") && item.EndsWith("Exam.json"))
  96. {
  97. string examsFile = item;
  98. if (examsFile.EndsWith("Exam.json"))
  99. {
  100. ExamData? examData = null;
  101. string jsons = await System.IO.File.ReadAllTextAsync(item);
  102. jsons = jsons.Replace("\"publish\": \"0\"", "\"publish\": 0").Replace("\"publish\": \"1\"", "\"publish\": 1");
  103. examData = jsons.ToObject<ExamData>();
  104. if (examData != null && examData.exam.papers.IsNotEmpty())
  105. {
  106. string paperId = examData.exam.papers.First().id;
  107. string paperPath = $"{path}\\ExamPaper\\{paperId}\\index.json";
  108. string jsonp = await System.IO.File.ReadAllTextAsync(paperPath);
  109. LessonPaper lessonPaper = jsonp.ToObject<LessonPaper>();
  110. examData.paper = lessonPaper;
  111. examDatas.Add(examData);
  112. }
  113. }
  114. }
  115. }
  116. catch (Exception ex)
  117. {
  118. _logger.LogError(ex, ex.Message);
  119. }
  120. }
  121. if (lessonBase!=null && timeLineData!=null)
  122. {
  123. studentLessonDatas = localStudents.ToJsonString().ToObject<List<StudentLessonData>>();
  124. studentLessonDatas = LessonETLService.GetIRSData(lessonBase, timeLineData, irsDatas, studentLessonDatas, examDatas, id);
  125. studentLessonDatas = LessonETLService.GetCoworkData(lessonBase, timeLineData, coworkDatas, studentLessonDatas,id);
  126. studentLessonDatas = LessonETLService.GetExamData(lessonBase, timeLineData, examDatas, studentLessonDatas, Constant.objectiveTypes, id);
  127. studentLessonDatas = LessonETLService.GetSmartRatingData(lessonBase, timeLineData, smartRatingDatas, studentLessonDatas, id);
  128. studentLessonDatas = LessonETLService.GetTaskData(lessonBase, timeLineData, taskDatas, studentLessonDatas,id);
  129. await System.IO.File.WriteAllTextAsync(Path.Combine(path, $"student-analysis.json"), studentLessonDatas.ToJsonString());
  130. string jsons = await System.IO.File.ReadAllTextAsync($"{lessonPath}\\analysis\\analysis.json");
  131. LessonDataAnalysisCluster lessonDataAnalysis = jsons.ToObject<LessonDataAnalysisCluster>();
  132. var lessonItems= LessonETLService.ProcessStudentDataV1(studentLessonDatas, lessonDataAnalysis);
  133. XmlDocument xmlDocument = new XmlDocument();
  134. var runtimePath= System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  135. xmlDocument.Load($"{runtimePath}\\summary.xml");
  136. await LessonETLService. ExportToExcel(lessonItems, $"{path}\\analysis.xlsx", xmlDocument);
  137. }
  138. }
  139. return Ok();
  140. }
  141. /// <summary>
  142. ///
  143. /// </summary>
  144. /// <param name="json"></param>
  145. /// <returns></returns>
  146. [HttpPost("process-history-students")]
  147. public async Task<IActionResult> ProcessHistoryStudents(JsonElement json)
  148. {
  149. string? lessonBasePath = _configuration.GetValue<string>("LessonPath");
  150. string? pathLessons = $"{lessonBasePath}\\lessons";
  151. string? pathAnalysis = $"{lessonBasePath}\\analysis";
  152. string jsons = await System.IO.File.ReadAllTextAsync($"{pathAnalysis}\\analysis.json");
  153. LessonDataAnalysisCluster lessonDataAnalysis = jsons.ToObject<LessonDataAnalysisCluster>();
  154. List<string> filesLessons = FileHelper.ListAllFiles(pathLessons, "-local.json");
  155. var runtimePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  156. XmlDocument xmlDocument = new XmlDocument();
  157. xmlDocument.Load($"{runtimePath}\\summary.xml");
  158. List<string> noStujson = new List<string>();
  159. foreach (string fileLesson in filesLessons)
  160. {
  161. try {
  162. var stuFile = fileLesson.Replace("-local.json", "-stu.json");
  163. var excleFile = fileLesson.Replace("-local.json", "-stu.xlsx");
  164. if (System.IO.File.Exists(stuFile))
  165. {
  166. string stuJson = await System.IO.File.ReadAllTextAsync(stuFile);
  167. List<StudentLessonData> studentLessonDatas = stuJson.ToObject<List<StudentLessonData>>();
  168. var lessonItems = LessonETLService.ProcessStudentDataV1(studentLessonDatas, lessonDataAnalysis);
  169. await LessonETLService.ExportToExcel(lessonItems, excleFile, xmlDocument);
  170. }
  171. else
  172. {
  173. noStujson.Add(stuFile);
  174. }
  175. }
  176. catch (Exception ex) {
  177. throw new Exception($"{fileLesson},{ex.Message}",ex);
  178. }
  179. }
  180. return Ok(noStujson);
  181. }
  182. /// <summary>
  183. /// 课例数据ETL处理过程
  184. /// </summary>
  185. /// <param name="json"></param>
  186. /// <returns></returns>
  187. [HttpPost("process-history")]
  188. public async Task<IActionResult> ProcessHistory(JsonElement json)
  189. {
  190. List<string> localIds = new List<string>();
  191. string? lessonBasePath = _configuration.GetValue<string>("LessonPath");
  192. string? pathLessons = $"{lessonBasePath}\\lessons";
  193. string? pathAnalysis = $"{lessonBasePath}\\analysis";
  194. var filesLessons = FileHelper.ListAllFiles(pathLessons);
  195. foreach (var file in filesLessons)
  196. {
  197. if (file.EndsWith("-local.json"))
  198. {
  199. string lessonId = file.Split("\\").Last().Replace("-local.json", "");
  200. localIds.Add(lessonId);
  201. }
  202. }
  203. bool loadLocal = true;
  204. List<LessonDataAnalysisMonth> lessonDataAnalysisMonths = new List<LessonDataAnalysisMonth>();
  205. var filesAnalysis = FileHelper.ListAllFiles(pathAnalysis);
  206. long stime = 1690819200000;//2023-08-01 00:00:00
  207. foreach (var file in filesAnalysis) {
  208. //读取每月的数据
  209. if (file.EndsWith("-m-analysis.json"))
  210. {
  211. string jsons = await System.IO.File.ReadAllTextAsync(file);
  212. LessonDataAnalysisMonth lessonDataAnalysis = jsons.ToObject<LessonDataAnalysisMonth>();
  213. lessonDataAnalysisMonths.Add(lessonDataAnalysis);
  214. }
  215. }
  216. if (lessonDataAnalysisMonths.IsNotEmpty()) {
  217. var maxUpdateTime = lessonDataAnalysisMonths.Max(x => x.updateTime);
  218. if (maxUpdateTime>0)
  219. {
  220. //更新周期是一周
  221. if (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()- maxUpdateTime>604800000)
  222. {
  223. stime=maxUpdateTime;
  224. loadLocal =true;
  225. }
  226. else
  227. {
  228. stime=maxUpdateTime;
  229. loadLocal=false;
  230. }
  231. }
  232. }
  233. HashSet<string> yearMonth = new HashSet<string>();
  234. long newest = 0;
  235. if (loadLocal ||(json.TryGetProperty("force", out JsonElement _force)&& _force.ValueKind.Equals(JsonValueKind.True)))
  236. {
  237. List<LessonRecord> lessonRecords = new List<LessonRecord>();
  238. var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
  239. .GetList<LessonRecord>($"SELECT value c FROM c where c.startTime>={stime} and c.expire<=0 and c.status<>404 and c.duration>300 and c.pk='LessonRecord' and c.school<>'hbcn' and c.school<>'habook' and (c.tLevel>0 or c.pLevel>0) ", null);
  240. if (resultSchool.list.IsNotEmpty())
  241. {
  242. newest= resultSchool.list.Max(x => x.startTime);
  243. lessonRecords.AddRange(resultSchool.list);
  244. }
  245. else {
  246. newest=stime;
  247. }
  248. var resultTeacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
  249. .GetList<LessonRecord>($"SELECT value c FROM c where c.startTime>={stime} and c.expire<=0 and c.status<>404 and c.duration>300 and c.pk='LessonRecord' and (c.tLevel>0 or c.pLevel>0) ", null);
  250. if (resultTeacher.list.IsNotEmpty())
  251. {
  252. long max = resultTeacher.list.Max(x => x.startTime);
  253. if (max<newest)
  254. {
  255. newest=max;
  256. }
  257. lessonRecords.AddRange(resultTeacher.list);
  258. }
  259. List<string> ignore = new List<string>() { "PgJump", "PgRcv", "PgAdd" };
  260. if (lessonRecords.IsNotEmpty())
  261. {
  262. await foreach (var item in LessonETLService.GetLessonLocal(lessonRecords, localIds, _azureStorage, pathLessons))
  263. {
  264. string yearMonthPath = DateTimeOffset.FromUnixTimeMilliseconds(item.lessonRecord.startTime).ToString("yyyyMM");
  265. if (item.lessonBase!=null && item.lessonBase.student!=null)
  266. {
  267. TechCount techCount = new TechCount
  268. {
  269. lessonId=item.lessonRecord?.id,
  270. examCount = item.examDatas.Count,
  271. taskCount = item.taskDatas.Count,
  272. irsCount = item.irsDatas.Count,
  273. coworkCount = item.coworkDatas.Count,
  274. smartRatingCount =item.smartRatingDatas.Count,
  275. timeCount=item.sokratesDatas.Where(x => !ignore.Contains(x.Event) && !x.Event.Contains("End", StringComparison.OrdinalIgnoreCase)).GroupBy(x => x.Event).Select(x => new CodeLong() { code=x.Key, value= x.ToList().Count }).ToList()
  276. };
  277. await System.IO.File.WriteAllTextAsync($"{pathLessons}\\MM{yearMonthPath}\\{item.lessonRecord.id}-count.json", techCount.ToJsonString());
  278. await System.IO.File.WriteAllTextAsync($"{pathLessons}\\MM{yearMonthPath}\\{item.lessonRecord!.id}-local.json", item.ToJsonString());
  279. }
  280. else
  281. {
  282. System.IO.File.Delete($"{pathLessons}\\MM{yearMonthPath}\\{item.lessonRecord!.id}-local.json");
  283. System.IO.File.Delete($"{pathLessons}\\MM{yearMonthPath}\\{item.lessonRecord!.id}-count.json");
  284. }
  285. }
  286. }
  287. List<TechCount> techCounts = new List<TechCount>();
  288. filesLessons = FileHelper.ListAllFiles(pathLessons, "-local.json");
  289. await foreach (var item in GetTeachCount(lessonRecords, filesLessons, pathLessons, ignore, Constant.objectiveTypes, _azureStorage))
  290. {
  291. techCounts.Add(item);
  292. }
  293. var yearMonthDatas = techCounts.GroupBy(x => x.yearMonth).Select(x => new { key = x.Key, list = x.ToList() });
  294. // lessonDataAnalysisMonths = new List<LessonDataAnalysisMonth>();
  295. LessonDataAnalysisCluster lessonDataAnalysisCluster = new LessonDataAnalysisCluster();
  296. foreach (var yearMonthData in yearMonthDatas)
  297. {
  298. if (string.IsNullOrWhiteSpace(yearMonthData.key))
  299. {
  300. Console.WriteLine(yearMonthData.list.Select(x => x.lessonId).ToJsonString());
  301. }
  302. LessonDataAnalysisMonth lessonDataAnalysisMonth= new LessonDataAnalysisMonth() { updateTime= newest, yearMonth= yearMonthData.key };
  303. lessonDataAnalysisMonth.pscore = yearMonthData.list.SelectMany(x => x.pscore).ToList();
  304. lessonDataAnalysisMonth.tscore = yearMonthData.list.SelectMany(x => x.tscore).ToList();
  305. lessonDataAnalysisMonth.gscore = yearMonthData.list.SelectMany(x => x.gscore).ToList();
  306. lessonDataAnalysisMonth.irs= yearMonthData.list.Where(x => x.irsCount>0).Select(x =>(double)x.irsCount).ToList();
  307. lessonDataAnalysisMonth.interactNormal= yearMonthData.list.Where(x => x.interactNormalCount > 0).Select(x => (double)x.interactNormalCount).ToList();
  308. lessonDataAnalysisMonth.task = yearMonthData.list.Where(x => x.taskCount > 0).Select(x => (double)x.taskCount).ToList();
  309. lessonDataAnalysisMonth.stuCowork=yearMonthData.list.SelectMany(x => x.stuCowork).ToList();
  310. lessonDataAnalysisMonth.groupCowork=yearMonthData.list.SelectMany(x => x.groupCowork).ToList();
  311. System.IO.File.WriteAllText(Path.Combine(pathAnalysis, $"{yearMonthData.key}-m-analysis.json"), lessonDataAnalysisMonth.ToJsonString());
  312. // lessonDataAnalysisMonths.Add( lessonDataAnalysisMonth);
  313. if (lessonDataAnalysisMonth.task.IsNotEmpty())
  314. {
  315. lessonDataAnalysisCluster.task.AddRange(lessonDataAnalysisMonth.task);
  316. }
  317. if (lessonDataAnalysisMonth.irs.IsNotEmpty())
  318. {
  319. lessonDataAnalysisCluster.irs.AddRange(lessonDataAnalysisMonth.irs);
  320. }
  321. if (lessonDataAnalysisMonth.interactNormal.IsNotEmpty())
  322. {
  323. lessonDataAnalysisCluster.interactNormal.AddRange(lessonDataAnalysisMonth.interactNormal);
  324. }
  325. if (lessonDataAnalysisMonth.pscore.IsNotEmpty())
  326. {
  327. lessonDataAnalysisCluster.pscore.AddRange(lessonDataAnalysisMonth.pscore);
  328. }
  329. if (lessonDataAnalysisMonth.gscore.IsNotEmpty())
  330. {
  331. lessonDataAnalysisCluster.gscore.AddRange(lessonDataAnalysisMonth.gscore);
  332. }
  333. if (lessonDataAnalysisMonth.tscore.IsNotEmpty())
  334. {
  335. lessonDataAnalysisCluster.tscore.AddRange(lessonDataAnalysisMonth.tscore);
  336. }
  337. if (lessonDataAnalysisMonth.stuCowork.IsNotEmpty())
  338. {
  339. lessonDataAnalysisCluster.stuCowork.AddRange(lessonDataAnalysisMonth.stuCowork);
  340. }
  341. if (lessonDataAnalysisMonth.groupCowork.IsNotEmpty())
  342. {
  343. lessonDataAnalysisCluster.groupCowork.AddRange(lessonDataAnalysisMonth.groupCowork);
  344. }
  345. }
  346. //标准差偏差N倍,视为异常数据
  347. int thresholdMultiplier = 2;
  348. lessonDataAnalysisCluster.pscore= LessonETLService.CleanDataBySDThreshold(lessonDataAnalysisCluster.pscore.OrderBy(x => x), thresholdMultiplier);
  349. lessonDataAnalysisCluster.gscore= LessonETLService.CleanDataBySDThreshold(lessonDataAnalysisCluster.gscore.OrderBy(x => x), thresholdMultiplier);
  350. lessonDataAnalysisCluster.tscore= LessonETLService.CleanDataBySDThreshold(lessonDataAnalysisCluster.tscore.OrderBy(x => x), thresholdMultiplier);
  351. lessonDataAnalysisCluster.irs = LessonETLService.CleanDataBySDThreshold(lessonDataAnalysisCluster.irs.OrderBy(x => x), thresholdMultiplier);
  352. lessonDataAnalysisCluster.interactNormal=LessonETLService. CleanDataBySDThreshold(lessonDataAnalysisCluster.interactNormal.OrderBy(x => x), thresholdMultiplier);
  353. lessonDataAnalysisCluster.stuCowork=LessonETLService.CleanDataBySDThreshold(lessonDataAnalysisCluster.stuCowork.OrderBy(x=>x), thresholdMultiplier);
  354. lessonDataAnalysisCluster.groupCowork=LessonETLService.CleanDataBySDThreshold(lessonDataAnalysisCluster.groupCowork.OrderBy(x => x), thresholdMultiplier);
  355. var d = lessonDataAnalysisCluster.interactNormal.Select(x => x).OrderBy(x => x).ToArray();
  356. // 设置0 为自动规划聚类,11 则为自动规划后得到的数字。
  357. var clusterInteract = KMeansService.KMeansOptimized(d,11,10);
  358. //foreach (var item in clusterInteract)
  359. //{
  360. // Console.WriteLine($"dp:{item.Key} ,avg: {item.Value.Average()}, count: {item.Value.Count}, min:{item.Value.Min()}, max:{item.Value.Max()}");
  361. //}
  362. foreach (var item in clusterInteract.OrderBy(x => x.Key))
  363. {
  364. lessonDataAnalysisCluster.clustersInteract.Add(new KeyValuePair<double, List<double>>(item.Value.Average(), item.Value));
  365. //Console.WriteLine($"dp:{item.Key} ,avg: {item.Value.Average()}, count: {item.Value.Count}, min:{item.Value.Min()}, max:{item.Value.Max()},weight:{item.Value.Count*1.0/d.Count()}");
  366. }
  367. System.IO.File.WriteAllText(Path.Combine(pathAnalysis, "analysis.json"), lessonDataAnalysisCluster.ToJsonString());
  368. }
  369. return Ok(new { yearMonth });
  370. }
  371. private static async IAsyncEnumerable<TechCount> GetTeachCount(List<LessonRecord> lessonRecords,List<string> filesLessons, string pathLessons, List<string> ignore, List<string> objectiveTypes,AzureStorageFactory azureStorage)
  372. {
  373. foreach (var item in filesLessons)
  374. {
  375. if (item.EndsWith("-local.json"))
  376. {
  377. TechCount count = null;
  378. string lessonId = item.Split("\\").Last().Replace("-local.json", "");
  379. string countFile = item.Replace("-local.json", "-count.json");
  380. if (System.IO.File.Exists(countFile))
  381. {
  382. if (System.IO.File.Exists(countFile))
  383. {
  384. string contjson = await System.IO.File.ReadAllTextAsync(countFile);
  385. count = contjson.ToObject<TechCount>();
  386. }
  387. }
  388. if (string.IsNullOrWhiteSpace(count?.yearMonth))
  389. {
  390. string localjson = await System.IO.File.ReadAllTextAsync(item);
  391. var lessonLocal = localjson.ToObject<LessonLocal>();
  392. count = new TechCount();
  393. count.lessonId=item.Split("\\").Last().Replace("-local.json", "");
  394. count.examCount= lessonLocal.examDatas.Count;
  395. count.taskCount= lessonLocal.taskDatas.Count;
  396. count.irsCount= lessonLocal.irsDatas.Count;
  397. count.interactNormalCount=count.irsCount;
  398. count.coworkCount= lessonLocal.coworkDatas.Count;
  399. count.smartRatingCount= lessonLocal.smartRatingDatas.Count;
  400. count.timeCount=lessonLocal.sokratesDatas.Where(x => !ignore.Contains(x.Event) && !x.Event.Contains("End", StringComparison.OrdinalIgnoreCase)).GroupBy(x => x.Event).Select(x => new CodeLong() { code=x.Key, value= x.ToList().Count }).ToList();
  401. if (lessonLocal.lessonRecord!=null)
  402. {
  403. count.yearMonth=DateTimeOffset.FromUnixTimeMilliseconds(lessonLocal.lessonRecord.startTime).ToString("yyyyMM");
  404. if (lessonLocal?.lessonBase?.summary!=null)
  405. {
  406. count.smartRatingCountBase=lessonLocal.lessonBase.summary.smartRatingCount;
  407. count.irsCountBase=lessonLocal.lessonBase.summary.interactionCount;
  408. count.taskCountBase=lessonLocal.lessonBase.summary.collateTaskCount;
  409. count.coworkCountBase=lessonLocal.lessonBase.summary.coworkTaskCount;
  410. count.examCountBase=lessonLocal.lessonBase.summary.examCount;
  411. count.interactNormalCountBase= count.interactNormalCount;
  412. }
  413. if (lessonLocal?.lessonBase?.report?.clientSummaryList!=null)
  414. {
  415. count.pscore= lessonLocal.lessonBase.report.clientSummaryList.Where(x => x.score>0).Select(x => x.score);
  416. count.gscore= lessonLocal.lessonBase.report.clientSummaryList.Where(x => x.groupScore>0).Select(x => x.groupScore);
  417. count.tscore= lessonLocal.lessonBase.report.clientSummaryList.Where(x => x.interactScore>0).Select(x => x.interactScore);
  418. }
  419. ///处理学生数据
  420. {
  421. List<StudentLessonData> studentLessonDatas = lessonLocal.studentLessonDatas.ToJsonString().ToObject<List<StudentLessonData>>();
  422. studentLessonDatas = LessonETLService.GetIRSData(lessonLocal.lessonBase!, lessonLocal.timeLineData!, lessonLocal.irsDatas, studentLessonDatas, lessonLocal.examDatas, lessonLocal.lessonRecord.id);
  423. studentLessonDatas = LessonETLService.GetCoworkData(lessonLocal.lessonBase!, lessonLocal.timeLineData!, lessonLocal.coworkDatas, studentLessonDatas, lessonLocal.lessonRecord.id);
  424. studentLessonDatas = LessonETLService.GetExamData(lessonLocal.lessonBase!, lessonLocal.timeLineData!, lessonLocal.examDatas, studentLessonDatas, objectiveTypes, lessonLocal.lessonRecord.id);
  425. studentLessonDatas = LessonETLService.GetSmartRatingData(lessonLocal.lessonBase!, lessonLocal.timeLineData!, lessonLocal.smartRatingDatas, studentLessonDatas, lessonLocal.lessonRecord.id);
  426. studentLessonDatas = LessonETLService.GetTaskData(lessonLocal.lessonBase!, lessonLocal.timeLineData!, lessonLocal.taskDatas, studentLessonDatas, lessonLocal.lessonRecord.id);
  427. // var techCount = techCounts.Find(x => !string.IsNullOrWhiteSpace(x.lessonId) && !string.IsNullOrWhiteSpace(lessonLocal?.lessonRecord?.id) && x.lessonId.Equals(lessonLocal.lessonRecord.id));
  428. int sumUpload = 0;
  429. int taskCount = 0;
  430. int maxUpload = 0;
  431. //HashSet<string> pickUp = new HashSet<string>();
  432. foreach (var stu in studentLessonDatas)
  433. {
  434. var countS = stu.taskRecord.itemRecords.Where(x => x.optCount>0);
  435. if (countS.Count()>0)
  436. {
  437. int stuUploadmax = stu.taskRecord.itemRecords.Where(x => x.optCount>0).Max(x => x.optCount);
  438. if (stuUploadmax> maxUpload)
  439. {
  440. maxUpload=stuUploadmax;
  441. }
  442. }
  443. int stuUpload = stu.taskRecord.itemRecords.Where(x => x.optCount>0).Sum(x => x.optCount);
  444. sumUpload+=stuUpload;
  445. if (stu.taskRecord.itemRecords.Count()> taskCount)
  446. {
  447. taskCount=stu.taskRecord.itemRecords.Count();
  448. }
  449. var stu_scores = stu.coworkRecord.itemRecords.Where(x => x.itemScore>0).Select(x => x.itemScore);
  450. if (stu_scores!=null && stu_scores.Count()>0)
  451. {
  452. count.stuCowork.AddRange(stu_scores);
  453. }
  454. var grp_scores = stu.group_coworkScore.Where(x => x>0);
  455. if (grp_scores!=null && grp_scores.Count()>0)
  456. {
  457. count.groupCowork.AddRange(grp_scores);
  458. }
  459. //if (stu.pickups.IsNotEmpty())
  460. //{
  461. // foreach (var pickup in stu.pickups)
  462. // {
  463. // pickUp.Add(pickup);
  464. // }
  465. //}
  466. }
  467. if (studentLessonDatas.Count>0&& taskCount>0 && maxUpload>0)
  468. {
  469. var avgUpload = sumUpload*1.0/(studentLessonDatas.Count *taskCount);
  470. count.upload.Add(new List<double>() { avgUpload, maxUpload });
  471. }
  472. //if (pickUp.Count>0)
  473. //{
  474. // count.pickup.Add(pickUp.ToList());
  475. //}
  476. string owner = lessonLocal.lessonRecord.scope.Equals("school") ? lessonLocal.lessonRecord.school : lessonLocal.lessonRecord.tmdid;
  477. // if (!azureStorage.GetBlobContainerClient(owner).GetBlobClient($"records/{lessonLocal.lessonRecord.id}/student-analysis.json").Exists())
  478. {
  479. }
  480. // if (!System.IO.File.Exists($"{pathLessons}\\MM{count.yearMonth}\\{lessonLocal.lessonRecord.id}-stu.json"))
  481. {
  482. }
  483. if (lessonRecords.FindAll(x => x.id.Equals(lessonLocal.lessonRecord.id)).IsNotEmpty())
  484. {
  485. await System.IO.File.WriteAllTextAsync($"{pathLessons}\\MM{count.yearMonth}\\{lessonLocal.lessonRecord.id}-stu.json", studentLessonDatas.ToJsonString());
  486. await azureStorage.GetBlobContainerClient(owner).UploadFileByContainer(studentLessonDatas.ToJsonString(), "records", $"{lessonLocal.lessonRecord.id}/student-analysis.json");
  487. await System.IO.File.WriteAllTextAsync($"{pathLessons}\\MM{count.yearMonth}\\{lessonLocal.lessonRecord.id}-count.json", count.ToJsonString());
  488. }
  489. }
  490. }
  491. }
  492. if (count!=null)
  493. {
  494. yield return count;
  495. }
  496. }
  497. }
  498. }
  499. }
  500. }