LessonService.cs 50 KB

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