LessonService.cs 49 KB

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