MonitorServicesBus.cs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Text.Json;
  5. using System.Threading.Tasks;
  6. using Azure.Cosmos;
  7. using Azure.Messaging.ServiceBus;
  8. using Microsoft.Azure.WebJobs;
  9. using Microsoft.Azure.WebJobs.Host;
  10. using Microsoft.Extensions.Logging;
  11. using StackExchange.Redis;
  12. using TEAMModelOS.SDK.DI;
  13. using TEAMModelOS.SDK.Extension;
  14. using TEAMModelOS.SDK;
  15. using TEAMModelOS.SDK.Models;
  16. using TEAMModelOS.SDK.Models.Cosmos;
  17. using TEAMModelOS.SDK.Models.Cosmos.Common;
  18. using TEAMModelOS.Services.Common;
  19. using System.Linq;
  20. using TEAMModelOS.SDK.Models.Service;
  21. using TEAMModelOS.SDK.Models.Cosmos.BI;
  22. using TEAMModelOS.Models;
  23. using Microsoft.Extensions.Options;
  24. using Microsoft.Extensions.Configuration;
  25. using HTEXLib.COMM.Helpers;
  26. namespace TEAMModelFunction
  27. {
  28. public class MonitorServicesBus
  29. {
  30. private readonly AzureCosmosFactory _azureCosmos;
  31. private readonly DingDing _dingDing;
  32. private readonly AzureStorageFactory _azureStorage;
  33. private readonly AzureRedisFactory _azureRedis;
  34. private readonly AzureServiceBusFactory _serviceBus;
  35. private readonly Option _option;
  36. private readonly NotificationService _notificationService;
  37. private readonly IConfiguration _configuration;
  38. public MonitorServicesBus(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, AzureServiceBusFactory serviceBus, IOptionsSnapshot<Option> option, NotificationService notificationService, IConfiguration configuration)
  39. {
  40. _azureCosmos = azureCosmos;
  41. _dingDing = dingDing;
  42. _azureStorage = azureStorage;
  43. _azureRedis = azureRedis;
  44. _serviceBus = serviceBus;
  45. _option = option?.Value;
  46. _notificationService = notificationService;
  47. _configuration = configuration;
  48. }
  49. [FunctionName("Exam")]
  50. public async Task ExamFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "exam", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  51. {
  52. try
  53. {
  54. var json = JsonDocument.Parse(msg);
  55. json.RootElement.TryGetProperty("id", out JsonElement id);
  56. json.RootElement.TryGetProperty("progress", out JsonElement progress);
  57. json.RootElement.TryGetProperty("code", out JsonElement code);
  58. //Dictionary<string, object> keyValuePairs = mySbMsg.ToObject<Dictionary<string, object>>();
  59. var client = _azureCosmos.GetCosmosClient();
  60. ExamInfo exam = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"{code}"));
  61. exam.progress = progress.ToString();
  62. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(exam, id.ToString(), new PartitionKey($"{code}"));
  63. }
  64. catch (CosmosException)
  65. {
  66. }
  67. catch (Exception ex)
  68. {
  69. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ExamBus()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  70. }
  71. }
  72. [FunctionName("Vote")]
  73. public async Task VoteFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "vote", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  74. {
  75. try
  76. {
  77. var jsonMsg = JsonDocument.Parse(msg);
  78. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  79. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  80. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  81. var client = _azureCosmos.GetCosmosClient();
  82. Vote vote = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Vote>(id.ToString(), new PartitionKey($"{code}"));
  83. vote.progress = progress.ToString();
  84. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(vote, id.ToString(), new PartitionKey($"{code}"));
  85. }
  86. catch (CosmosException)
  87. {
  88. }
  89. catch (Exception ex)
  90. {
  91. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,VoteBus()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  92. }
  93. }
  94. [FunctionName("Correct")]
  95. public async Task CorrectFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "correct", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  96. {
  97. try
  98. {
  99. var jsonMsg = JsonDocument.Parse(msg);
  100. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  101. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  102. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  103. var client = _azureCosmos.GetCosmosClient();
  104. Correct correct = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Correct>(id.ToString(), new PartitionKey($"{code}"));
  105. correct.progress = progress.ToString();
  106. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(correct, id.ToString(), new PartitionKey($"{code}"));
  107. }
  108. catch (CosmosException)
  109. {
  110. }
  111. catch (Exception ex)
  112. {
  113. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Correct()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  114. }
  115. }
  116. [FunctionName("Survey")]
  117. public async Task SurveyFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "survey", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  118. {
  119. try
  120. {
  121. var jsonMsg = JsonDocument.Parse(msg);
  122. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  123. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  124. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  125. //Dictionary<string, object> keyValuePairs = mySbMsg.ToObject<Dictionary<string, object>>();
  126. var client = _azureCosmos.GetCosmosClient();
  127. Survey survey = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Survey>(id.ToString(), new PartitionKey($"{code}"));
  128. survey.progress = progress.ToString();
  129. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(survey, id.ToString(), new PartitionKey($"{code}"));
  130. }
  131. catch (CosmosException)
  132. {
  133. }
  134. catch (Exception ex)
  135. {
  136. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,SurveyBus()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  137. }
  138. }
  139. [FunctionName("Homework")]
  140. public async Task HomeworkFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "homework", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  141. {
  142. try
  143. {
  144. var jsonMsg = JsonDocument.Parse(msg);
  145. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  146. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  147. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  148. var client = _azureCosmos.GetCosmosClient();
  149. Homework homework = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Homework>(id.ToString(), new PartitionKey($"{code}"));
  150. homework.progress = progress.ToString();
  151. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(homework, id.ToString(), new PartitionKey($"{code}"));
  152. }
  153. catch (CosmosException ) {
  154. }
  155. catch (Exception ex)
  156. {
  157. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Homework()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  158. }
  159. }
  160. [FunctionName("Study")]
  161. public async Task StudyFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "study", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  162. {
  163. try
  164. {
  165. var jsonMsg = JsonDocument.Parse(msg);
  166. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  167. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  168. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  169. var client = _azureCosmos.GetCosmosClient();
  170. Study study = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Study>(id.ToString(), new PartitionKey($"{code}"));
  171. study.progress = progress.ToString();
  172. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(study, id.ToString(), new PartitionKey($"{code}"));
  173. }
  174. catch (CosmosException)
  175. {
  176. }
  177. catch (Exception ex)
  178. {
  179. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Study()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  180. }
  181. }
  182. [FunctionName("ExamLite")]
  183. public async Task ExamLiteFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "examlite", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  184. {
  185. try
  186. {
  187. var jsonMsg = JsonDocument.Parse(msg);
  188. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  189. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  190. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  191. var client = _azureCosmos.GetCosmosClient();
  192. ExamLite lite = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamLite>(id.ToString(), new PartitionKey($"{code}"));
  193. lite.progress = progress.ToString();
  194. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(lite, id.ToString(), new PartitionKey($"{code}"));
  195. }
  196. catch (CosmosException)
  197. {
  198. }
  199. catch (Exception ex)
  200. {
  201. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ExamLite()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  202. }
  203. }
  204. /// <summary>
  205. /// 根据容器的根目录刷新redis并获取redis的最新使用情况
  206. /// </summary>
  207. /// <param name="msg"></param>
  208. /// <returns></returns>
  209. [FunctionName("BlobRoot")]
  210. public async Task BlobRootFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "blobroot", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  211. {
  212. try
  213. {
  214. var jsonMsg = JsonDocument.Parse(msg);
  215. if (jsonMsg.RootElement.TryGetProperty("name", out JsonElement _name) && _name.ValueKind == JsonValueKind.String
  216. && jsonMsg.RootElement.TryGetProperty("root", out JsonElement root) && root.ValueKind == JsonValueKind.String)
  217. {
  218. //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Blob() 容器:触发变更,{jsonMsg.ToJsonString()}",
  219. // GroupNames.成都开发測試群組);
  220. List<Dictionary<string, double?>> list = new List<Dictionary<string, double?>>();
  221. string[] uls = System.Web.HttpUtility.UrlDecode($"{root}", Encoding.UTF8).Split("/");
  222. string u = !string.IsNullOrEmpty(uls[0]) ? uls[0] : uls[1];
  223. string name = $"{_name}";
  224. string lockKey = $"Blob:Lock:{name}:{u}";
  225. bool exist= await _azureRedis.GetRedisClient(8).KeyExistsAsync(lockKey);
  226. if (!exist)
  227. { ///key不存在则正常进行计算
  228. bool condition = false;
  229. TimeSpan timeSpan = new TimeSpan(DateTimeOffset.UtcNow.AddMinutes(5).Ticks);
  230. timeSpan = timeSpan - new TimeSpan(DateTimeOffset.UtcNow.Ticks);
  231. //准备处理Blob刷新时间
  232. long action = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  233. await _azureRedis.GetRedisClient(8).StringSetAsync(lockKey, action, expiry: timeSpan);
  234. await RefreshBlob(name, u);
  235. //将action 与Redis最新的时间进行比较,如果
  236. var rds = await CheckLockKey(lockKey, action);
  237. condition = rds.condition;
  238. exist = rds.exist;
  239. if (condition || !exist) {
  240. await RefreshBlob(name, u);
  241. }
  242. //使用 CancellationToken
  243. //while (condition || !exist)
  244. //{
  245. //}
  246. }
  247. else {
  248. ///key存在则,则刷新key对应的值
  249. TimeSpan timeSpan = new TimeSpan(DateTimeOffset.UtcNow.AddMinutes(5).Ticks);
  250. timeSpan = timeSpan - new TimeSpan(DateTimeOffset.UtcNow.Ticks);
  251. long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  252. await _azureRedis.GetRedisClient(8).StringSetAsync(lockKey, now, expiry: timeSpan);
  253. }
  254. //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Blob() 容器:{name}使用:{u},文件分类:{list.ToJsonString()}",
  255. // GroupNames.成都开发測試群組);
  256. }
  257. }
  258. catch (Exception ex)
  259. {
  260. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Blob()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  261. }
  262. }
  263. private async Task<(bool condition,bool exist)> CheckLockKey(string lockKey,long nowTime) {
  264. //Redis的最新时间
  265. long newestTime = 0;
  266. RedisValue value = await _azureRedis.GetRedisClient(8).StringGetAsync(lockKey);
  267. if (value != default && !value.IsNullOrEmpty)
  268. {
  269. JsonElement record = value.ToString().ToObject<JsonElement>();
  270. if (record.TryGetInt64(out newestTime))
  271. {
  272. }
  273. }
  274. //说明key已经不存在
  275. if (newestTime == 0)
  276. {
  277. return (false, true);
  278. }
  279. //说明key存在
  280. else {
  281. //说明Redis记录了最新的时间戳
  282. if (nowTime != newestTime)
  283. {
  284. return (true, false);
  285. }
  286. //时间相同,没有被再次记录最新的时间戳
  287. else
  288. {
  289. await _azureRedis.GetRedisClient(8).KeyDeleteAsync(lockKey);
  290. return (false, true);
  291. }
  292. }
  293. }
  294. private async Task RefreshBlob(string name ,string u) {
  295. long statr = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  296. var client = _azureStorage.GetBlobContainerClient(name);
  297. var size = await client.GetBlobsSize(u);
  298. await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{name}", u);
  299. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", u, size.HasValue ? size.Value : 0);
  300. var scores = await _azureRedis.GetRedisClient(8).SortedSetRangeByRankWithScoresAsync($"Blob:Catalog:{name}");
  301. double blobsize = 0;
  302. if (scores != default && scores != null)
  303. {
  304. foreach (var score in scores)
  305. {
  306. blobsize = blobsize + score.Score;
  307. }
  308. }
  309. await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", new RedisValue(name), new RedisValue($"{blobsize}"));
  310. long end = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  311. long dis = (end - statr)/1000;
  312. long timeout = 10;
  313. if (dis> timeout) {
  314. await _dingDing.SendBotMsg($"ServiceBus,RefreshBlob:空间计算已经超过{timeout}秒\n容器名:{name}\n文件夹:{u}\n计算时长:{dis}", GroupNames.醍摩豆服務運維群組);
  315. }
  316. }
  317. /// <summary>
  318. /// 完善课程变更,StuListChange, originCode是学校编码 则表示名单是学校自定义名单,如果是tmdid则表示醍摩豆的私有名单,scope=school,private。
  319. /// </summary>
  320. /// <data msg>
  321. /// CourseChange
  322. ///// </data>
  323. /// <param name="msg"></param>
  324. /// <returns></returns>
  325. [FunctionName("TeacherTrainChange")]
  326. public async Task TeacherTrainChangeFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "teacher-train-change", Connection = "Azure:ServiceBus:ConnectionString")] string msg) {
  327. try
  328. {
  329. // await _dingDing.SendBotMsg($"teacher-train-change\n{msg}",GroupNames.成都开发測試群組);
  330. TeacherTrainChange change = msg.ToObject<TeacherTrainChange>();
  331. if (change.update == null || change.update.Count <= 0 || change.tmdids.IsEmpty())
  332. {
  333. return;
  334. }
  335. var client = _azureCosmos.GetCosmosClient();
  336. string insql = $"where c.id in ({string.Join(",", change.tmdids.Select(x => $"'{x}'"))})";
  337. string selsql = $"select value(c) from c {insql} ";
  338. List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
  339. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<TeacherTrain>(queryText: selsql,
  340. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{change.school}") }))
  341. {
  342. teacherTrains.Add(item);
  343. }
  344. if (change.statistics != 1)
  345. {
  346. List<Task<ItemResponse<TeacherTrain>>> task = new List<Task<ItemResponse<TeacherTrain>>>();
  347. teacherTrains.ForEach(x =>
  348. {
  349. x.update.UnionWith(change.update);
  350. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<TeacherTrain>(x, x.id, new PartitionKey($"TeacherTrain-{change.school}")));
  351. });
  352. await task.TaskPage(5);
  353. var unchange = change.tmdids.Except(teacherTrains.Select(x => x.id));
  354. if (unchange != null)
  355. {
  356. task.Clear();
  357. unchange.ToList().ForEach(x =>
  358. {
  359. TeacherTrain teacherTrain = new TeacherTrain
  360. {
  361. pk = "TeacherTrain",
  362. id = x,
  363. code = $"TeacherTrain-{change.school}",
  364. tmdid = x,
  365. school = change.school,
  366. update = new HashSet<string> { StatisticsService.TeacherAbility,
  367. StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
  368. };
  369. teacherTrain.update.UnionWith(change.update);
  370. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<TeacherTrain>(teacherTrain, new PartitionKey($"TeacherTrain-{change.school}")));
  371. });
  372. await task.TaskPage(1);
  373. }
  374. }
  375. else
  376. {
  377. Area area = null;
  378. string sql = $"select value(c) from c where c.standard='{change.standard}'";
  379. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Area>(queryText: sql,
  380. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-Area") }))
  381. {
  382. area = item;
  383. }
  384. AreaSetting setting = null;
  385. if (area != null)
  386. {
  387. try
  388. {
  389. //优先找校级
  390. setting = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<AreaSetting>(change.school, new PartitionKey("AreaSetting"));
  391. }
  392. catch (CosmosException)
  393. {
  394. try
  395. {
  396. setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>(area.id, new PartitionKey("AreaSetting"));
  397. }
  398. catch (CosmosException)
  399. {
  400. setting = null;
  401. }
  402. }
  403. }
  404. if (setting == null)
  405. {
  406. setting = new AreaSetting
  407. {
  408. allTime = 50,
  409. classTime = 5,
  410. submitTime = 15,
  411. onlineTime = 20,
  412. offlineTime = 10,
  413. lessonMinutes = 45,
  414. };
  415. }
  416. List<Task<TeacherTrain>> task = new List<Task<TeacherTrain>>();
  417. teacherTrains.ForEach(x =>
  418. {
  419. x.update.UnionWith(change.update);
  420. task.Add(StatisticsService.StatisticsTeacher(x, setting, area, client, null));
  421. });
  422. await task.TaskPage(1);
  423. var unchange = change.tmdids.Except(teacherTrains.Select(x => x.id));
  424. if (unchange != null)
  425. {
  426. task.Clear();
  427. unchange.ToList().ForEach(x =>
  428. {
  429. task.Add(StatisticsService.StatisticsTeacher(new TeacherTrain
  430. {
  431. pk = "TeacherTrain",
  432. id = x,
  433. code = $"TeacherTrain-{change.school}",
  434. tmdid = x,
  435. school = change.school,
  436. update = new HashSet<string> { StatisticsService.TeacherAbility,
  437. StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
  438. }, setting, area, client, null));
  439. });
  440. await task.TaskPage(1);
  441. }
  442. }
  443. }
  444. catch (CosmosException ex) {
  445. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-研修数据变更,重新统计-TeacherTrainChange\n{msg}\n{ex.Message}\n{ex.StackTrace}CosmosException{ex.Status}", GroupNames.成都开发測試群組);
  446. }
  447. catch (Exception ex)
  448. {
  449. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-研修数据变更,重新统计-TeacherTrainChange\n{msg}\n{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  450. }
  451. }
  452. /// <summary>
  453. /// 完善课程变更,StuListChange, originCode是学校编码 则表示名单是学校自定义名单,如果是tmdid则表示醍摩豆的私有名单,scope=school,private。
  454. /// </summary>
  455. /// <data msg>
  456. /// CourseChange
  457. ///// </data>
  458. /// <param name="msg"></param>
  459. /// <returns></returns>
  460. [FunctionName("GroupChange")]
  461. public async Task GroupChangeFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "group-change", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  462. {
  463. var client = _azureCosmos.GetCosmosClient();
  464. try
  465. {
  466. //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-名单成员变更-GroupChange\n{msg}", GroupNames.成都开发測試群組);
  467. var jsonMsg = JsonDocument.Parse(msg);
  468. GroupChange groupChange = msg.ToObject<GroupChange>();
  469. //名单变动修改学生课程关联信息
  470. //await StuListService.FixStuCourse(client, stuListChange);
  471. //Vote投票 Survey问卷 Exam评测 Learn学习活动 Homework作业活动
  472. //名单变动修改学生问卷关联信息
  473. await ActivityService.FixActivity(client, _dingDing, groupChange, "Survey");
  474. //名单变动修改学生投票关联信息
  475. await ActivityService.FixActivity(client, _dingDing, groupChange, "Vote");
  476. //名单变动修改学生评测关联信息
  477. await ActivityService.FixActivity(client, _dingDing, groupChange, "Exam");
  478. //名单变动修改学生研修关联信息
  479. await ActivityService.FixActivity(client, _dingDing, groupChange, "Study");
  480. //名单变动修改学生简易评测关联信息
  481. await ActivityService.FixActivity(client, _dingDing, groupChange, "ExamLite");
  482. //TODO学习活动
  483. //await FixActivity(client, stuListChange, "Learn");
  484. //名单变动修改学生作业活动信息
  485. await ActivityService.FixActivity(client, _dingDing, groupChange, "Homework");
  486. if (groupChange.type == null || !groupChange.type.Equals("research") || !groupChange.type.Equals("yxtrain")|| !groupChange.type.Equals("activity"))
  487. {
  488. //课程名单变动修改学生课程关联信息
  489. await ActivityService.FixStuCourse(client, _dingDing, groupChange);
  490. }
  491. }
  492. catch (Exception ex)
  493. {
  494. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-GroupChange-GroupChange\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.成都开发測試群組);
  495. }
  496. }
  497. [FunctionName("ItemCond")]
  498. public async Task ItemCondFunc([ServiceBusTrigger("%Azure:ServiceBus:ItemCondQueue%", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  499. {
  500. try
  501. {
  502. var client = _azureCosmos.GetCosmosClient();
  503. var jsonMsg = JsonDocument.Parse(msg);
  504. List<ItemCondDto> itemCondDtos = msg.ToObject<List<ItemCondDto>>();
  505. foreach (var itemCondDto in itemCondDtos)
  506. {
  507. if (itemCondDto.scope.Equals("school")) {
  508. ItemCond itemCond = null;
  509. List<ItemInfo> items = new List<ItemInfo>();
  510. var queryslt = $"SELECT c.gradeIds,c.subjectId,c.periodId,c.type,c.level,c.field ,c.scope FROM c where c.periodId='{itemCondDto.filed}' and c.pid= null ";
  511. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{itemCondDto.key}") }))
  512. {
  513. items.Add(item);
  514. }
  515. itemCond = new ItemCond()
  516. {
  517. id = $"{itemCondDto.filed}",
  518. code = $"ItemCond-{itemCondDto.key}",
  519. pk = "ItemCond",
  520. ttl = -1,
  521. count = items.Count,
  522. grades = new List<GradeCount>(),
  523. subjects = new List<SubjectCount>()
  524. };
  525. items.ForEach(z =>
  526. {
  527. if (!string.IsNullOrEmpty(z.type)) {
  528. ItemService.CountItemCond(z, null, itemCond);
  529. }
  530. });
  531. await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:{itemCondDto.key}", $"{itemCondDto.filed}", itemCond.ToJsonString());
  532. }
  533. else
  534. {
  535. ItemCond itemCond = null;
  536. List<ItemInfo> items = new List<ItemInfo>();
  537. var queryslt = $"SELECT c.gradeIds,c.subjectId,c.periodId,c.type,c.level,c.field ,c.scope FROM c where c.pid= null ";
  538. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{itemCondDto.filed}") }))
  539. {
  540. items.Add(item);
  541. }
  542. itemCond = new ItemCond() { id = $"{itemCondDto.filed}", code = $"ItemCond", pk = "ItemCond", ttl = -1, count = items.Count };
  543. items.ForEach(z =>
  544. {
  545. if (!string.IsNullOrEmpty(z.type))
  546. {
  547. ItemService.CountItemCond(z, null, itemCond);
  548. }
  549. });
  550. await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:ItemCond", $"{itemCondDto.filed}", itemCond.ToJsonString());
  551. }
  552. }
  553. }
  554. catch (CosmosException ex )
  555. {
  556. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ItemCond()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  557. }
  558. catch (Exception ex)
  559. {
  560. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ItemCond()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  561. }
  562. }
  563. //更新產品一覽表
  564. [FunctionName("Product")]
  565. public async Task ProductFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "product", Connection = "Azure:ServiceBus:ConnectionString")] string msg, ILogger log)
  566. {
  567. try
  568. {
  569. var jsonMsg = JsonDocument.Parse(msg);
  570. jsonMsg.RootElement.TryGetProperty("method", out JsonElement method);
  571. jsonMsg.RootElement.TryGetProperty("schoolId", out JsonElement schoolId);
  572. jsonMsg.RootElement.TryGetProperty("prodCode", out JsonElement prodCode);
  573. jsonMsg.RootElement.TryGetProperty("prodId", out JsonElement prodId);
  574. var client = _azureCosmos.GetCosmosClient();
  575. string strQuery = string.Empty;
  576. //取得所有學校產品
  577. ////序號
  578. List<SchoolProductSumData> serialsProductSumOrg = new List<SchoolProductSumData>();
  579. strQuery = $"SELECT * FROM c WHERE c.dataType = 'serial'";
  580. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
  581. {
  582. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  583. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  584. {
  585. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  586. {
  587. SchoolProductSerial serialInfo = obj.ToObject<SchoolProductSerial>();
  588. SchoolProductSumData serialProd = serialsProductSumOrg.Where(sp => sp.prodCode == serialInfo.prodCode).FirstOrDefault();
  589. if(serialProd == null)
  590. {
  591. SchoolProductSumData serialProdAdd = new SchoolProductSumData();
  592. serialProdAdd.prodCode = serialInfo.prodCode;
  593. serialProdAdd.ids.Add(serialInfo.id);
  594. serialProdAdd.avaliable = serialProdAdd.ids.Count;
  595. serialsProductSumOrg.Add(serialProdAdd);
  596. }
  597. else
  598. {
  599. if(!serialProd.ids.Contains(serialInfo.id))
  600. {
  601. serialProd.ids.Add(serialInfo.id);
  602. }
  603. serialProd.avaliable = serialProd.ids.Count;
  604. }
  605. }
  606. }
  607. }
  608. ////服務
  609. List<SchoolProductSumData> servicesProductSumOrg = new List<SchoolProductSumData>();
  610. long timestampToday = DateTimeOffset.UtcNow.AddSeconds(1).ToUnixTimeSeconds(); //比現實時間延遲1秒
  611. strQuery = $"SELECT * FROM c WHERE c.dataType = 'service' AND c.startDate <= {timestampToday} AND {timestampToday} <= c.endDate AND c.ttl < 0"; //在授權期間、ttl < 0 才取
  612. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
  613. {
  614. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  615. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  616. {
  617. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  618. {
  619. SchoolProductService serviceInfo = obj.ToObject<SchoolProductService>();
  620. SchoolProductSumData serviceProd = servicesProductSumOrg.Where(sp => sp.prodCode == serviceInfo.prodCode).FirstOrDefault();
  621. if (serviceProd == null)
  622. {
  623. SchoolProductSumData serviceProdAdd = new SchoolProductSumData();
  624. serviceProdAdd.prodCode = serviceInfo.prodCode;
  625. serviceProdAdd.avaliable = 0;
  626. serviceProdAdd.ids.Add(serviceInfo.id);
  627. serviceProdAdd.avaliable += serviceInfo.number;
  628. servicesProductSumOrg.Add(serviceProdAdd);
  629. }
  630. else
  631. {
  632. if (!serviceProd.ids.Contains(serviceInfo.id))
  633. {
  634. serviceProd.ids.Add(serviceInfo.id);
  635. serviceProd.avaliable += serviceInfo.number;
  636. }
  637. }
  638. }
  639. }
  640. }
  641. ////服務產品特別對應項
  642. if (servicesProductSumOrg.Count > 0)
  643. {
  644. foreach (SchoolProductSumData servicesProductSumOrgRow in servicesProductSumOrg)
  645. {
  646. //更新學校空間
  647. if (servicesProductSumOrgRow.prodCode.Equals("IPALJ6NY"))
  648. {
  649. School school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{schoolId}", new PartitionKey("Base"));
  650. school.size = (servicesProductSumOrgRow.avaliable < 1) ? 1 : servicesProductSumOrgRow.avaliable;
  651. await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(school, $"{schoolId}", new PartitionKey("Base"));
  652. }
  653. }
  654. }
  655. ////硬體
  656. List<SchoolProductSumDataHard> hardsProductSumOrg = new List<SchoolProductSumDataHard>();
  657. strQuery = $"SELECT * FROM c WHERE c.dataType = 'hard'";
  658. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
  659. {
  660. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  661. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  662. {
  663. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  664. {
  665. SchoolProductHard hardInfo = obj.ToObject<SchoolProductHard>();
  666. SchoolProductSumData hardProd = hardsProductSumOrg.Where(sp => sp.prodCode == hardInfo.prodCode).FirstOrDefault();
  667. if (hardProd == null)
  668. {
  669. SchoolProductSumDataHard hardProdAdd = new SchoolProductSumDataHard();
  670. hardProdAdd.prodCode = hardInfo.prodCode;
  671. hardProdAdd.model = hardInfo.model;
  672. hardProdAdd.ids.Add(hardInfo.id);
  673. hardProdAdd.avaliable = hardProdAdd.ids.Count;
  674. hardsProductSumOrg.Add(hardProdAdd);
  675. }
  676. else
  677. {
  678. if (!hardProd.ids.Contains(hardInfo.id))
  679. {
  680. hardProd.ids.Add(hardInfo.id);
  681. }
  682. hardProd.avaliable = hardProd.ids.Count;
  683. }
  684. }
  685. }
  686. }
  687. //更新學校產品一覽表
  688. SchoolProductSum prodSum = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SchoolProductSum>(schoolId.ToString(), new PartitionKey($"ProductSum"));
  689. prodSum.serial = serialsProductSumOrg;
  690. prodSum.service = servicesProductSumOrg;
  691. prodSum.hard = hardsProductSumOrg;
  692. await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<SchoolProductSum>(prodSum, prodSum.id, new PartitionKey($"{prodSum.code}"));
  693. }
  694. catch (CosmosException ex)
  695. {
  696. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Product()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  697. }
  698. catch (Exception ex)
  699. {
  700. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Product()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  701. }
  702. }
  703. /// <summary>
  704. /// 批量复制文件
  705. /// </summary>
  706. /// <param name="msg"></param>
  707. /// <returns></returns>
  708. [FunctionName("CopyStandardFile")]
  709. public async Task BatchCopyBlobFunc([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "copy-standard-file", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  710. {
  711. try
  712. {
  713. //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-Blob复制文件-CopyStandardFile\n{msg}", GroupNames.成都开发測試群組);
  714. var jsonMsg = JsonDocument.Parse(msg);
  715. BatchCopyFile bIBatchCopyFile = msg.ToObject<BatchCopyFile>();
  716. //批量复制文件
  717. var result = await BatchCopyFileService.CopyFile(_dingDing, _azureStorage, bIBatchCopyFile);
  718. if (result == 200)
  719. {
  720. //发送消息实体
  721. Notification notification = new Notification
  722. {
  723. hubName = "hita",
  724. type = "msg",
  725. from = $"ies5:{_option.Location}:private",
  726. to = bIBatchCopyFile.tmdIds,
  727. label = $"{bIBatchCopyFile.codeKey}_finish",
  728. body = new { location = _option.Location, biz = $"{bIBatchCopyFile.codeKey}", tmdid = $"{bIBatchCopyFile.tmdid}", tmdname = $"{bIBatchCopyFile.tmdName}", status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
  729. expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
  730. };
  731. var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
  732. var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
  733. var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
  734. var location = _option.Location;
  735. await _notificationService.SendNotification(clientID, clientSecret, location, url, notification); //站内发送消息
  736. }
  737. }
  738. catch (Exception ex)
  739. {
  740. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-Blob复制文件-CopyStandardFile\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  741. }
  742. }
  743. }
  744. }