ActivityStudentService.cs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text.Json;
  5. using System.Threading.Tasks;
  6. using TEAMModelOS.SDK.Models.Cosmos;
  7. using TEAMModelOS.SDK.Extension;
  8. using Azure.Cosmos;
  9. using TEAMModelOS.SDK.DI;
  10. using HTEXLib.COMM.Helpers;
  11. using System.Text;
  12. using TEAMModelOS.SDK.Models;
  13. using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
  14. using StackExchange.Redis;
  15. using TEAMModelOS.SDK.Models.Cosmos.Common;
  16. using TEAMModelOS.Models;
  17. using TEAMModelOS.SDK;
  18. namespace TEAMModelOS.SDK.Services
  19. {
  20. public static class ActivityStudentService
  21. {
  22. public static async Task<(int msgid, int taskStatus)> Decide(DingDing _dingDing, Option _option, JsonElement request, AzureCosmosFactory _azureCosmos, AzureRedisFactory _azureRedis,
  23. AzureStorageFactory _azureStorage, string userid, string school, string standard, AzureServiceBusFactory _serviceBus, Microsoft.Extensions.Configuration.IConfiguration _configuration)
  24. {
  25. Vote vote = null;
  26. DateTimeOffset now = DateTimeOffset.UtcNow;
  27. long curr = now.ToUnixTimeMilliseconds();
  28. byte msgid = 0;//0投票失败,1投票成功,2不在时间范围内,3不在发布范围内,4投票周期内重复投票,5周期内的可投票数不足,6未设置投票项
  29. int taskStatus = 0;
  30. //活动id
  31. if (!request.TryGetProperty("id", out JsonElement id))
  32. {
  33. return (msgid, -1);
  34. }
  35. //活动分区
  36. if (!request.TryGetProperty("code", out JsonElement code))
  37. {
  38. return (msgid, taskStatus);
  39. }
  40. Dictionary<string, int> option = new Dictionary<string, int>();
  41. if (request.TryGetProperty("option", out JsonElement joption))
  42. {
  43. option = joption.ToObject<Dictionary<string, int>>();
  44. if (option.IsEmpty())
  45. {
  46. msgid = 6;
  47. return (msgid, -1);
  48. }
  49. }
  50. else
  51. {
  52. return (msgid, -1);
  53. }
  54. try
  55. {
  56. //1.再次检查投票
  57. var client = _azureCosmos.GetCosmosClient();
  58. ///TODO 检查是否在投票范围内,包括在tmdids 及班级 但是需要处理认证金钥中的班级问题
  59. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<Vote>(queryText: $"select c.id,c.code ,c.school,c.creatorId,c.scope , c.progress,c.times,c.voteNum,c.startTime,c.endTime from c where c.id = '{id}'",
  60. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
  61. {
  62. vote = item;
  63. break;
  64. }
  65. if (vote != null)
  66. {
  67. //判断投票时间是否在起止时间内
  68. if (curr >= vote.startTime && curr <= vote.endTime)
  69. {
  70. string endField = null;
  71. string Field = "";
  72. var endDtae = DateTimeOffset.FromUnixTimeMilliseconds(vote.endTime);
  73. RedisValue value;
  74. switch (vote.times)
  75. {
  76. case "once":
  77. // //如果是只能投票一次的活动则直接获取Redis的第一条 只能投一次
  78. Field = $"{userid}-once";
  79. HashEntry[] values = _azureRedis.GetRedisClient(8).HashGetAll($"Vote:Record:{vote.id}");
  80. if (values != null && values.Length > 0)
  81. {
  82. value = new RedisValue();
  83. foreach (var val in values)
  84. {
  85. if (val.Name.ToString() == Field)
  86. {
  87. value = val.Value;
  88. break;
  89. }
  90. }
  91. msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times, "once");
  92. }
  93. else
  94. {
  95. msgid = await VoteIng(vote, new RedisValue(), msgid, option, Field, curr, _azureRedis, userid, vote.times, "once");
  96. }
  97. if (msgid == 1) { taskStatus = 1; }
  98. break;
  99. case "day": //周期内每天
  100. Field = $"{userid}-day-{now.ToString("yyyyMMdd")}";
  101. endField = $"{userid}-day-{endDtae.ToString("yyyyMMdd")}";
  102. if (Field.Equals(endField))
  103. {
  104. taskStatus = 1;
  105. }
  106. value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
  107. msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times, now.ToString("yyyyMMdd"));
  108. break;
  109. case "week": //自然周
  110. int week = GetWeek(now);
  111. int endweek = GetWeek(endDtae);
  112. Field = $"{userid}-week-{now.ToString("yyyy")}{week}";
  113. endField = $"{userid}-week-{endDtae.ToString("yyyy")}{endweek}";
  114. if (Field.Equals(endField))
  115. {
  116. taskStatus = 1;
  117. }
  118. value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
  119. msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times, $"{now.ToString("yyyy")}{week}");
  120. break;
  121. case "month": //月份
  122. Field = $"{userid}-month-{now.ToString("yyyyMM")}";
  123. endField = $"{userid}-month-{endDtae.ToString("yyyyMM")}";
  124. if (Field.Equals(endField))
  125. {
  126. taskStatus = 1;
  127. }
  128. value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
  129. msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times, now.ToString("yyyyMM"));
  130. break;
  131. case "year"://年份
  132. Field = $"{userid}-year-{now.ToString("yyyy")}";
  133. endField = $"{userid}-year-{endDtae.ToString("yyyy")}";
  134. if (Field.Equals(endField))
  135. {
  136. taskStatus = 1;
  137. }
  138. value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
  139. msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times, now.ToString("yyyy"));
  140. break;
  141. }
  142. }
  143. else
  144. {
  145. msgid = 2;
  146. }
  147. try
  148. {
  149. if (!string.IsNullOrEmpty(school))
  150. {
  151. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuActivity>(vote.id, new PartitionKey($"Activity-{school}-{userid}"));
  152. activity.taskStatus = taskStatus;
  153. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuActivity>(activity, vote.id, new PartitionKey($"Activity-{school}-{userid}"));
  154. }
  155. else
  156. {
  157. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuActivity>(vote.id, new PartitionKey($"Activity-{userid}"));
  158. activity.taskStatus = taskStatus;
  159. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuActivity>(activity, vote.id, new PartitionKey($"Activity-{userid}"));
  160. }
  161. }
  162. catch (CosmosException ex)
  163. {
  164. if (ex.Status == 404)
  165. {
  166. try
  167. {
  168. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuActivity>(vote.id, new PartitionKey($"Activity-{userid}"));
  169. activity.taskStatus = taskStatus;
  170. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuActivity>(activity, vote.id, new PartitionKey($"Activity-{userid}"));
  171. }
  172. catch (CosmosException cex)
  173. {
  174. try
  175. {
  176. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<StuActivity>(vote.id, new PartitionKey($"Activity-{userid}"));
  177. activity.taskStatus = taskStatus;
  178. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<StuActivity>(activity, vote.id, new PartitionKey($"Activity-{userid}"));
  179. if (!string.IsNullOrEmpty(standard) && !string.IsNullOrEmpty(school))
  180. {
  181. await StatisticsService.SendServiceBus(($"{standard}", new List<string> { $"{userid}" }, $"{school}", new List<string> { StatisticsService.TeacherVote }, 0), _configuration, _serviceBus, client);
  182. }
  183. }
  184. catch (CosmosException cosex)
  185. {
  186. taskStatus = -1;
  187. }
  188. }
  189. }
  190. }
  191. }
  192. else
  193. {
  194. return (msgid, -1);
  195. }
  196. }
  197. catch (Exception ex)
  198. {
  199. await _dingDing.SendBotMsg($"OS,{_option.Location},common/delete-activity\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
  200. throw new Exception(ex.StackTrace);
  201. }
  202. if (msgid == 1 && vote != null)
  203. {
  204. string blobcntr = null;
  205. if (vote.scope.Equals("school"))
  206. {
  207. blobcntr = vote.school;
  208. }
  209. else
  210. {
  211. blobcntr = vote.creatorId;
  212. }
  213. //获取投票活动的所有投票记录
  214. var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Vote:Record:{vote.id}");
  215. //获取投票活动的选项及投票数
  216. var counts = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Vote:Count:{vote.id}");
  217. List<dynamic> countcds = new List<dynamic>();
  218. if (counts != null && counts.Length > 0)
  219. {
  220. foreach (var count in counts)
  221. {
  222. countcds.Add(new { code = count.Element.ToString(), count = (int)count.Score });
  223. }
  224. }
  225. List<Task<string>> tasks = new List<Task<string>>();
  226. List<VoteRecord> recordsBlob = new List<VoteRecord>();
  227. foreach (var rcd in records)
  228. {
  229. var value = rcd.Value.ToString().ToObject<VoteRecord>();
  230. recordsBlob.Add(value);
  231. }
  232. //分组每个人的
  233. var gp = recordsBlob.GroupBy(x => x.userid).Select(x => new { key = x.Key, list = x.ToList() });
  234. var userdata = gp.Where(x => x.key.Equals(userid)).FirstOrDefault();
  235. if (userdata != null)
  236. {
  237. tasks.Add(_azureStorage.UploadFileByContainer(blobcntr, userdata.list.ToJsonString(), "vote", $"{vote.id}/urecord/{userdata.key}.json"));
  238. }
  239. //处理活动方的记录,
  240. string url = $"/vote/{vote.id}/record.json";
  241. tasks.Add(_azureStorage.UploadFileByContainer(blobcntr, new { options = countcds, records = recordsBlob }.ToJsonString(), "vote", $"{vote.id}/record.json"));
  242. }
  243. return (msgid, taskStatus);
  244. }
  245. public static async Task<byte> VoteIng(Vote vote, RedisValue value, byte msgid, Dictionary<string, int> option, string Field, long curr, AzureRedisFactory _azureRedis, string userid, string times, string endpoint)
  246. {
  247. if (!value.IsNullOrEmpty)
  248. {
  249. VoteRecord record = value.ToString().ToObject<VoteRecord>();
  250. int addCount = 0;
  251. foreach (var op in option)
  252. {
  253. addCount += op.Value;
  254. }
  255. int crdCount = 0;
  256. foreach (var op in record.opt)
  257. {
  258. crdCount += op.Value;
  259. }
  260. //处理记录投票+当前设置的投票是否小于等于周期内最大投票数
  261. if (addCount + crdCount <= vote.voteNum)
  262. {
  263. foreach (var op in option)
  264. {
  265. if (record.opt.ContainsKey(op.Key))
  266. {
  267. record.opt[op.Key] = record.opt[op.Key] + op.Value;
  268. }
  269. else
  270. {
  271. record.opt.Add(op.Key, op.Value);
  272. }
  273. }
  274. record.time = curr;
  275. record.userid = userid;
  276. record.times = times;
  277. record.endpoint = endpoint;
  278. //保存投票记录
  279. bool status = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}", Field, record.ToJsonString());
  280. //单独保存每个人方便查询的记录
  281. bool stuallstatus = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}:{userid}", Field, record.ToJsonString());
  282. //当前投票分组计数存入活动的Redis
  283. foreach (var opt in option)
  284. {
  285. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Vote:Count:{vote.id}", opt.Key, opt.Value);
  286. }
  287. msgid = 1;
  288. }
  289. else
  290. {
  291. msgid = 5;
  292. }
  293. }
  294. else
  295. {
  296. if (option.Count <= vote.voteNum)
  297. {
  298. //保存投票记录
  299. VoteRecord record = new VoteRecord { opt = option, time = curr, userid = userid, times = times, endpoint = endpoint };
  300. bool status = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}", Field, record.ToJsonString());
  301. //单独保存每个人方便查询的记录
  302. bool stuallstatus = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}:{userid}", Field, record.ToJsonString());
  303. //当前投票分组计数存入活动的Redis
  304. foreach (var opt in option)
  305. {
  306. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Vote:Count:{vote.id}", opt.Key, opt.Value);
  307. }
  308. if (status)
  309. {
  310. msgid = 1;
  311. }
  312. }
  313. else
  314. {
  315. msgid = 5;
  316. }
  317. }
  318. return msgid;
  319. }
  320. /// <summary>
  321. /// 获取时间的在当年的第几周
  322. /// </summary>
  323. /// <param name="dt"></param>
  324. /// <returns></returns>
  325. public static int GetWeek(DateTimeOffset dt)
  326. {
  327. DateTimeOffset time = Convert.ToDateTime(dt.ToString("yyyy") + "-01-01");
  328. TimeSpan ts = dt - time;
  329. int iii = (int)time.DayOfWeek;
  330. int day = int.Parse(ts.TotalDays.ToString("F0"));
  331. if (iii == 0)
  332. {
  333. day--;
  334. }
  335. else
  336. {
  337. day = day - (7 - iii) - 1;
  338. }
  339. int week = ((day + 7) / 7) + 1;
  340. return week;
  341. }
  342. public static async Task<(List<StuActivity> datas, string continuationToken)> FindActivity(JsonElement request, string id, string school, AzureCosmosFactory _azureCosmos, AzureRedisFactory azureRedis)
  343. {
  344. if (string.IsNullOrWhiteSpace(id))
  345. {
  346. if (request.TryGetProperty("userid", out JsonElement userid))
  347. {
  348. if (!userid.ValueKind.Equals(JsonValueKind.Undefined) && !userid.ValueKind.Equals(JsonValueKind.Null) && userid.ValueKind.Equals(JsonValueKind.String))
  349. {
  350. id = userid.GetString();
  351. }
  352. }
  353. }
  354. if (string.IsNullOrWhiteSpace(school))
  355. {
  356. if (request.TryGetProperty("school", out JsonElement schooljson))
  357. {
  358. if (!schooljson.ValueKind.Equals(JsonValueKind.Undefined) && !schooljson.ValueKind.Equals(JsonValueKind.Null) && schooljson.ValueKind.Equals(JsonValueKind.String))
  359. {
  360. school = schooljson.GetString();
  361. }
  362. }
  363. }
  364. /// tmdid, schoolid
  365. var userType = "tmdid";
  366. if (request.TryGetProperty("userType", out JsonElement usertype))
  367. {
  368. if (!usertype.ValueKind.Equals(JsonValueKind.Undefined) && !usertype.ValueKind.Equals(JsonValueKind.Null) && usertype.ValueKind.Equals(JsonValueKind.String))
  369. {
  370. userType = usertype.GetString();
  371. }
  372. }
  373. string stimesql = "";
  374. //开始时间,默认最近三十天
  375. if (request.TryGetProperty("stime", out JsonElement stime))
  376. {
  377. if (!stime.ValueKind.Equals(JsonValueKind.Undefined) && !stime.ValueKind.Equals(JsonValueKind.Null) && stime.TryGetInt64(out long data))
  378. {
  379. stimesql = $" and c.startTime >= {data} ";
  380. }
  381. }
  382. string source = "";
  383. //评测类型
  384. if (request.TryGetProperty("source", out JsonElement sc))
  385. {
  386. source = $" and c.source = '{sc}' ";
  387. }
  388. string owner = "";
  389. //评测来源
  390. if (request.TryGetProperty("owner", out JsonElement element))
  391. {
  392. owner = $" and c.owner = '{element}' ";
  393. }
  394. string name = "";
  395. //评测来源
  396. if (request.TryGetProperty("name", out JsonElement jsonElement))
  397. {
  398. name = $" and Contains( c.name , '{jsonElement}') = true ";
  399. }
  400. //默认当前时间, 未开始的不能查询
  401. var etimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  402. string etimesql = $" and c.startTime <= {etimestamp} ";
  403. var typesql = "";
  404. if (request.TryGetProperty("type", out JsonElement type))
  405. {
  406. if (!type.ValueKind.Equals(JsonValueKind.Undefined) && !type.ValueKind.Equals(JsonValueKind.Null) && type.ValueKind.Equals(JsonValueKind.String))
  407. {
  408. typesql = $" and c.type='{type}' ";
  409. }
  410. }
  411. string continuationToken = default;
  412. //默认不指定返回大小
  413. int? topcout = null;
  414. if (request.TryGetProperty("count", out JsonElement jcount))
  415. {
  416. if (!jcount.ValueKind.Equals(JsonValueKind.Undefined) && !jcount.ValueKind.Equals(JsonValueKind.Null) && jcount.TryGetInt32(out int data))
  417. {
  418. topcout = data;
  419. }
  420. }
  421. //是否需要进行分页查询,默认不分页
  422. bool iscontinuation = false;
  423. if (topcout != null && topcout.Value > 0)
  424. {
  425. iscontinuation = true;
  426. }
  427. //如果指定了返回大小
  428. if (request.TryGetProperty("continuationToken", out JsonElement token))
  429. {
  430. //指定了cancellationToken continuationSchool
  431. if (!token.ValueKind.Equals(JsonValueKind.Null) && token.ValueKind.Equals(JsonValueKind.String))
  432. {
  433. continuationToken = token.GetString();
  434. }
  435. }
  436. //科目
  437. string joinSqlSubjects = "";
  438. string andSqlSubjects = "";
  439. if (request.TryGetProperty("subjects", out JsonElement jsubjects))
  440. {
  441. if (jsubjects.ValueKind is JsonValueKind.Array)
  442. {
  443. List<string> subjects = jsubjects.ToObject<List<string>>();
  444. if (subjects.IsNotEmpty())
  445. {
  446. joinSqlSubjects = " join A2 in c.subjects ";
  447. List<string> sqlList = new List<string>();
  448. subjects.ForEach(x => { sqlList.Add($" '{x}' "); });
  449. string sql = string.Join(" , ", sqlList);
  450. andSqlSubjects = $" and A2 in ({sql}) ";
  451. }
  452. }
  453. }
  454. List<StuActivity> datas = new List<StuActivity>();
  455. var client = _azureCosmos.GetCosmosClient();
  456. string containerId = "Student";
  457. string PartitionKey = "";
  458. if (!string.IsNullOrWhiteSpace(school) && userType.Equals("schoolid"))
  459. {
  460. containerId = "Student";
  461. PartitionKey = $"Activity-{school}-{id}";
  462. }
  463. else
  464. {
  465. containerId = "Student";
  466. PartitionKey = $"Activity-{id}";
  467. }
  468. string querySchool = $" SELECT distinct value c FROM c {joinSqlSubjects} where c.pk='Activity' {stimesql} {etimesql} {typesql} {andSqlSubjects} {source} {owner} {name} order by c.createTime desc";
  469. //查询数据归属学校的
  470. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, containerId).GetItemQueryStreamIterator(querySchool, continuationToken: continuationToken,
  471. requestOptions: new QueryRequestOptions() { MaxItemCount = topcout, PartitionKey = new PartitionKey(PartitionKey) }))
  472. {
  473. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  474. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  475. {
  476. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  477. {
  478. datas.Add(obj.ToObject<StuActivity>());
  479. }
  480. //如果需要分页则跳出
  481. if (iscontinuation)
  482. {
  483. continuationToken = item.GetContinuationToken();
  484. break;
  485. }
  486. }
  487. }
  488. /* List<(string id, HashSet<string> name)> cn = new();
  489. foreach (StuActivity activity in datas) {
  490. var cIds = activity.classIds;
  491. HashSet<string> name = new HashSet<string>();
  492. if (cIds.ToList().Count > 0)
  493. {
  494. List<GroupListDto> groups = await GroupListService.GetGroupListListids(client, _dingDing, cIds.ToList(), school);
  495. foreach (GroupListDto dto in groups)
  496. {
  497. name.Add(dto.name);
  498. }
  499. cn.Add((activity.id, name));
  500. }
  501. }
  502. //string SummarySql = " c.id,c.code,c.name,c.no,c.periodId,c.scope,c.school,c.creatorId,c.type,c.year,c.tcount,c.scount,c.leader ";
  503. datas.Select(item => new {
  504. item.name,
  505. item.classIds,
  506. cName = cn.Where(c =>c.id.Equals(item.id)).FirstOrDefault().name,
  507. item.code,
  508. item.createTime,
  509. item.creatorId,
  510. item.id,
  511. item.owner,
  512. item.endTime,
  513. item.startTime,
  514. item.pk,
  515. item.sStatus,
  516. item.school,
  517. item.scode,
  518. item.scope,
  519. item.source,
  520. item.subjects,
  521. item.taskStatus,
  522. item.type
  523. });*/
  524. return (datas, continuationToken);
  525. }
  526. public static async Task<(int msgid, int taskStatus)> Answer(DingDing _dingDing, Option _option, JsonElement request, AzureCosmosFactory _azureCosmos, AzureRedisFactory azureRedis, string userid, string school, AzureStorageFactory _azureStorage, string standard, AzureServiceBusFactory _serviceBus, Microsoft.Extensions.Configuration.IConfiguration _configuration)
  527. {
  528. DateTimeOffset now = DateTimeOffset.UtcNow;
  529. long curr = now.ToUnixTimeMilliseconds();
  530. int msgid = 0;//
  531. int taskStatus = 0;
  532. //活动id
  533. if (!request.TryGetProperty("id", out JsonElement id))
  534. {
  535. return (msgid, -1);
  536. }
  537. //活动分区
  538. if (!request.TryGetProperty("code", out JsonElement code))
  539. {
  540. return (msgid, -1);
  541. }
  542. try
  543. {
  544. //1.再次检查投票
  545. var client = _azureCosmos.GetCosmosClient();
  546. Survey survey = null;
  547. ///TODO 检查是否在投票范围内,包括在tmdids 及班级 但是需要处理认证金钥中的班级问题
  548. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<Survey>(queryText: $"select c.id,c.owner,c.scope, c.code ,c.creatorId,c.answers ,c.school , c.progress,c.times,c.startTime,c.endTime from c where c.id = '{id}'",
  549. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
  550. {
  551. survey = item;
  552. break;
  553. }
  554. if (survey != null)
  555. {
  556. //判断投票时间是否在起止时间内
  557. if (curr >= survey.startTime && curr <= survey.endTime)
  558. {
  559. if (request.TryGetProperty("record", out JsonElement _record))
  560. {
  561. var recs = _record.ToObject<List<List<string>>>();
  562. if (recs.IsNotEmpty() && recs.Count == survey.answers.Count)
  563. {
  564. //处理问卷调查表的每一题选项数
  565. // List<Task<string>> tasks = new List<Task<string>>();
  566. for (int index = 0; index < recs.Count; index++)
  567. {
  568. Dictionary<string, int> dict = new Dictionary<string, int>();
  569. if (recs[index].IsNotEmpty())
  570. {
  571. recs[index].ForEach(x =>
  572. {
  573. if (survey.answers[index].Contains(x))
  574. {
  575. if (dict.ContainsKey(x))
  576. {
  577. dict[x] = dict[x] + 1;
  578. }
  579. else
  580. {
  581. dict[x] = 1;
  582. }
  583. }
  584. else
  585. {
  586. if (dict.ContainsKey("other"))
  587. {
  588. dict["other"] = dict["other"] + 1;
  589. }
  590. else
  591. {
  592. dict["other"] = 1;
  593. }
  594. //这里暂不处理, 结算再处理other
  595. // tasks.Add(_azureStorage.UploadFileByContainer(survey.owner,new { other=x, userid, time =curr }.ToJsonString(), "survey", $"{survey.id}/other/{index}/{userid}.json", false));
  596. }
  597. });
  598. }
  599. var value = azureRedis.GetRedisClient(8).HashGet($"Survey:Record:{survey.id}", index);
  600. if (value != default && !value.IsNullOrEmpty)
  601. {
  602. Dictionary<string, int> dt = value.ToString().ToObject<Dictionary<string, int>>();
  603. foreach (var kp in dict)
  604. { //不建议放在reids
  605. if (dt.ContainsKey(kp.Key))
  606. {
  607. dt[kp.Key] = dt[kp.Key] + kp.Value;
  608. }
  609. else
  610. {
  611. dt.Add(kp.Key, kp.Value);
  612. }
  613. }
  614. await azureRedis.GetRedisClient(8).HashSetAsync($"Survey:Record:{survey.id}", index, dt.ToJsonString());
  615. }
  616. else
  617. {
  618. await azureRedis.GetRedisClient(8).HashSetAsync($"Survey:Record:{survey.id}", index, dict.ToJsonString());
  619. }
  620. }
  621. //处理other ,这里暂不处理, 结算再处理other
  622. //await Task.WhenAll(tasks);
  623. //保存当前提交人的记录
  624. string blobcntr = null;
  625. if (survey.scope.Equals("school"))
  626. {
  627. blobcntr = survey.school;
  628. }
  629. else
  630. {
  631. blobcntr = survey.creatorId;
  632. }
  633. await _azureStorage.UploadFileByContainer(blobcntr, new SurveyRecord { ans = recs, userid = userid, time = curr }.ToJsonString(), "survey", $"{survey.id}/urecord/{userid}.json");
  634. ///bgn 20210805 huanghb 实时结算
  635. await azureRedis.GetRedisClient(8).SetAddAsync($"Survey:Submit:{survey.id}", userid);
  636. var submits = await azureRedis.GetRedisClient(8).SetMembersAsync($"Survey:Submit:{survey.id}");
  637. List<dynamic> userids = new List<dynamic>();
  638. foreach (var submit in submits)
  639. {
  640. var value = submit.ToString();
  641. userids.Add(value);
  642. }
  643. List<QuestionRecord> questionRecords = new List<QuestionRecord>();
  644. //结算每道题的答题情况
  645. var ContainerClient = _azureStorage.GetBlobContainerClient(blobcntr);
  646. List<Task<string>> tasks = new List<Task<string>>();
  647. List<string> items = await ContainerClient.List($"survey/{survey.id}/urecord");
  648. List<SurveyRecord> surveyRecords = new List<SurveyRecord>();
  649. foreach (string item in items)
  650. {
  651. var Download = await _azureStorage.GetBlobContainerClient(blobcntr).GetBlobClient(item).DownloadAsync();
  652. var json = await JsonDocument.ParseAsync(Download.Value.Content);
  653. var Record = json.RootElement.ToObject<SurveyRecord>();
  654. surveyRecords.Add(Record);
  655. }
  656. for (int index = 0; index < survey.answers.Count; index++)
  657. {
  658. string url = $"{survey.id}/qrecord/{index}.json";
  659. QuestionRecord question = new QuestionRecord() { index = index };
  660. foreach (SurveyRecord record in surveyRecords)
  661. {
  662. if (record.ans.Count == survey.answers.Count)
  663. {
  664. foreach (var an in record.ans[index])
  665. {
  666. //
  667. if (question.opt.ContainsKey(an))
  668. {
  669. if (question.opt[an] != null)
  670. {
  671. question.opt[an].Add(record.userid);
  672. }
  673. else
  674. {
  675. question.opt[an] = new HashSet<string>() { record.userid };
  676. }
  677. }
  678. else
  679. {
  680. if (survey.answers[index].Contains(an))
  681. {
  682. //如果是客观题code
  683. question.opt.Add(an, new HashSet<string> { record.userid });
  684. }
  685. else
  686. {
  687. //如果不是客观code
  688. question.other[record.userid] = an;
  689. }
  690. }
  691. }
  692. }
  693. }
  694. questionRecords.Add(question);
  695. tasks.Add(_azureStorage.UploadFileByContainer(blobcntr, question.ToJsonString(), "survey", url));
  696. }
  697. var records = await azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}");
  698. List<dynamic> recds = new List<dynamic>();
  699. foreach (var rcd in records)
  700. {
  701. var value = rcd.Value.ToString().ToObject<JsonElement>();
  702. recds.Add(new { index = rcd.Name.ToString(), ans = value });
  703. }
  704. await Task.WhenAll(tasks);
  705. var cods = new { records = recds, userids, question = questionRecords, urecord = surveyRecords };
  706. //问卷整体情况
  707. await _azureStorage.UploadFileByContainer(blobcntr, cods.ToJsonString(), "survey", $"{survey.id}/record.json");
  708. ///end 20210805 huanghb 实时结算
  709. taskStatus = 1;
  710. msgid = 1;
  711. }
  712. else
  713. {
  714. //提交的作答不符合问卷的答案长度。
  715. msgid = 3;
  716. }
  717. }
  718. }
  719. else
  720. {
  721. msgid = 2;
  722. }
  723. try
  724. {
  725. if (!string.IsNullOrEmpty(school))
  726. {
  727. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuActivity>(survey.id, new PartitionKey($"Activity-{school}-{userid}"));
  728. activity.taskStatus = taskStatus;
  729. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuActivity>(activity, survey.id, new PartitionKey($"Activity-{school}-{userid}"));
  730. }
  731. else
  732. {
  733. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuActivity>(survey.id, new PartitionKey($"Activity-{userid}"));
  734. activity.taskStatus = taskStatus;
  735. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuActivity>(activity, survey.id, new PartitionKey($"Activity-{userid}"));
  736. }
  737. }
  738. catch (CosmosException ex)
  739. {
  740. if (ex.Status == 404)
  741. {
  742. try
  743. {
  744. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuActivity>(survey.id, new PartitionKey($"Activity-{userid}"));
  745. activity.taskStatus = taskStatus;
  746. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuActivity>(activity, survey.id, new PartitionKey($"Activity-{userid}"));
  747. }
  748. catch (CosmosException cex)
  749. {
  750. if (cex.Status == 404)
  751. {
  752. try
  753. {
  754. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<StuActivity>(survey.id, new PartitionKey($"Activity-{userid}"));
  755. activity.taskStatus = taskStatus;
  756. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<StuActivity>(activity, survey.id, new PartitionKey($"Activity-{userid}"));
  757. if (!string.IsNullOrEmpty(standard) && !string.IsNullOrEmpty(school))
  758. {
  759. await StatisticsService.SendServiceBus(($"{standard}", new List<string> { $"{userid}" }, $"{school}", new List<string> { StatisticsService.TeacherSurvey }, 0), _configuration, _serviceBus, client);
  760. }
  761. }
  762. catch (CosmosException cosex)
  763. {
  764. if (cosex.Status == 404)
  765. {
  766. taskStatus = -1;
  767. }
  768. }
  769. }
  770. }
  771. }
  772. }
  773. }
  774. else
  775. {
  776. return (msgid, -1);
  777. }
  778. }
  779. catch (Exception e)
  780. {
  781. throw new Exception(e.StackTrace);
  782. }
  783. return (msgid, taskStatus);
  784. }
  785. public class RdsRecord
  786. {
  787. public Dictionary<string, int> srecord { get; set; } = new Dictionary<string, int>();
  788. public Dictionary<string, string[]> urecord { get; set; } = new Dictionary<string, string[]>();
  789. }
  790. }
  791. }