ActivityStudentService.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  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}\n{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 token = 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_1))
  429. {
  430. //指定了cancellationToken continuationSchool
  431. if (!token_1.ValueKind.Equals(JsonValueKind.Null) && token_1.ValueKind.Equals(JsonValueKind.String))
  432. {
  433. token = token_1.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 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: token,
  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. //如果需要分页则跳出
  482. if (iscontinuation)
  483. {
  484. token = item.GetContinuationToken();
  485. break;
  486. }
  487. }
  488. List<StuActivity> results = datas.Where((x, i) => datas.FindIndex(z => z.id == x.id && z.code == x.code) == i).ToList();
  489. return (results, token);
  490. }
  491. 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)
  492. {
  493. DateTimeOffset now = DateTimeOffset.UtcNow;
  494. long curr = now.ToUnixTimeMilliseconds();
  495. int msgid = 0;//
  496. int taskStatus = 0;
  497. //活动id
  498. if (!request.TryGetProperty("id", out JsonElement id))
  499. {
  500. return (msgid, -1);
  501. }
  502. //活动分区
  503. if (!request.TryGetProperty("code", out JsonElement code))
  504. {
  505. return (msgid, -1);
  506. }
  507. try
  508. {
  509. //1.再次检查投票
  510. var client = _azureCosmos.GetCosmosClient();
  511. Survey survey = null;
  512. ///TODO 检查是否在投票范围内,包括在tmdids 及班级 但是需要处理认证金钥中的班级问题
  513. 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}'",
  514. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
  515. {
  516. survey = item;
  517. break;
  518. }
  519. if (survey != null)
  520. {
  521. //判断投票时间是否在起止时间内
  522. if (curr >= survey.startTime && curr <= survey.endTime)
  523. {
  524. if (request.TryGetProperty("record", out JsonElement _record))
  525. {
  526. var recs = _record.ToObject<List<List<string>>>();
  527. if (recs.IsNotEmpty() && recs.Count == survey.answers.Count)
  528. {
  529. //处理问卷调查表的每一题选项数
  530. // List<Task<string>> tasks = new List<Task<string>>();
  531. for (int index = 0; index < recs.Count; index++)
  532. {
  533. Dictionary<string, int> dict = new Dictionary<string, int>();
  534. if (recs[index].IsNotEmpty())
  535. {
  536. recs[index].ForEach(x =>
  537. {
  538. if (survey.answers[index].Contains(x))
  539. {
  540. if (dict.ContainsKey(x))
  541. {
  542. dict[x] = dict[x] + 1;
  543. }
  544. else
  545. {
  546. dict[x] = 1;
  547. }
  548. }
  549. else
  550. {
  551. if (dict.ContainsKey("other"))
  552. {
  553. dict["other"] = dict["other"] + 1;
  554. }
  555. else
  556. {
  557. dict["other"] = 1;
  558. }
  559. //这里暂不处理, 结算再处理other
  560. // tasks.Add(_azureStorage.UploadFileByContainer(survey.owner,new { other=x, userid, time =curr }.ToJsonString(), "survey", $"{survey.id}/other/{index}/{userid}.json", false));
  561. }
  562. });
  563. }
  564. var value = azureRedis.GetRedisClient(8).HashGet($"Survey:Record:{survey.id}", index);
  565. if (value != default && !value.IsNullOrEmpty)
  566. {
  567. Dictionary<string, int> dt = value.ToString().ToObject<Dictionary<string, int>>();
  568. foreach (var kp in dict)
  569. { //不建议放在reids
  570. if (dt.ContainsKey(kp.Key))
  571. {
  572. dt[kp.Key] = dt[kp.Key] + kp.Value;
  573. }
  574. else
  575. {
  576. dt.Add(kp.Key, kp.Value);
  577. }
  578. }
  579. await azureRedis.GetRedisClient(8).HashSetAsync($"Survey:Record:{survey.id}", index, dt.ToJsonString());
  580. }
  581. else
  582. {
  583. await azureRedis.GetRedisClient(8).HashSetAsync($"Survey:Record:{survey.id}", index, dict.ToJsonString());
  584. }
  585. }
  586. //处理other ,这里暂不处理, 结算再处理other
  587. //await Task.WhenAll(tasks);
  588. //保存当前提交人的记录
  589. string blobcntr = null;
  590. if (survey.scope.Equals("school"))
  591. {
  592. blobcntr = survey.school;
  593. }
  594. else
  595. {
  596. blobcntr = survey.creatorId;
  597. }
  598. await _azureStorage.UploadFileByContainer(blobcntr, new SurveyRecord { ans = recs, userid = userid, time = curr }.ToJsonString(), "survey", $"{survey.id}/urecord/{userid}.json");
  599. ///bgn 20210805 huanghb 实时结算
  600. await azureRedis.GetRedisClient(8).SetAddAsync($"Survey:Submit:{survey.id}", userid);
  601. var submits = await azureRedis.GetRedisClient(8).SetMembersAsync($"Survey:Submit:{survey.id}");
  602. List<dynamic> userids = new List<dynamic>();
  603. foreach (var submit in submits)
  604. {
  605. var value = submit.ToString();
  606. userids.Add(value);
  607. }
  608. List<QuestionRecord> questionRecords = new List<QuestionRecord>();
  609. //结算每道题的答题情况
  610. var ContainerClient = _azureStorage.GetBlobContainerClient(blobcntr);
  611. List<Task<string>> tasks = new List<Task<string>>();
  612. List<string> items = await ContainerClient.List($"survey/{survey.id}/urecord");
  613. List<SurveyRecord> surveyRecords = new List<SurveyRecord>();
  614. foreach (string item in items)
  615. {
  616. var Download = await _azureStorage.GetBlobContainerClient(blobcntr).GetBlobClient(item).DownloadAsync();
  617. var json = await JsonDocument.ParseAsync(Download.Value.Content);
  618. var Record = json.RootElement.ToObject<SurveyRecord>();
  619. surveyRecords.Add(Record);
  620. }
  621. for (int index = 0; index < survey.answers.Count; index++)
  622. {
  623. string url = $"{survey.id}/qrecord/{index}.json";
  624. QuestionRecord question = new QuestionRecord() { index = index };
  625. foreach (SurveyRecord record in surveyRecords)
  626. {
  627. if (record.ans.Count == survey.answers.Count)
  628. {
  629. foreach (var an in record.ans[index])
  630. {
  631. //
  632. if (question.opt.ContainsKey(an))
  633. {
  634. if (question.opt[an] != null)
  635. {
  636. question.opt[an].Add(record.userid);
  637. }
  638. else
  639. {
  640. question.opt[an] = new HashSet<string>() { record.userid };
  641. }
  642. }
  643. else
  644. {
  645. if (survey.answers[index].Contains(an))
  646. {
  647. //如果是客观题code
  648. question.opt.Add(an, new HashSet<string> { record.userid });
  649. }
  650. else
  651. {
  652. //如果不是客观code
  653. question.other[record.userid] = an;
  654. }
  655. }
  656. }
  657. }
  658. }
  659. questionRecords.Add(question);
  660. tasks.Add(_azureStorage.UploadFileByContainer(blobcntr, question.ToJsonString(), "survey", url));
  661. }
  662. var records = await azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}");
  663. List<dynamic> recds = new List<dynamic>();
  664. foreach (var rcd in records)
  665. {
  666. var value = rcd.Value.ToString().ToObject<JsonElement>();
  667. recds.Add(new { index = rcd.Name.ToString(), ans = value });
  668. }
  669. await Task.WhenAll(tasks);
  670. var cods = new { records = recds, userids, question = questionRecords, urecord = surveyRecords };
  671. //问卷整体情况
  672. await _azureStorage.UploadFileByContainer(blobcntr, cods.ToJsonString(), "survey", $"{survey.id}/record.json");
  673. ///end 20210805 huanghb 实时结算
  674. taskStatus = 1;
  675. msgid = 1;
  676. }
  677. else
  678. {
  679. //提交的作答不符合问卷的答案长度。
  680. msgid = 3;
  681. }
  682. }
  683. }
  684. else
  685. {
  686. msgid = 2;
  687. }
  688. try
  689. {
  690. if (!string.IsNullOrEmpty(school))
  691. {
  692. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuActivity>(survey.id, new PartitionKey($"Activity-{school}-{userid}"));
  693. activity.taskStatus = taskStatus;
  694. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuActivity>(activity, survey.id, new PartitionKey($"Activity-{school}-{userid}"));
  695. }
  696. else
  697. {
  698. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuActivity>(survey.id, new PartitionKey($"Activity-{userid}"));
  699. activity.taskStatus = taskStatus;
  700. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuActivity>(activity, survey.id, new PartitionKey($"Activity-{userid}"));
  701. }
  702. }
  703. catch (CosmosException ex)
  704. {
  705. if (ex.Status == 404)
  706. {
  707. try
  708. {
  709. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuActivity>(survey.id, new PartitionKey($"Activity-{userid}"));
  710. activity.taskStatus = taskStatus;
  711. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuActivity>(activity, survey.id, new PartitionKey($"Activity-{userid}"));
  712. }
  713. catch (CosmosException cex)
  714. {
  715. if (cex.Status == 404)
  716. {
  717. try
  718. {
  719. StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<StuActivity>(survey.id, new PartitionKey($"Activity-{userid}"));
  720. activity.taskStatus = taskStatus;
  721. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<StuActivity>(activity, survey.id, new PartitionKey($"Activity-{userid}"));
  722. if (!string.IsNullOrEmpty(standard) && !string.IsNullOrEmpty(school))
  723. {
  724. await StatisticsService.SendServiceBus(($"{standard}", new List<string> { $"{userid}" }, $"{school}", new List<string> { StatisticsService.TeacherSurvey }, 0), _configuration, _serviceBus, client);
  725. }
  726. }
  727. catch (CosmosException cosex)
  728. {
  729. if (cosex.Status == 404)
  730. {
  731. taskStatus = -1;
  732. }
  733. }
  734. }
  735. }
  736. }
  737. }
  738. }
  739. else
  740. {
  741. return (msgid, -1);
  742. }
  743. }
  744. catch (Exception e)
  745. {
  746. throw new Exception(e.StackTrace);
  747. }
  748. return (msgid, taskStatus);
  749. }
  750. public class RdsRecord
  751. {
  752. public Dictionary<string, int> srecord { get; set; } = new Dictionary<string, int>();
  753. public Dictionary<string, string[]> urecord { get; set; } = new Dictionary<string, string[]>();
  754. }
  755. }
  756. }