LessonService.cs 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. using Azure.Core;
  2. using Azure.Cosmos;
  3. using Azure.Messaging.ServiceBus;
  4. using DocumentFormat.OpenXml.Drawing.Charts;
  5. using DocumentFormat.OpenXml.VariantTypes;
  6. using HTEXLib.COMM.Helpers;
  7. using MathNet.Numerics.Distributions;
  8. using Microsoft.Extensions.Configuration;
  9. using Microsoft.Extensions.Hosting;
  10. using OpenXmlPowerTools;
  11. using StackExchange.Redis;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Linq;
  15. using System.Text;
  16. using System.Text.Json;
  17. using System.Threading.Tasks;
  18. using TEAMModelOS.SDK.DI;
  19. using TEAMModelOS.SDK.Extension;
  20. using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
  21. using TEAMModelOS.SDK.Models.Cosmos.Common;
  22. using TEAMModelOS.SDK.Models.Cosmos.OpenEntity;
  23. using TEAMModelOS.SDK.Services;
  24. namespace TEAMModelOS.SDK.Models.Service
  25. {
  26. public class LessonService
  27. {
  28. public static readonly DateTime dateTime1970 = new DateTime(1970, 1, 1).ToLocalTime();
  29. public static Dictionary<string, object> GetLessonCond(JsonElement request)
  30. {
  31. Dictionary<string, object> dict = new Dictionary<string, object>();
  32. if (request.TryGetProperty("tmdid", out JsonElement tmdid))
  33. {
  34. if (tmdid.ValueKind.Equals(JsonValueKind.String) && !string.IsNullOrWhiteSpace($"{tmdid}"))
  35. {
  36. dict.Add("tmdid", tmdid);
  37. }
  38. else if(tmdid.ValueKind.Equals(JsonValueKind.Array)) {
  39. dict.Add("tmdid", tmdid);
  40. }
  41. }
  42. if (request.TryGetProperty("courseId", out JsonElement courseId) && !string.IsNullOrWhiteSpace($"{courseId}"))
  43. {
  44. dict.Add("courseId", courseId);
  45. }
  46. if (request.TryGetProperty("courseIds", out JsonElement courseIds))
  47. {
  48. dict.Add("courseId[*]", courseIds);
  49. }
  50. if (request.TryGetProperty("periodId", out JsonElement periodId) && !string.IsNullOrWhiteSpace($"{periodId}"))
  51. {
  52. dict.Add("periodId", periodId);
  53. }
  54. if (request.TryGetProperty("subjectId", out JsonElement subjectId))
  55. {
  56. dict.Add("subjectId", subjectId);
  57. }
  58. if (request.TryGetProperty("groupIds", out JsonElement groupIds))
  59. {
  60. dict.Add("groupIds[*]", groupIds);
  61. }
  62. if (request.TryGetProperty("grade", out JsonElement grade))
  63. {
  64. dict.Add("grade[*]", grade);
  65. }
  66. if (request.TryGetProperty("category", out JsonElement category))
  67. {
  68. dict.Add("category[*]", category);
  69. }
  70. if (request.TryGetProperty("doubleGreen", out JsonElement doubleGreen) && doubleGreen.GetBoolean())
  71. {
  72. dict.Add("=.tLevel", 2);
  73. dict.Add("=.pLevel", 2);
  74. //dict.Add(">=.tScore", 70);
  75. //dict.Add(">=.pScore", 70);
  76. }
  77. if (request.TryGetProperty("doubleRed", out JsonElement doubleRed) && doubleRed.GetBoolean())
  78. {
  79. dict.Add("=.tLevel", 0);
  80. dict.Add("=.pLevel", 0);
  81. //dict.Add(">=.tScore", 70);
  82. //dict.Add(">=.pScore", 70);
  83. }
  84. if (request.TryGetProperty("quality", out JsonElement quality) && quality.GetBoolean())
  85. {
  86. dict.Add(">=.discuss", 1);
  87. }
  88. if (request.TryGetProperty("excellent", out JsonElement excellent) && excellent.GetBoolean())
  89. {
  90. dict.Add(">=.excellent", 1);
  91. }
  92. if (request.TryGetProperty("name", out JsonElement name) && !string.IsNullOrWhiteSpace($"{name}"))
  93. {
  94. dict.Add("$.name", name);
  95. }
  96. if (request.TryGetProperty("today", out JsonElement today) && today.GetBoolean())
  97. {
  98. DateTime dateTimeA = Convert.ToDateTime(DateTimeOffset.UtcNow.ToString("D"));
  99. DateTime dateTimeB = Convert.ToDateTime(DateTimeOffset.UtcNow.ToString("D")).AddDays(1);
  100. double dayOf00_00_00 = (dateTimeA - dateTime1970).TotalMilliseconds;
  101. double day1Of00_00_00 = (dateTimeB - dateTime1970).TotalMilliseconds;
  102. dict.Add(">=.startTime", dayOf00_00_00);
  103. dict.Add("<.startTime", day1Of00_00_00);
  104. }
  105. if (request.TryGetProperty("week", out JsonElement week) && week.GetBoolean())
  106. {
  107. // DateTime dateTimeA = Convert.ToDateTime(DateTimeOffset.UtcNow.ToString("D"));
  108. DateTime dateTimeB = Convert.ToDateTime(DateTimeOffset.UtcNow.ToString("D")).AddDays(-7);
  109. double now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  110. double dayB = (dateTimeB - dateTime1970).TotalMilliseconds;
  111. dict.Add("<=.startTime", now);
  112. dict.Add(">=.startTime", dayB);
  113. }
  114. //查询即将到期的且没有被清理的。
  115. if (request.TryGetProperty("expire", out JsonElement expire) && expire.ValueKind.Equals(JsonValueKind.True))
  116. {
  117. dict.Add(">.expire", 0);
  118. dict.Add("!=.status", 404);
  119. }
  120. //查询已经清理的
  121. if (request.TryGetProperty("is404", out JsonElement is404) && is404.ValueKind.Equals(JsonValueKind.True))
  122. {
  123. dict.Add("=.status", 404);
  124. }
  125. //只查有效的
  126. if (request.TryGetProperty("isOk", out JsonElement isOk) && isOk.ValueKind.Equals(JsonValueKind.True))
  127. {
  128. dict.Add("<=.expire", 0);
  129. dict.Add("!=.status", 404);
  130. }
  131. if (request.TryGetProperty("month", out JsonElement month) && month.GetBoolean())
  132. {
  133. //DateTime dateTimeA = Convert.ToDateTime(DateTimeOffset.UtcNow.ToString("D"));
  134. DateTime dateTimeB = Convert.ToDateTime(DateTimeOffset.UtcNow.ToString("D")).AddDays(-30);
  135. double now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  136. double dayB = (dateTimeB - dateTime1970).TotalMilliseconds;
  137. dict.Add("<=.startTime", now);
  138. dict.Add(">=.startTime", dayB);
  139. }
  140. if (request.TryGetProperty("stime", out JsonElement stime) && !string.IsNullOrWhiteSpace($"{stime}"))
  141. {
  142. dict.Add(">=.startTime", stime);
  143. }
  144. if (request.TryGetProperty("etime", out JsonElement etime) && !string.IsNullOrWhiteSpace($"{etime}"))
  145. {
  146. dict.Add("<=.startTime", etime);
  147. }
  148. if (request.TryGetProperty("conds", out JsonElement conds) && conds.ValueKind.Equals(JsonValueKind.Array))
  149. {
  150. List<LessonSettingCond> settingConds = conds.Deserialize<List<LessonSettingCond>>();
  151. foreach (var item in settingConds)
  152. {
  153. dict.TryAdd($"{item.type}.{item.key}", item.val);
  154. //switch (item.type)
  155. //{
  156. // case ">=":
  157. // dict.TryAdd($">=.{item.key}",item.val);
  158. // break;
  159. // case "<=":
  160. // dict.TryAdd($"<=.{item.key}", item.val);
  161. // break;
  162. //}
  163. }
  164. }
  165. return dict;
  166. }
  167. public static async void DoLessonStudentRecord(DingDing _dingding, SnowflakeId snowflakeId, LessonRecord lessonRecord, string scope, CosmosClient client, string school, string tmdid,
  168. Teacher teacher, AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, IConfiguration _configuration, LessonBase lessonBase,AzureRedisFactory _azureRedis, List<string> pickupMemberIds, List<TaskData> taskDatas, List<IRSData> iRSDatas)
  169. {
  170. School schoolBase = null;
  171. Period period = null;
  172. try
  173. {
  174. int year = DateTimeOffset.UtcNow.Year;
  175. string hs = lessonBase?.report?.clientSummaryList.ToJsonString();
  176. var clientSummaryLists = lessonBase?.report?.clientSummaryList?.Where(x => x.groupTaskCompleteCount != 0 || x.groupScore != 0 || x.score != 0 || x.interactScore != 0 || x.taskCompleteCount != 0);
  177. IEnumerable<LessonStudent> students = new List<LessonStudent>();
  178. if (clientSummaryLists.Any())
  179. {
  180. var ids = clientSummaryLists.Select(x => x.seatID);
  181. students = lessonBase.student.Where(x => ids.Contains(x.seatID));
  182. }
  183. List<Student> studentsBase = new List<Student>();
  184. var stuids = students.Where(x => x.type == 2);
  185. if (stuids.Any())
  186. {
  187. stuids.ToList().ForEach(x => {
  188. x.school = string.IsNullOrWhiteSpace(x.school) ? school : x.school;
  189. });
  190. var result= await client.GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<Student>($"select value c from c where c.id in ({string.Join(",",stuids.Select(d=>$"'{d.id}'"))})", $"Base-{school}");
  191. if (result.list.Any()) {
  192. studentsBase = result.list;
  193. }
  194. }
  195. var groups = stuids.Where(z => !string.IsNullOrWhiteSpace(z.school)).GroupBy(x => x.school).Select(y => new { code = y.Key, list = y.ToList() });
  196. List<StudentScoreRecord> lessonStudentRecords = new List<StudentScoreRecord>();
  197. foreach (var group in groups)
  198. {
  199. string stusql = $"select value(c) from c where c.stuid in({string.Join(",", group.list.Select(x => $"'{x.id}'"))}) and c.school='{group.code}' and c.year={year}";
  200. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Student).GetItemQueryIterator<StudentScoreRecord>(queryText: stusql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"StudentScoreRecord") }))
  201. {
  202. lessonStudentRecords.Add(item);
  203. }
  204. }
  205. var tmdids = students.Where(x => x.type == 1);
  206. if (tmdids.Any())
  207. {
  208. string tmdsql = $"select value(c) from c where c.tmdid in({string.Join(",", tmdids.Select(x => $"'{x}'"))}) and c.year={year}";
  209. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Student).GetItemQueryIterator<StudentScoreRecord>(queryText: tmdsql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"StudentScoreRecord") }))
  210. {
  211. lessonStudentRecords.Add(item);
  212. }
  213. }
  214. (Semester currSemester, int studyYear, DateTimeOffset currSemesterDate, DateTimeOffset date, DateTimeOffset nextSemester) dataSemester = new(null,-1, DateTimeOffset.UtcNow, DateTimeOffset.UtcNow, DateTimeOffset.UtcNow) ;
  215. if (!string.IsNullOrWhiteSpace(school)) {
  216. schoolBase = await client.GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(school, new PartitionKey("Base"));
  217. period = schoolBase.period.Find(x => x.id.Equals($"{lessonRecord.periodId}"));
  218. if (period!= null) {
  219. dataSemester= SchoolService.GetSemester(period);
  220. }
  221. }
  222. List <Task<ItemResponse<StudentScoreRecord>>> records = new List<Task<ItemResponse<StudentScoreRecord>>>();
  223. HashSet <OverallEducation> overallEducations = new HashSet<OverallEducation>();
  224. // 互动次数,-1 表示没有进行互动。 与 0 不同
  225. int interactCount = -1;
  226. if (iRSDatas.IsNotEmpty()) {
  227. interactCount= iRSDatas.Where(z => z.isBuzz==false).SelectMany(v => v.clientAnswers).Count();
  228. }
  229. //任务发布次数 ,-1 表示没有进行互动。 与 0 不同
  230. int taskCount = -1;
  231. if (taskDatas.IsNotEmpty())
  232. {
  233. taskCount=0;
  234. foreach (var taskData in taskDatas)
  235. {
  236. var isGroupItem= taskData.clientWorks.FindAll(z => z.isGroupItem);
  237. if (isGroupItem.IsNotEmpty())
  238. {
  239. //有组任务
  240. }
  241. else {
  242. //没有组任务
  243. taskCount+=1;
  244. }
  245. }
  246. }
  247. foreach (var x in stuids) {
  248. var record = lessonStudentRecords.Find(l => l.stuid.Equals(x.id) && l.code.Equals($"StudentScoreRecord") && l.school.Equals(x.school));
  249. ClientSummaryList clientSummaryList = lessonBase.report.clientSummaryList.Find(c => c.seatID == x.seatID);
  250. if (record != null)
  251. {
  252. if (clientSummaryList != null)
  253. {
  254. var hasrecord = record.lessonRecords.Find(x => x.lessonId.Equals(lessonRecord.id));
  255. if (hasrecord != null)
  256. {
  257. hasrecord.gscore = clientSummaryList.groupScore;
  258. hasrecord.pscore = clientSummaryList.score;
  259. hasrecord.tscore = clientSummaryList.interactScore;
  260. hasrecord.tmdid = teacher.id;
  261. hasrecord.school = school;
  262. hasrecord.scope = lessonRecord.scope;
  263. hasrecord.lessonId = lessonRecord.id;
  264. hasrecord.courseId = lessonRecord.courseId;
  265. hasrecord.periodId = lessonRecord.periodId;
  266. hasrecord.subjectId = lessonRecord.subjectId;
  267. hasrecord.time = lessonRecord.startTime;
  268. }
  269. else
  270. {
  271. record.lessonRecords.Add(
  272. new StudentLessonRecord
  273. {
  274. gscore = clientSummaryList.groupScore,
  275. pscore = clientSummaryList.score,
  276. tscore = clientSummaryList.interactScore,
  277. tmdid = teacher.id,
  278. school = school,
  279. scope = lessonRecord.scope,
  280. lessonId = lessonRecord.id,
  281. courseId = lessonRecord.courseId,
  282. periodId = lessonRecord.periodId,
  283. subjectId = lessonRecord.subjectId,
  284. time = lessonRecord.startTime
  285. }
  286. );
  287. }
  288. }
  289. }
  290. else
  291. {
  292. record = new StudentScoreRecord
  293. {
  294. userType = Constant.ScopeStudent,
  295. id = $"{snowflakeId.NextId()}",
  296. year = year,
  297. stuid = x.id,
  298. school = x.school,
  299. code = $"StudentScoreRecord",
  300. pk = "StudentScoreRecord",
  301. ttl = -1,
  302. lessonRecords = new List<StudentLessonRecord> { new StudentLessonRecord
  303. {
  304. gscore = clientSummaryList.groupScore,
  305. pscore = clientSummaryList.score,
  306. tscore = clientSummaryList.interactScore,
  307. tmdid = teacher.id,
  308. school = school,
  309. scope = lessonRecord.scope,
  310. lessonId = lessonRecord.id,
  311. courseId = lessonRecord.courseId,
  312. periodId = lessonRecord.periodId,
  313. subjectId = lessonRecord.subjectId,
  314. time= lessonRecord.startTime
  315. }}
  316. };
  317. }
  318. record.userType = Constant.ScopeStudent;
  319. record.gscore = record.lessonRecords.Select(x => x.gscore).Sum();
  320. record.pscore = record.lessonRecords.Select(x => x.pscore).Sum();
  321. record.tscore = record.lessonRecords.Select(x => x.tscore).Sum();
  322. if (dataSemester.currSemester != null && (clientSummaryList.groupScore>0 || clientSummaryList.score > 0 || clientSummaryList.interactScore > 0))
  323. {
  324. string oid = $"{dataSemester.studyYear}-{dataSemester.currSemester.id}-{record.stuid}";
  325. string ocode = $"OverallEducation-{school}";
  326. var student = studentsBase.Find(stu => stu.id.Equals(x.id));
  327. Azure.Response response = await client.GetContainer(Constant.TEAMModelOS, Constant.Student).ReadItemStreamAsync(oid, new PartitionKey(ocode));
  328. OverallEducation overallEducation = null;
  329. if (response.Status != 200)
  330. {
  331. overallEducation = new OverallEducation
  332. {
  333. id =oid,
  334. code = $"OverallEducation-{school}",
  335. pk = "OverallEducation",
  336. ttl = -1,
  337. name = x.name,
  338. classId = student?.classId,
  339. schoolCode = $"{school}",
  340. semesterId = dataSemester.currSemester.id,
  341. year = dataSemester.studyYear,
  342. periodId = $"{period.id}",
  343. stuYear = student.year,
  344. studentId = x.id,
  345. lessonScore= new List<StudentLessonRecord> { new StudentLessonRecord
  346. {
  347. gscore = clientSummaryList.groupScore,
  348. pscore = clientSummaryList.score,
  349. tscore = clientSummaryList.interactScore,
  350. tmdid = teacher.id,
  351. school = school,
  352. scope = lessonRecord.scope,
  353. lessonId = lessonRecord.id,
  354. courseId = lessonRecord.courseId,
  355. periodId = lessonRecord.periodId,
  356. subjectId = lessonRecord.subjectId,
  357. time= lessonRecord.startTime
  358. }}
  359. };
  360. }
  361. else
  362. {
  363. overallEducation=JsonDocument.Parse(response.Content).RootElement.ToObject<OverallEducation>();
  364. var hasrecord = overallEducation.lessonScore.Find(x => x.lessonId.Equals(lessonRecord.id));
  365. if (hasrecord != null)
  366. {
  367. hasrecord.gscore = clientSummaryList.groupScore;
  368. hasrecord.pscore = clientSummaryList.score;
  369. hasrecord.tscore = clientSummaryList.interactScore;
  370. hasrecord.tmdid = teacher.id;
  371. hasrecord.school = school;
  372. hasrecord.scope = lessonRecord.scope;
  373. hasrecord.lessonId = lessonRecord.id;
  374. hasrecord.courseId = lessonRecord.courseId;
  375. hasrecord.periodId = lessonRecord.periodId;
  376. hasrecord.subjectId = lessonRecord.subjectId;
  377. hasrecord.time = lessonRecord.startTime;
  378. }
  379. else
  380. {
  381. overallEducation.lessonScore.Add(
  382. new StudentLessonRecord
  383. {
  384. gscore = clientSummaryList.groupScore,
  385. pscore = clientSummaryList.score,
  386. tscore = clientSummaryList.interactScore,
  387. tmdid = teacher.id,
  388. school = school,
  389. scope = lessonRecord.scope,
  390. lessonId = lessonRecord.id,
  391. courseId = lessonRecord.courseId,
  392. periodId = lessonRecord.periodId,
  393. subjectId = lessonRecord.subjectId,
  394. time = lessonRecord.startTime
  395. }
  396. );
  397. }
  398. }
  399. overallEducations.Add(overallEducation);
  400. }
  401. records.Add(client.GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(record, partitionKey: new PartitionKey(record.code)));
  402. }
  403. foreach (var x in tmdids) {
  404. var record = lessonStudentRecords.Find(l => l.tmdid.Equals(x.id) && l.code.Equals($"StudentScoreRecord"));
  405. ClientSummaryList clientSummaryList = lessonBase.report.clientSummaryList.Find(c => c.seatID == x.seatID);
  406. if (record != null)
  407. {
  408. if (clientSummaryList != null)
  409. {
  410. var hasrecord = record.lessonRecords.Find(x => x.lessonId.Equals(lessonRecord.id));
  411. if (hasrecord != null)
  412. {
  413. hasrecord.gscore = clientSummaryList.groupScore;
  414. hasrecord.pscore = clientSummaryList.score;
  415. hasrecord.tscore = clientSummaryList.interactScore;
  416. hasrecord.tmdid = teacher.id;
  417. hasrecord.school = school;
  418. hasrecord.scope = lessonRecord.scope;
  419. hasrecord.lessonId = lessonRecord.id;
  420. hasrecord.courseId = lessonRecord.courseId;
  421. hasrecord.periodId = lessonRecord.periodId;
  422. hasrecord.subjectId = lessonRecord.subjectId;
  423. hasrecord.time = lessonRecord.startTime;
  424. }
  425. else
  426. {
  427. record.lessonRecords.Add(
  428. new StudentLessonRecord
  429. {
  430. gscore = clientSummaryList.groupScore,
  431. pscore = clientSummaryList.score,
  432. tscore = clientSummaryList.interactScore,
  433. tmdid = teacher.id,
  434. school = school,
  435. scope = lessonRecord.scope,
  436. lessonId = lessonRecord.id,
  437. courseId = lessonRecord.courseId,
  438. periodId = lessonRecord.periodId,
  439. subjectId = lessonRecord.subjectId,
  440. time = lessonRecord.startTime
  441. }
  442. );
  443. }
  444. }
  445. }
  446. else
  447. {
  448. record = new StudentScoreRecord
  449. {
  450. userType = Constant.ScopeTmdUser,
  451. id = $"{snowflakeId.NextId()}",
  452. code = $"StudentScoreRecord",
  453. pk = "StudentScoreRecord",
  454. ttl = -1,
  455. year = year,
  456. tmdid = x.id,
  457. lessonRecords = new List<StudentLessonRecord>
  458. {
  459. new StudentLessonRecord
  460. {
  461. gscore = clientSummaryList.groupScore,
  462. pscore = clientSummaryList.score,
  463. tscore = clientSummaryList.interactScore,
  464. tmdid = teacher.id,
  465. school = school,
  466. scope = lessonRecord.scope,
  467. lessonId = lessonRecord.id,
  468. courseId = lessonRecord.courseId,
  469. periodId = lessonRecord.periodId,
  470. subjectId = lessonRecord.subjectId,
  471. time=lessonRecord.startTime
  472. }
  473. }
  474. };
  475. }
  476. record.userType = Constant.ScopeStudent;
  477. record.gscore = record.lessonRecords.Select(x => x.gscore).Sum();
  478. record.pscore = record.lessonRecords.Select(x => x.pscore).Sum();
  479. record.tscore = record.lessonRecords.Select(x => x.tscore).Sum();
  480. records.Add(client.GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(record, partitionKey: new PartitionKey(record.code)));
  481. }
  482. if (records.Any())
  483. {
  484. await Task.WhenAll(records);
  485. }
  486. if (overallEducations.Any())
  487. {
  488. foreach (var item in overallEducations) {
  489. await client.GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(item, partitionKey: new PartitionKey(item.code));
  490. string key = $"OverallEducation:{item.schoolCode}:{item.periodId}:{item.year}:{item.semesterId}:{item.classId}";
  491. await _azureRedis.GetRedisClient(8).HashSetAsync(key, item.studentId, item.ToJsonString());
  492. await _azureRedis.GetRedisClient(8).KeyExpireAsync(key,new TimeSpan(180 *24 ,0,0));
  493. }
  494. }
  495. }
  496. catch (Exception ex)
  497. {
  498. await _dingding.SendBotMsg($"学生个人课例统计信息异常,{ex.Message}\n{ex.StackTrace},{lessonRecord?.ToJsonString()}{school}", GroupNames.醍摩豆服務運維群組);
  499. }
  500. }
  501. public static async void DoAutoDeleteSchoolLessonRecord(LessonRecord lessonRecord, string scope, CosmosClient client, string school, string tmdid,
  502. Teacher teacher, AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, IConfiguration _configuration, CoreAPIHttpService _coreAPIHttpService,DingDing _dingDing,AzureRedisFactory _azureRedis)
  503. {
  504. if (lessonRecord.scope.Equals("school"))
  505. {
  506. SchoolSetting setting = null;
  507. Azure.Response schoolSetting = await client.GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync(school, new PartitionKey("SchoolSetting"));
  508. School schoolBase = await client.GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(school, new PartitionKey("Base"));
  509. if (schoolSetting.Status == 200)
  510. {
  511. setting = JsonDocument.Parse(schoolSetting.Content).RootElement.Deserialize<SchoolSetting>();
  512. if (setting.lessonSetting != null)
  513. {
  514. //两种状态都不属于,则默认未开启。
  515. if (setting.lessonSetting.openAutoClean != 0 && setting.lessonSetting.openAutoClean != 1)
  516. {
  517. setting.lessonSetting.openAutoClean = 0;
  518. setting.lessonSetting.expireDays = Constant.school_lesson_expire;
  519. }
  520. else {
  521. //属于 要么开启1,要么关闭0
  522. }
  523. }
  524. else
  525. {
  526. setting.lessonSetting = new LessonSetting() { openAutoClean = 0, expireDays = Constant.school_lesson_expire };
  527. }
  528. }
  529. else
  530. {
  531. setting = new SchoolSetting() { lessonSetting = new LessonSetting { openAutoClean = 0, expireDays = Constant.school_lesson_expire } };
  532. }
  533. int school_lesson_expire = 0;
  534. bool save = true;
  535. List<string> msg = new List<string>();
  536. if (setting.lessonSetting.openAutoClean == 1)
  537. {
  538. if (setting.lessonSetting.conds.IsEmpty())
  539. {
  540. save = false;
  541. }
  542. else
  543. {
  544. school_lesson_expire = setting.lessonSetting.expireDays;
  545. foreach (var item in setting.lessonSetting.conds)
  546. {
  547. switch (item.type)
  548. {
  549. case ">=":
  550. switch (item.key)
  551. {
  552. case "attendRate":
  553. if (!(lessonRecord.attendRate >= item.val))
  554. {
  555. save = false;
  556. msg.Add($"{item.key}:{lessonRecord.attendRate}{item.type}{item.val}");
  557. }
  558. break;
  559. case "groupCount":
  560. if (!(lessonRecord.groupCount >= item.val))
  561. {
  562. save = false;
  563. msg.Add($"{item.key}:{lessonRecord.groupCount}{item.type}{item.val}");
  564. }
  565. break;
  566. case "totalPoint":
  567. if (!(lessonRecord.totalPoint >= item.val))
  568. {
  569. save = false;
  570. msg.Add($"{item.key}:{lessonRecord.totalPoint}{item.type}{item.val}");
  571. }
  572. break;
  573. case "collateTaskCount":
  574. if (!(lessonRecord.collateTaskCount >= item.val))
  575. {
  576. save = false;
  577. msg.Add($"{item.key}:{lessonRecord.collateTaskCount}{item.type}{item.val}");
  578. }
  579. break;
  580. case "collateCount":
  581. if (!(lessonRecord.collateCount >= item.val))
  582. {
  583. save = false;
  584. msg.Add($"{item.key}:{lessonRecord.collateCount}{item.type}{item.val}");
  585. }
  586. break;
  587. case "pushCount":
  588. if (!(lessonRecord.pushCount >= item.val))
  589. {
  590. save = false;
  591. msg.Add($"{item.key}:{lessonRecord.pushCount}{item.type}{item.val}");
  592. }
  593. break;
  594. case "totalInteractPoint":
  595. if (!(lessonRecord.totalInteractPoint >= item.val))
  596. {
  597. save = false;
  598. msg.Add($"{item.key}:{lessonRecord.totalInteractPoint}{item.type}{item.val}");
  599. }
  600. break;
  601. case "interactionCount":
  602. if (!(lessonRecord.interactionCount >= item.val))
  603. {
  604. save = false;
  605. msg.Add($"{item.key}:{lessonRecord.interactionCount}{item.type}{item.val}");
  606. }
  607. break;
  608. case "clientInteractionCount":
  609. if (!(lessonRecord.clientInteractionCount >= item.val))
  610. {
  611. save = false;
  612. msg.Add($"{item.key}:{lessonRecord.clientInteractionCount}{item.type}{item.val}");
  613. }
  614. break;
  615. case "examQuizCount":
  616. if (!(lessonRecord.examQuizCount >= item.val))
  617. {
  618. save = false;
  619. msg.Add($"{item.key}:{lessonRecord.examQuizCount}{item.type}{item.val}");
  620. }
  621. break;
  622. case "examPointRate":
  623. if (!(lessonRecord.examPointRate >= item.val))
  624. {
  625. save = false;
  626. msg.Add($"{item.key}:{lessonRecord.examPointRate}{item.type}{item.val}");
  627. }
  628. break;
  629. }
  630. break;
  631. case "<=":
  632. switch (item.key)
  633. {
  634. case "attendRate":
  635. if (!(lessonRecord.attendRate <= item.val))
  636. {
  637. save = false;
  638. msg.Add($"{item.key}:{lessonRecord.attendRate}{item.type}{item.val}");
  639. }
  640. break;
  641. case "groupCount":
  642. if (!(lessonRecord.groupCount <= item.val))
  643. {
  644. save = false;
  645. msg.Add($"{item.key}:{lessonRecord.groupCount}{item.type}{item.val}");
  646. }
  647. break;
  648. case "totalPoint":
  649. if (!(lessonRecord.totalPoint <= item.val))
  650. {
  651. save = false;
  652. msg.Add($"{item.key}:{lessonRecord.totalPoint}{item.type}{item.val}");
  653. }
  654. break;
  655. case "collateTaskCount":
  656. if (!(lessonRecord.collateTaskCount <= item.val))
  657. {
  658. save = false;
  659. msg.Add($"{item.key}:{lessonRecord.collateTaskCount}{item.type}{item.val}");
  660. }
  661. break;
  662. case "collateCount":
  663. if (!(lessonRecord.collateCount <= item.val))
  664. {
  665. save = false;
  666. msg.Add($"{item.key}:{lessonRecord.collateCount}{item.type}{item.val}");
  667. }
  668. break;
  669. case "pushCount":
  670. if (!(lessonRecord.pushCount <= item.val))
  671. {
  672. save = false;
  673. msg.Add($"{item.key}:{lessonRecord.pushCount}{item.type}{item.val}");
  674. }
  675. break;
  676. case "totalInteractPoint":
  677. if (!(lessonRecord.totalInteractPoint <= item.val))
  678. {
  679. save = false;
  680. msg.Add($"{item.key}:{lessonRecord.totalInteractPoint}{item.type}{item.val}");
  681. }
  682. break;
  683. case "interactionCount":
  684. if (!(lessonRecord.interactionCount <= item.val))
  685. {
  686. save = false;
  687. msg.Add($"{item.key}:{lessonRecord.interactionCount}{item.type}{item.val}");
  688. }
  689. break;
  690. case "clientInteractionCount":
  691. if (!(lessonRecord.clientInteractionCount <= item.val))
  692. {
  693. save = false;
  694. msg.Add($"{item.key}:{lessonRecord.clientInteractionCount}{item.type}{item.val}");
  695. }
  696. break;
  697. case "examQuizCount":
  698. if (!(lessonRecord.examQuizCount <= item.val))
  699. {
  700. save = false;
  701. msg.Add($"{item.key}:{lessonRecord.examQuizCount}{item.type}{item.val}");
  702. }
  703. break;
  704. case "examPointRate":
  705. if (!(lessonRecord.examPointRate <= item.val))
  706. {
  707. save = false;
  708. msg.Add($"{item.key}:{lessonRecord.examPointRate}{item.type}{item.val}");
  709. }
  710. break;
  711. }
  712. break;
  713. }
  714. }
  715. }
  716. }
  717. /* 注释start 2023.3.22,该段逻辑在开课的时候已经处理,详见ActiveTaskTopic. LessonRecordEvent create ,无论有没有开启setting.lessonSetting.openAutoClean 自动删除策略,只要空间不足都会对课例进行自动清理管理。
  718. else
  719. {
  720. ///未设置openAutoClean=1时,则检查学校使用空间是否充足。
  721. double usize = 0;
  722. int tsize = schoolBase.tsize;
  723. //schoolBase.tsize
  724. //計算學校或個人的使用空間
  725. RedisValue redisValue = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", $"{schoolBase.id}");
  726. if (redisValue.HasValue && long.TryParse(redisValue.ToString(), out var bsize))
  727. {
  728. usize = Math.Round(bsize / 1073741824.0 - (tsize), 2, MidpointRounding.AwayFromZero); //1073741824 1G
  729. }
  730. else //如果檢測不到緩存,觸發刷新計算空間
  731. {
  732. await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "update", root = "records", name = $"{schoolBase.id}" }, _serviceBus, _configuration, _azureRedis);
  733. }
  734. ///空间充足的情况保存。
  735. if (schoolBase.size - usize > 0)
  736. {
  737. save = true;
  738. }
  739. else {
  740. save = false;
  741. school_lesson_expire = Constant.school_lesson_expire;
  742. }
  743. } 注释end 2023.3.22,该段逻辑在开课的时候已经处理,详见ActiveTaskTopic. LessonRecordEvent create ,无论有没有开启setting.lessonSetting.openAutoClean 自动删除策略,只要空间不足都会对课例进行自动清理管理。
  744. */
  745. if (!save && school_lesson_expire > 0)
  746. {
  747. // 1-时间戳,7-时间戳
  748. Dictionary<int, ExpireTag> result = new Dictionary<int, ExpireTag>();
  749. //暂定7天
  750. var now = DateTimeOffset.UtcNow;
  751. //剩余3天的通知
  752. //var day3= now.AddDays(school_lesson_expire - 3).ToUnixTimeMilliseconds();
  753. //result.Add(3, day3);
  754. //剩余1天的通知
  755. var day1 = now.AddDays(school_lesson_expire - (school_lesson_expire - 1)).ToUnixTimeMilliseconds();
  756. result.Add(1, new ExpireTag { expire = day1, tag = "notification" });
  757. //到期通知
  758. //不到五点上传的课例,七天之后直接删除。
  759. int addSecond = 0;
  760. if (now.Hour > 5)
  761. {
  762. // 到凌晨00点还差 (24 - now.Hour) *60 * 60 分钟,再加天数;
  763. addSecond = school_lesson_expire * 86400 + (24 - now.Hour) * 3600 - (now.Hour * 3600);
  764. //再加 00到05小时内的 随机秒数
  765. Random rand = new Random();
  766. int randInt = rand.Next(0, 18000);
  767. addSecond += randInt;
  768. }
  769. else
  770. {
  771. addSecond = school_lesson_expire * 24 * 60 * 60;
  772. }
  773. lessonRecord.expire = now.AddSeconds(addSecond).ToUnixTimeMilliseconds();
  774. result.Add(school_lesson_expire, new ExpireTag { expire = lessonRecord.expire, tag = "delete" });
  775. // result.Add(school_lesson_expire, lessonRecord.expire);
  776. string biz = "expire";
  777. string expireTime = DateTimeOffset.FromUnixTimeMilliseconds(lessonRecord.expire).ToString("yyyy-MM-dd HH:mm:ss");
  778. Teacher targetTeacher = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>($"{tmdid}", new PartitionKey($"Base"));
  779. _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = targetTeacher.id, name = targetTeacher.name, code = targetTeacher.lang } }, "expire-school_lessonRecord", Constant.NotifyType_IES5_Course,
  780. new Dictionary<string, object> { { "tmdid", teacher.id }, { "tmdname", teacher.name }, { "schoolName", schoolBase.name },
  781. { "schoolId", $"{school}" },{ "lessonId",lessonRecord.id }, { "expireTime", expireTime },{ "lessonName",lessonRecord.name } }, $"{Environment.GetEnvironmentVariable("Option:Location")}", _configuration, _dingDing, "");
  782. var table = _azureStorage.GetCloudTableClient().GetTableReference("ChangeRecord");
  783. List<ChangeRecord> records = await table.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", lessonRecord.id } });
  784. if (records.Count <= 0)
  785. {
  786. foreach (var item in result)
  787. {
  788. string PartitionKey = string.Format("{0}{1}{2}", lessonRecord.code, "-", $"expire-{item.Key}");
  789. //课堂的id ,
  790. //课堂的通知时间类型progress, 默认就会发送一条,到期前一天发送一条,最后已到期发送一条。
  791. var message = new ServiceBusMessage(new
  792. {
  793. id = lessonRecord.id,
  794. progress = item.Key,
  795. code = lessonRecord.code,
  796. scope = lessonRecord.scope,
  797. school = lessonRecord.school,
  798. opt = "delete",
  799. expire = lessonRecord.expire,
  800. tmdid = tmdid,
  801. tmdname = teacher.name,
  802. name = lessonRecord.name,
  803. startTime = lessonRecord.startTime,
  804. tag = item.Value.tag
  805. }.ToJsonString());
  806. message.ApplicationProperties.Add("name", "LessonRecordExpire");
  807. long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), message, DateTimeOffset.FromUnixTimeMilliseconds(item.Value.expire));
  808. ChangeRecord changeRecord = new ChangeRecord
  809. {
  810. RowKey = lessonRecord.id,
  811. PartitionKey = PartitionKey,
  812. sequenceNumber = start,
  813. msgId = message.MessageId
  814. };
  815. await table.Save<ChangeRecord>(changeRecord);
  816. }
  817. }
  818. }
  819. else
  820. {
  821. if (lessonRecord.expire > 0)
  822. {
  823. var table = _azureStorage.GetCloudTableClient().GetTableReference("ChangeRecord");
  824. List<ChangeRecord> records = await table.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", lessonRecord.id } });
  825. foreach (var record in records)
  826. {
  827. try
  828. {
  829. await table.DeleteSingle<ChangeRecord>(record.PartitionKey, record.RowKey);
  830. await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
  831. }
  832. catch (Exception)
  833. {
  834. continue;
  835. }
  836. }
  837. }
  838. lessonRecord.save = 1;
  839. lessonRecord.expire = -1;
  840. }
  841. }
  842. }
  843. public record ExpireTag
  844. {
  845. public long expire { get; set; }
  846. public string tag { get; set; }
  847. }
  848. /// <summary>
  849. ///
  850. /// </summary>
  851. /// <param name="client"></param>
  852. /// <param name="_dingDing"></param>
  853. /// <param name="data"></param>
  854. /// <returns></returns>
  855. public static LessonDis DisLessonCount(LessonRecord oldRecord, LessonRecord newRecord, LessonDis lessonDis)
  856. {
  857. //创建课堂的情况
  858. if (oldRecord == null && newRecord != null)
  859. {
  860. lessonDis.record = 1;
  861. }
  862. //删除数据的情况
  863. //不再对LessonCount进行减
  864. else if (oldRecord != null && newRecord == null)
  865. {
  866. /*lessonDis.record = -1;
  867. //P分数量加减
  868. if (oldRecord.pScore >= 70)
  869. {
  870. lessonDis.disPCount = -1;
  871. }
  872. //T分数量加减
  873. if (oldRecord.tScore >= 70)
  874. {
  875. lessonDis.disTCount = -1;
  876. }
  877. if (oldRecord.tScore >= 70 && oldRecord.pScore >= 70)
  878. {
  879. lessonDis.disTCount = -1;
  880. }*/
  881. }
  882. //无效操作
  883. else if (oldRecord == null && newRecord == null)
  884. {
  885. }
  886. //前后操作都有值,则表示更新
  887. else
  888. {
  889. //P分数量加减
  890. if (oldRecord.pScore >= 70)
  891. {
  892. if (newRecord.pScore < 70)
  893. {
  894. lessonDis.disPCount = -1;
  895. }
  896. }
  897. else
  898. {
  899. if (newRecord.pScore >= 70)
  900. {
  901. lessonDis.disPCount = 1;
  902. }
  903. }
  904. //T分数量加减
  905. if (oldRecord.tScore >= 70)
  906. {
  907. if (newRecord.tScore < 70)
  908. {
  909. lessonDis.disTCount = -1;
  910. }
  911. }
  912. else
  913. {
  914. if (newRecord.tScore >= 70)
  915. {
  916. lessonDis.disTCount = 1;
  917. }
  918. }
  919. //双绿灯数量
  920. if (oldRecord.tScore >= 70 && oldRecord.pScore >= 70)
  921. {
  922. if (newRecord.tScore < 70 || newRecord.pScore < 70)
  923. {
  924. lessonDis.disDCount = -1;
  925. }
  926. }
  927. else
  928. {
  929. if (newRecord.tScore >= 70 && newRecord.pScore >= 70)
  930. {
  931. lessonDis.disDCount = 1;
  932. }
  933. }
  934. }
  935. return lessonDis;
  936. }
  937. public static LessonDis DisLessonCount_2(LessonRecord oldRecord, LessonRecord newRecord, LessonDis lessonDis)
  938. {
  939. //创建课堂的情况
  940. if (oldRecord == null && newRecord != null)
  941. {
  942. lessonDis.record = 1;
  943. //P分数量加减
  944. if (newRecord.pScore >= 70)
  945. {
  946. lessonDis.disPCount = 1;
  947. }
  948. //T分数量加减
  949. if (newRecord.tScore >= 70)
  950. {
  951. lessonDis.disTCount = 1;
  952. }
  953. //双绿灯数量
  954. if (newRecord.tScore >= 70 && newRecord.pScore >= 70)
  955. {
  956. lessonDis.disDCount = 1;
  957. }
  958. }
  959. return lessonDis;
  960. }
  961. public static async Task FixLessonCount(CosmosClient client, DingDing _dingDing, LessonRecord record, LessonRecord oldRecord, LessonDis lessonDis)
  962. {
  963. LessonRecord data = null;
  964. try
  965. {
  966. if (record != null && oldRecord == null)
  967. {
  968. data = record;
  969. }
  970. if (record == null && oldRecord != null)
  971. {
  972. data = oldRecord;
  973. }
  974. if (record != null && oldRecord != null)
  975. {
  976. data = record;
  977. }
  978. int day = DateTimeOffset.FromUnixTimeMilliseconds(data.startTime).DayOfYear;
  979. int year = DateTimeOffset.FromUnixTimeMilliseconds(data.startTime).Year;
  980. int days = DateTimeHelper.getDays(year);
  981. //int years = DateTimeOffset.UtcNow.DayOfYear;
  982. string tbname = string.Empty;
  983. string code = string.Empty;
  984. if (data.groupIds.Any()) {
  985. if (data.scope != null && data.scope.Equals("school"))
  986. {
  987. if (string.IsNullOrEmpty(data.periodId))
  988. {
  989. code = $"LessonCount-{data.school}-{year}";
  990. tbname = "School";
  991. }
  992. else
  993. {
  994. code = $"LessonCount-{data.school}-{year}-{data.periodId}";
  995. tbname = "School";
  996. }
  997. }
  998. else
  999. {
  1000. code = $"LessonCount-{year}";
  1001. tbname = "Teacher";
  1002. }
  1003. var response = await client.GetContainer(Constant.TEAMModelOS, tbname).ReadItemStreamAsync(data.tmdid.ToString(), new PartitionKey(code));
  1004. if (response.Status == 200)
  1005. {
  1006. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  1007. LessonCount count = json.ToObject<LessonCount>();
  1008. count.tCount[day - 1] += lessonDis.disTCount;
  1009. count.pCount[day - 1] += lessonDis.disPCount;
  1010. count.ptCount[day - 1] += lessonDis.disDCount;
  1011. count.beginCount[day - 1] += lessonDis.record;
  1012. await client.GetContainer("TEAMModelOS", tbname).ReplaceItemAsync(count, count.id, new PartitionKey(code));
  1013. }
  1014. else
  1015. {
  1016. LessonCount count = new()
  1017. {
  1018. id = data.tmdid,
  1019. code = code,
  1020. ttl = -1
  1021. };
  1022. double[] da = new double[days];
  1023. List<double> list = new(da);
  1024. List<double> listT = new(da);
  1025. List<double> listP = new(da);
  1026. List<double> listPT = new(da);
  1027. list[day - 1] += lessonDis.record;
  1028. listT[day - 1] += lessonDis.disTCount;
  1029. listP[day - 1] += lessonDis.disPCount;
  1030. listPT[day - 1] += lessonDis.disDCount;
  1031. count.beginCount.AddRange(list);
  1032. count.tCount.AddRange(listT);
  1033. count.pCount.AddRange(listP);
  1034. count.ptCount.AddRange(listPT);
  1035. //count.courseIds.Add(data.courseId);
  1036. await client.GetContainer("TEAMModelOS", tbname).CreateItemAsync(count, new PartitionKey(code));
  1037. }
  1038. }
  1039. }
  1040. catch (Exception ex)
  1041. {
  1042. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-LessonCount-FixLessonCount\n{ex.Message}\n{ex.StackTrace}{data.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
  1043. }
  1044. }
  1045. }
  1046. }