ActivityStudentService.cs 47 KB

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