ActivityStudentService.cs 42 KB

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