LessonRecordController.cs 28 KB

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