SurveyController.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. using Azure.Cosmos;
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.AspNetCore.Mvc;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IdentityModel.Tokens.Jwt;
  7. using System.Text;
  8. using System.Text.Json;
  9. using System.Threading.Tasks;
  10. using TEAMModelOS.Models.Dto;
  11. using TEAMModelOS.SDK.Models;
  12. using TEAMModelOS.SDK;
  13. using TEAMModelOS.SDK.Context.Constant.Common;
  14. using TEAMModelOS.SDK.DI;
  15. using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
  16. using TEAMModelOS.SDK.Extension;
  17. using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
  18. using TEAMModelOS.Models;
  19. using Microsoft.Extensions.Options;
  20. using TEAMModelOS.Filter;
  21. using TEAMModelOS.Services.Common;
  22. using Azure.Storage.Blobs.Models;
  23. using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
  24. using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
  25. using System.Net.Http;
  26. using TEAMModelOS.SDK.Models.Cosmos;
  27. using Azure.Messaging.ServiceBus;
  28. using Azure.Storage.Sas;
  29. namespace TEAMModelOS.Controllers
  30. {
  31. /// <summary>
  32. /// 投票活动
  33. /// </summary>
  34. [ProducesResponseType(StatusCodes.Status200OK)]
  35. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  36. //[Authorize(Roles = "IES5")]
  37. [Route("common/survey")]
  38. [ApiController]
  39. public class SurveyController : ControllerBase
  40. {
  41. private readonly AzureRedisFactory _azureRedis;
  42. private readonly AzureCosmosFactory _azureCosmos;
  43. private readonly SnowflakeId _snowflakeId;
  44. private readonly AzureServiceBusFactory _serviceBus;
  45. private readonly DingDing _dingDing;
  46. private readonly Option _option;
  47. private readonly AzureStorageFactory _azureStorage;
  48. private readonly IHttpClientFactory _clientFactory;
  49. public SurveyController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option,
  50. AzureRedisFactory azureRedis, AzureStorageFactory azureStorage, IHttpClientFactory clientFactory)
  51. {
  52. _snowflakeId= snowflakeId;
  53. _serviceBus = serviceBus;
  54. _azureCosmos = azureCosmos;
  55. _dingDing = dingDing;
  56. _option = option?.Value;
  57. _azureRedis = azureRedis;
  58. _azureStorage = azureStorage;
  59. _clientFactory = clientFactory;
  60. }
  61. /// <summary>
  62. /// 新增 或 修改投票活动
  63. /// </summary>
  64. /// <param name="request"></param>
  65. /// <returns></returns>
  66. [ProducesDefaultResponseType]
  67. [HttpPost("upsert")]
  68. public async Task<IActionResult> Upsert(Survey request) {
  69. try {
  70. var client = _azureCosmos.GetCosmosClient();
  71. request.code = request.pk + "-" + request.code;
  72. long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  73. request.createTime = now;
  74. if (string.IsNullOrEmpty(request.id))
  75. {
  76. request.id = Guid.NewGuid().ToString();
  77. if (request.startTime > now)
  78. {
  79. request.progress = "pending";
  80. }
  81. else
  82. {
  83. request.progress = "going";
  84. }
  85. request = await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(request, new PartitionKey($"{request.code}"));
  86. }
  87. else {
  88. var response = await client.GetContainer("TEAMModelOS", "Common").ReadItemStreamAsync(request.id, new PartitionKey($"{request.code}"));
  89. if (response.Status == 200)
  90. {
  91. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  92. var info = json.ToObject<Survey>();
  93. if (info.progress.Equals("going"))
  94. {
  95. return Ok(new { v = "活动正在进行中" });
  96. }
  97. if (request.startTime > now)
  98. {
  99. request.progress = "pending";
  100. }
  101. else
  102. {
  103. request.progress = "going";
  104. }
  105. request.progress = info.progress;
  106. request = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(request, info.id, new PartitionKey($"{info.code}"));
  107. }
  108. else {
  109. if (request.startTime > now)
  110. {
  111. request.progress = "pending";
  112. }
  113. else
  114. {
  115. request.progress = "going";
  116. }
  117. request = await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(request, new PartitionKey($"{request.code}"));
  118. }
  119. }
  120. return Ok(new { survey = request});
  121. } catch (Exception ex) {
  122. await _dingDing.SendBotMsg($"OS,{_option.Location},common/survey/save()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  123. return BadRequest(ex.StackTrace);
  124. }
  125. }
  126. /// <summary>
  127. /// 查询问卷调查,用于列表,编辑,查看
  128. /// </summary>
  129. /// <data>
  130. ///Survey-学校/教师编码 活动分区 !"code":"hbcn"/1606285227
  131. ///时间筛选范围开始时间 默认30天之前 ?"stime":1608274766154
  132. ///时间筛选范围结束时间 默认当前时间 ?"etime":1608274766666
  133. ///每页大小 ?"count":10/null/Undefined
  134. ///分页Token ?"continuationToken":Undefined/null/"[{\"token\":\"+RID:~omxMAP3ipcSEEwAAAAAAAA==#RT:2#TRC:20#ISV:2#IEO:65551#QCF:1#FPC:AYQTAAAAAAAAiRMAAAAAAAA=\",\"range\":{\"min\":\"\",\"max\":\"FF\"}}]"
  135. /// 当前状态 ?"progress":Undefined/null/"" 表示两种状态都要查询/ "going"/"finish" 表示查询进行中/ 或者已完成 学生端只能查询正在进行或已经结束 going 已发布|finish 已结束
  136. /// </data>
  137. /// <param name="request"></param>
  138. /// <returns></returns>
  139. [ProducesDefaultResponseType]
  140. [HttpPost("find")]
  141. public async Task<IActionResult> Find(JsonElement requert)
  142. {
  143. try {
  144. //必须有学校或者教师编码
  145. if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
  146. //开始时间,默认最近三十天
  147. var stimestamp = DateTimeOffset.UtcNow.AddDays(-30).ToUnixTimeMilliseconds();
  148. if (requert.TryGetProperty("stime", out JsonElement stime))
  149. {
  150. if (!stime.ValueKind.Equals(JsonValueKind.Undefined)&& !stime.ValueKind.Equals(JsonValueKind.Null) && stime.TryGetInt64(out long data))
  151. {
  152. stimestamp = data;
  153. };
  154. };
  155. //默认当前时间
  156. var etimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  157. if (requert.TryGetProperty("etime", out JsonElement etime))
  158. {
  159. if (!etime.ValueKind.Equals(JsonValueKind.Null)&&!etime.ValueKind.Equals(JsonValueKind.Undefined) && etime.TryGetInt64(out long data))
  160. {
  161. etimestamp = data;
  162. };
  163. };
  164. var progresssql = "";
  165. if (requert.TryGetProperty("progress", out JsonElement progress))
  166. {
  167. if (!progress.ValueKind.Equals(JsonValueKind.Undefined) && !progress.ValueKind.Equals(JsonValueKind.Null) && progress.ValueKind.Equals(JsonValueKind.String))
  168. {
  169. progresssql = $" and c.progress='{progresssql}' ";
  170. }
  171. }
  172. string continuationToken = null;
  173. //默认不指定返回大小
  174. int? topcout = null;
  175. if (requert.TryGetProperty("count", out JsonElement jcount))
  176. {
  177. if (!jcount.ValueKind.Equals(JsonValueKind.Undefined) && !jcount.ValueKind.Equals(JsonValueKind.Null) && jcount.TryGetInt32(out int data))
  178. {
  179. topcout = data;
  180. }
  181. };
  182. //是否需要进行分页查询,默认不分页
  183. bool iscontinuation = false;
  184. //如果指定了返回大小
  185. if (requert.TryGetProperty("continuationToken", out JsonElement continuation))
  186. {
  187. //指定了cancellationToken 表示需要进行分页
  188. if (!continuation.ValueKind.Equals(JsonValueKind.Null) && !continuation.ValueKind.Equals(JsonValueKind.Undefined))
  189. {
  190. continuationToken = continuation.GetString();
  191. iscontinuation = true;
  192. }
  193. };
  194. List<object> surveys = new List<object>();
  195. var client = _azureCosmos.GetCosmosClient();
  196. var query = $"select c.id,c.name,c.code,c.startTime,c.endTime,c.progress from c where c.createTime >= {stimestamp} and c.createTime <= {etimestamp} {progresssql } ";
  197. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: query,
  198. requestOptions: new QueryRequestOptions() { MaxItemCount = topcout, PartitionKey = new PartitionKey($"Survey-{code}") }))
  199. {
  200. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  201. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  202. {
  203. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  204. {
  205. surveys.Add(obj.ToObject<JsonElement>());
  206. }
  207. //如果需要分页则跳出
  208. if (iscontinuation)
  209. {
  210. continuationToken = item.GetContinuationToken();
  211. break;
  212. }
  213. }
  214. }
  215. return Ok(new { surveys, continuationToken });
  216. } catch (Exception ex) {
  217. await _dingDing.SendBotMsg($"OS,{_option.Location},common/survey/find()\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
  218. return BadRequest(ex.StackTrace);
  219. }
  220. }
  221. ///<summary>
  222. /// 查询问卷调查,用于创建者列表,编辑,查看,作答人员查看
  223. /// </summary>
  224. /// <data>
  225. /// ! "id":"3c075347-75ef-4bcb-ae03-68678d02d5ef",
  226. /// ! "code":"Survey-hbcn"/"code":"Survey-1606285227"
  227. /// </data>
  228. /// <param name="request"></param>
  229. /// <returns></returns>
  230. [ProducesDefaultResponseType]
  231. [HttpPost("find-id")]
  232. public async Task<IActionResult> FindById(JsonElement requert)
  233. {
  234. try
  235. {
  236. var client = _azureCosmos.GetCosmosClient();
  237. //活动id
  238. if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
  239. //活动分区
  240. if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
  241. Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Survey>(id.GetString(), new PartitionKey($"{code}"));
  242. if (survey != null)
  243. {
  244. return Ok(new { survey });
  245. }
  246. else
  247. {
  248. return BadRequest("id,code不存在!");
  249. }
  250. }
  251. catch (Exception ex)
  252. {
  253. await _dingDing.SendBotMsg($"OS,{_option.Location},common/survey/find-id()\n{ex.Message}{requert.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
  254. return BadRequest(ex.StackTrace);
  255. }
  256. }
  257. /// <summary>
  258. /// 删除问卷调查 TODO 使用ttl删除,并处理相关事务逻辑
  259. /// </summary>
  260. /// <param name="request"></param>
  261. /// <returns></returns>
  262. [ProducesDefaultResponseType]
  263. [HttpPost("delete")]
  264. [AuthToken(Roles = "admin,teacher")]
  265. public async Task<IActionResult> Delete(JsonElement request)
  266. {
  267. try
  268. {
  269. var (userid, _, _, school) = HttpContext.GetAuthTokenInfo();
  270. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  271. if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  272. var client = _azureCosmos.GetCosmosClient();
  273. Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Survey>(id.GetString(), new PartitionKey($"{code}"));
  274. bool flag = false;
  275. //必须是本人或者这个学校的管理者才能删除
  276. if (survey.creatorId == userid)
  277. {
  278. flag = true;
  279. }
  280. else
  281. {
  282. if (survey.scope == "school" && survey.owner.Equals(school))
  283. {
  284. flag = true;
  285. }
  286. }
  287. if (flag)
  288. {
  289. //使用ttl删除,并处理相关事务逻辑
  290. survey.ttl = 5;
  291. survey = await client.GetContainer("TEAMModelOS", "Common").UpsertItemAsync(survey, new PartitionKey($"{survey.code}"));
  292. return Ok(new { flag });
  293. }
  294. else
  295. {
  296. return Ok(new { flag });
  297. }
  298. }
  299. catch (Exception e)
  300. {
  301. return BadRequest(e.StackTrace);
  302. }
  303. }
  304. /// <summary>
  305. /// 问卷答案提交
  306. /// </summary>
  307. /// <redis>
  308. /// Survey:Record:e6b887f8-adb5-3677-bcc7-3b36450909df_Survey-1595321354 {"C":2,"A":2,"other":2}
  309. /// </redis>
  310. /// <param name="request">
  311. /// !"id":"aaaa"
  312. /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
  313. /// !"record":[["A","B"],["A"],["D"],[],["建议提升服务质量"]]
  314. /// </param>
  315. /// <returns>
  316. /// msgid=0投票失败,1提交成功,2不在时间范围内,3不在发布范围内,6未设置投票项
  317. /// </returns>
  318. [ProducesDefaultResponseType]
  319. [HttpPost("answer")]
  320. //[AuthToken(Roles = "teacher,student")]
  321. public async Task<IActionResult> Answer(JsonElement request)
  322. {
  323. // var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
  324. if (request.TryGetProperty("userid", out JsonElement userid)) {
  325. int msgid = await ActivityStudentService.Answer(request, _azureCosmos, _azureRedis, $"{userid}", _azureStorage);
  326. return Ok(new { msgid });
  327. }
  328. else { return Ok(new { msgid = 0 }); }
  329. }
  330. /// <summary>
  331. /// 问卷答案提交
  332. /// </summary>
  333. /// <redis>
  334. /// Survey:Record:e6b887f8-adb5-3677-bcc7-3b36450909df_Survey-1595321354 {"C":2,"A":2,"other":2}
  335. /// </redis>
  336. /// <param name="request">
  337. /// !"id":"aaaa"
  338. /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
  339. /// </param>
  340. /// <returns>
  341. /// msgid=0投票失败,1提交成功,2不在时间范围内,3不在发布范围内,6未设置投票项
  342. /// </returns>
  343. [ProducesDefaultResponseType]
  344. [HttpPost("answered-list")]
  345. //[AuthToken(Roles = "teacher,student")]
  346. public async Task<IActionResult> AnsweredList(JsonElement request)
  347. {
  348. // var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
  349. if (!request.TryGetProperty("id", out JsonElement id))
  350. {
  351. return BadRequest();
  352. }
  353. //活动分区
  354. if (!request.TryGetProperty("code", out JsonElement code))
  355. {
  356. return BadRequest();
  357. }
  358. List<string> userids = new List<string>();
  359. var values= await _azureRedis.GetRedisClient(8).SetMembersAsync($"Survey:Submit:{id}");
  360. if (values != default && values.Length>0) {
  361. foreach(var val in values) {
  362. userids.Add(val);
  363. }
  364. }
  365. return Ok(new { userids = userids });
  366. }
  367. /// <summary>
  368. /// 问卷答案提交
  369. /// </summary>
  370. /// <redis>
  371. /// Survey:Record:e6b887f8-adb5-3677-bcc7-3b36450909df_Survey-1595321354 {"C":2,"A":2,"other":2}
  372. /// </redis>
  373. /// <param name="request">
  374. /// !"id":"aaaa"
  375. /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
  376. /// </param>
  377. /// <returns>
  378. /// msgid=0投票失败,1提交成功,2不在时间范围内,3不在发布范围内,6未设置投票项
  379. /// </returns>
  380. [ProducesDefaultResponseType]
  381. [HttpPost("answered")]
  382. [AuthToken(Roles = "teacher,student")]
  383. public async Task<IActionResult> Answered(JsonElement request)
  384. {
  385. var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
  386. if (!request.TryGetProperty("id", out JsonElement id))
  387. {
  388. return BadRequest();
  389. }
  390. //活动分区
  391. if (!request.TryGetProperty("code", out JsonElement code))
  392. {
  393. return BadRequest();
  394. }
  395. List<string> userids = new List<string>();
  396. var answered = await _azureRedis.GetRedisClient(8).SetContainsAsync($"Survey:Submit:{id}",userid);
  397. return Ok(new { answered = answered });
  398. }
  399. /// <summary>
  400. /// 问卷记录 当活动没结算且没有BlobUrl时则调用此接口
  401. /// </summary>
  402. /// <redis>
  403. /// {"C":2,"A":2,"other":2}
  404. /// </redis>
  405. /// <param name="request">
  406. /// !"id":"aaaa"
  407. /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
  408. /// </param>
  409. /// <returns>
  410. /// </returns>
  411. [ProducesDefaultResponseType]
  412. [HttpPost("record")]
  413. //[AuthToken(Roles = "teacher,student")]
  414. public async Task<IActionResult> Record(JsonElement request)
  415. {
  416. if (!request.TryGetProperty("id", out JsonElement id))
  417. {
  418. return BadRequest();
  419. }
  420. //活动分区
  421. if (!request.TryGetProperty("code", out JsonElement code))
  422. {
  423. return BadRequest();
  424. }
  425. //获取问卷记录
  426. var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{id}");
  427. List<dynamic> res = new List<dynamic>();
  428. foreach (var rcd in records)
  429. {
  430. var value = rcd.Value.ToString().ToObject<JsonElement>();
  431. res.Add(new { index = rcd.Name.ToString(), ans = value }) ;
  432. }
  433. return Ok(new {records = res});
  434. }
  435. /// <summary>
  436. /// 问卷记录 当活动没结算且没有BlobUrl时则调用此接口
  437. /// </summary>
  438. /// <redis>
  439. /// {"C":2,"A":2,"other":2}
  440. /// </redis>
  441. /// <param name="request">
  442. /// !"id":"aaaa"
  443. /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
  444. /// </param>
  445. /// <returns>
  446. /// </returns>
  447. [ProducesDefaultResponseType]
  448. [HttpPost("settlement")]
  449. //[AuthToken(Roles = "teacher,student")]
  450. public async Task<IActionResult> Settlement(JsonElement request)
  451. {
  452. try
  453. {
  454. var client = _azureCosmos.GetCosmosClient();
  455. //活动id
  456. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  457. //活动分区
  458. if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  459. Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Survey>(id.GetString(), new PartitionKey($"{code}"));
  460. List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", $"{id}" }, { "PartitionKey", survey.progress } });
  461. ActivityData data = null;
  462. if (survey != null)
  463. {
  464. var adid = survey.id;
  465. var adcode = $"Activity-{survey.owner}";
  466. try {
  467. if (survey.scope == "school")
  468. {
  469. data = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<ActivityData>(adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
  470. }
  471. else if (survey.scope == "private")
  472. {
  473. data = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<ActivityData>(adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
  474. }
  475. } catch {
  476. data = null;
  477. }
  478. if (survey.ttl >= 1)
  479. {
  480. _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Record:{survey.id}");
  481. _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Submit:{survey.id}");
  482. if (data != null)
  483. {
  484. data.ttl = 1;
  485. if (survey.scope == "school")
  486. {
  487. data = await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<ActivityData>(data, adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
  488. }
  489. else if (survey.scope == "private")
  490. {
  491. data = await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<ActivityData>(data, adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
  492. }
  493. }
  494. await _dingDing.SendBotMsg($"问卷调查【{survey.name}-{survey.id}】被删除", GroupNames.醍摩豆服務運維群組);
  495. return Ok();
  496. }
  497. else
  498. {
  499. switch (survey.progress)
  500. {
  501. case "finish":
  502. var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}");
  503. List<dynamic> recs = new List<dynamic>();
  504. foreach (var rcd in records)
  505. {
  506. var value = rcd.Value.ToString().ToObject<JsonElement>();
  507. recs.Add(new { index = rcd.Name.ToString(), ans = value });
  508. }
  509. var cods = new { records = recs };
  510. //问卷整体情况
  511. await _azureStorage.UploadFileByContainer(survey.owner, cods.ToJsonString(), "survey", $"{survey.id}/record.json");
  512. //结算每道题的答题情况
  513. var ContainerClient = _azureStorage.GetBlobContainerClient(survey.owner);
  514. var route = ContainerClient.Uri.ToString();
  515. //获取
  516. try
  517. {
  518. List<string> items = await ContainerClient.List($"survey/{survey.id}/urecord");
  519. List<SurveyRecord> surveyRecords = new List<SurveyRecord>();
  520. (string uri, string sas) blobAuth = _azureStorage.GetBlobContainerSAS(survey.owner, BlobContainerSasPermissions.Read);
  521. string sas = blobAuth.sas;
  522. var rcode = await _clientFactory.CreateClient().GetAsync(new Uri($"{route}/survey/{survey.id}/record.json?{sas}"));
  523. var jsonc = await JsonDocument.ParseAsync(await rcode.Content.ReadAsStreamAsync());
  524. var Recordc = jsonc.RootElement.ToObject<JsonElement>();
  525. HttpClient httpClient = _clientFactory.CreateClient();
  526. await _dingDing.SendBotMsg($"问卷调查问题结算数据11111--->>{Recordc.ToJsonString()}", GroupNames.成都开发測試群組);
  527. foreach (string item in items)
  528. {
  529. var url = $"{route}/{item}?{sas}";
  530. var response = await httpClient.GetAsync(new Uri(url));
  531. var json = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
  532. var Record = json.RootElement.ToObject<SurveyRecord>();
  533. surveyRecords.Add(Record);
  534. }
  535. await _dingDing.SendBotMsg($"问卷调查问题结算数据{surveyRecords.ToJsonString()}", GroupNames.成都开发測試群組);
  536. for (int index = 0; index < survey.ans.Count; index++)
  537. {
  538. string url = $"{survey.id}/qrecord/{index}.json";
  539. QuestionRecord question = new QuestionRecord() { index = index };
  540. foreach (SurveyRecord record in surveyRecords)
  541. {
  542. if (record.ans.Count == survey.ans.Count)
  543. {
  544. foreach (var an in record.ans[index])
  545. {
  546. //
  547. if (question.opt.ContainsKey(an))
  548. {
  549. if (question.opt[an] != null)
  550. {
  551. question.opt[an].Add(record.userid);
  552. }
  553. else
  554. {
  555. question.opt[an] = new HashSet<string>() { record.userid };
  556. }
  557. }
  558. else
  559. {
  560. if (survey.ans[index].Contains(an))
  561. {
  562. //如果是客观题code
  563. question.opt.Add(an, new HashSet<string> { record.userid });
  564. }
  565. else
  566. {
  567. //如果不是客观code
  568. question.other[record.userid] = an;
  569. }
  570. }
  571. }
  572. }
  573. }
  574. await _azureStorage.UploadFileByContainer(survey.owner, question.ToJsonString(), "survey", url);
  575. }
  576. }
  577. catch (Exception ex)
  578. {
  579. await _dingDing.SendBotMsg($"问卷调查问题结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  580. }
  581. if (string.IsNullOrEmpty(survey.recordUrl))
  582. {
  583. survey.recordUrl = $"/survey/{survey.id}/record.json";
  584. await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync<Survey>(survey, survey.id, new Azure.Cosmos.PartitionKey(survey.code));
  585. }
  586. else
  587. {
  588. //异动,且已经有结算记录则不必再继续。
  589. //break;
  590. }
  591. // await Task.WhenAll(tasks);
  592. //更新结束状态
  593. data.progress = "finish";
  594. if (survey.scope == "school")
  595. {
  596. await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
  597. }
  598. else if (survey.scope == "private")
  599. {
  600. await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
  601. }
  602. break;
  603. }
  604. }
  605. }
  606. return Ok();
  607. }
  608. catch (Exception ex)
  609. {
  610. await _dingDing.SendBotMsg($"OS,{_option.Location},common/survey/find-id()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  611. return BadRequest(ex.StackTrace);
  612. }
  613. }
  614. }
  615. public class QuestionRecord
  616. {
  617. public int index { get; set; }
  618. public Dictionary<string, HashSet<string>> opt { get; set; } = new Dictionary<string, HashSet<string>>();
  619. public Dictionary<string, string> other { get; set; } = new Dictionary<string, string>();
  620. }
  621. }