LessonService.cs 56 KB

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