ExamController.cs 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. using Azure.Cosmos;
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.AspNetCore.Mvc;
  4. using Microsoft.Extensions.Options;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Dynamic;
  8. using System.IdentityModel.Tokens.Jwt;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Text.Json;
  13. using System.Threading.Tasks;
  14. using TEAMModelOS.Models;
  15. using TEAMModelOS.SDK.Models;
  16. using TEAMModelOS.SDK;
  17. using TEAMModelOS.SDK.Context.Constant.Common;
  18. using TEAMModelOS.SDK.DI;
  19. using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
  20. using TEAMModelOS.SDK.Extension;
  21. using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
  22. using TEAMModelOS.SDK.Helper.Common.StringHelper;
  23. namespace TEAMModelOS.Controllers
  24. {
  25. [ProducesResponseType(StatusCodes.Status200OK)]
  26. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  27. //[Authorize(Roles = "IES5")
  28. [Route("common/exam")]
  29. [ApiController]
  30. public class ExamController : ControllerBase
  31. {
  32. private readonly AzureCosmosFactory _azureCosmos;
  33. private readonly SnowflakeId _snowflakeId;
  34. private readonly AzureServiceBusFactory _serviceBus;
  35. private readonly DingDing _dingDing;
  36. private readonly Option _option;
  37. private readonly AzureStorageFactory _azureStorage;
  38. public ExamController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage)
  39. {
  40. _azureCosmos = azureCosmos;
  41. _serviceBus = serviceBus;
  42. _snowflakeId = snowflakeId;
  43. _dingDing = dingDing;
  44. _option = option?.Value;
  45. _azureStorage = azureStorage;
  46. }
  47. /// <summary>
  48. /// 保存考试信息
  49. /// </summary>
  50. /// <param name="request"></param>
  51. /// <returns></returns>
  52. [ProducesDefaultResponseType]
  53. //[AuthToken(Roles = "Teacher")]
  54. [HttpPost("save")]
  55. public async Task<IActionResult> Save(ExamInfo request)
  56. {
  57. try
  58. {
  59. //新增
  60. //string code = request.code;
  61. var client = _azureCosmos.GetCosmosClient();
  62. ExamInfo exam;
  63. string code = request.code;
  64. request.code = "Exam-" + request.code;
  65. request.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  66. if (string.IsNullOrEmpty(request.id))
  67. {
  68. request.id = Guid.NewGuid().ToString();
  69. request.progress = "pending";
  70. int count = 0;
  71. for (int i = 0; i < request.targetClassIds.Count; i++)
  72. {
  73. if (request.scope.Equals("private") || request.scope.Equals("teacher"))
  74. {
  75. var sresponse = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(request.targetClassIds[i], new PartitionKey($"Class-{code}"));
  76. if (sresponse.Status == 200)
  77. {
  78. using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
  79. Class classroom = json.ToObject<Class>();
  80. count += classroom.students.Count;
  81. }
  82. }
  83. else {
  84. var sresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(request.targetClassIds[i], new PartitionKey($"Class-{code}"));
  85. if (sresponse.Status == 200)
  86. {
  87. using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
  88. Class classroom = json.ToObject<Class>();
  89. count += classroom.students.Count;
  90. }
  91. }
  92. }
  93. request.stuCount = count;
  94. foreach (PaperSimple simple in request.papers) {
  95. simple.blob = "/exam/" + request.id + "/paper/" + simple.id;
  96. }
  97. //request.papers
  98. /*long SequenceNumber = await _serviceBus.GetServiceBusClient().SendLeamMessage<ExamInfo>(Constants.TopicName, request.id, request.code, request.startTime);
  99. request.sequenceNumber = SequenceNumber;*/
  100. exam = await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(request, new PartitionKey($"{request.code}"));
  101. //await _serviceBus.GetServiceBusClient().SendLeamMessage<ExamInfo>(Constants.TopicName, request.id, request.code, request.startTime);
  102. //request.sequenceNumber = SequenceNumber;
  103. }
  104. else
  105. {
  106. ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(request.id, new PartitionKey($"{request.code}"));
  107. if (info.progress.Equals("going"))
  108. {
  109. return Ok(new { v = "活动正在进行中" });
  110. }
  111. request.progress = info.progress;
  112. foreach (PaperSimple simple in request.papers)
  113. {
  114. simple.blob = "/exam/" + request.id + "/paper/" + simple.id;
  115. }
  116. /* await _serviceBus.GetServiceBusClient().cancelMessage(Constants.TopicName, info.sequenceNumber);
  117. long SequenceNumber = await _serviceBus.GetServiceBusClient().SendLeamMessage<ExamInfo>(Constants.TopicName, request.id, request.code, request.startTime);
  118. request.sequenceNumber = SequenceNumber;*/
  119. exam = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(request, request.id, new PartitionKey($"{request.code}"));
  120. //await _serviceBus.GetServiceBusClient().SendLeamMessage<ExamInfo>(Constants.TopicName, request.id, request.code, request.startTime);
  121. }
  122. //Survey homeWork = await _azureCosmos.SaveOrUpdate<Survey>(request.survey);
  123. //设定结束时间
  124. //string msgEndId = _snowflakeId.NextId() + "";
  125. //await _serviceBus.GetServiceBusClient().SendLeamMessage<ExamInfo>(Constants.TopicName, request.id, request.code, request.endTime);
  126. return Ok(new { exam });
  127. }
  128. catch (Exception ex)
  129. {
  130. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/save()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  131. return BadRequest();
  132. }
  133. }
  134. //TODO blob 批量删除
  135. /// <summary>
  136. /// 删除
  137. /// </summary>
  138. /// <param name="request"></param>
  139. /// <returns></returns>
  140. [ProducesDefaultResponseType]
  141. //[AuthToken(Roles = "Teacher")]
  142. [HttpPost("delete")]
  143. public async Task<IActionResult> Delete(JsonElement request)
  144. {
  145. /* ResponseBuilder builder = ResponseBuilder.custom();
  146. IdPk items = await _azureCosmos.DeleteAsync<ExamInfo>(request.id, request.pk);
  147. await _azureCosmos.DeleteAll<Paper>(new Dictionary<string, object>() { { "code", request.id } });
  148. return builder.Data(items).build();*/
  149. try
  150. {
  151. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  152. if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  153. if (!request.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  154. var client = _azureCosmos.GetCosmosClient();
  155. //string school_code = code.ToString().Substring(typeof(ExamClassResult).Name.Length + 1);
  156. var response = await client.GetContainer("TEAMModelOS", "Common").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"Exam-{code}"));
  157. List<ExamClassResult> examClassResults = new List<ExamClassResult>();
  158. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{code}") }))
  159. {
  160. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  161. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  162. {
  163. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  164. {
  165. examClassResults.Add(obj.ToObject<ExamClassResult>());
  166. }
  167. }
  168. }
  169. foreach (ExamClassResult classResult in examClassResults)
  170. {
  171. await client.GetContainer("TEAMModelOS", "Common").DeleteItemStreamAsync(classResult.id, new PartitionKey($"ExamClassResult-{code}"));
  172. }
  173. //await _azureCosmos.DeleteAll(examClassResults);
  174. return Ok(new { id });
  175. }
  176. catch (Exception e)
  177. {
  178. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/delete()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
  179. return BadRequest();
  180. }
  181. }
  182. /// <summary>
  183. /// 查询考试信息
  184. /// </summary>
  185. /// <param name="request"></param>
  186. /// <returns></returns>
  187. [ProducesDefaultResponseType]
  188. //[AuthToken(Roles = "Teacher")]
  189. [HttpPost("find")]
  190. public async Task<IActionResult> Find(JsonElement requert)
  191. {
  192. try
  193. {
  194. //ResponseBuilder builder = ResponseBuilder.custom();
  195. //if (!requert.TryGetProperty("id_token", out JsonElement id_token)) return BadRequest();
  196. if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
  197. //if (!requert.TryGetProperty("school", out JsonElement school_code)) return BadRequest();
  198. //if (!requert.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  199. //var jwt = new JwtSecurityToken(id_token.GetString());
  200. //if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
  201. //var id = jwt.Payload.Sub;
  202. var client = _azureCosmos.GetCosmosClient();
  203. List<ExamInfo> examInfo = new List<ExamInfo>();
  204. var query = $"select c.id,c.name,c.code,c.period,c.startTime,c.endTime,c.stuCount,c.type,c.progress,c.examType,c.createTime, c.subjects, c.grades, c.scope from c ";
  205. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{code}") }))
  206. {
  207. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  208. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  209. {
  210. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  211. {
  212. //obj.TryGetProperty("progress", out JsonElement progress);
  213. examInfo.Add(obj.ToObject<ExamInfo>());
  214. }
  215. }
  216. }
  217. return Ok(new { examInfo });
  218. /*if (StringHelper.getKeyCount(request) > 0)
  219. {
  220. return builder.Data(await _azureCosmos.FindByDict<ExamInfo>(request)).build();
  221. }
  222. else {
  223. return builder.build();
  224. }*/
  225. }
  226. catch (Exception e)
  227. {
  228. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/find()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
  229. return BadRequest();
  230. }
  231. }
  232. [ProducesDefaultResponseType]
  233. //[AuthToken(Roles = "Teacher")]
  234. [HttpPost("find-summary")]
  235. public async Task<IActionResult> FindSummary(JsonElement requert)
  236. {
  237. try
  238. {
  239. //ResponseBuilder builder = ResponseBuilder.custom();
  240. //if (!requert.TryGetProperty("id_token", out JsonElement id_token)) return BadRequest();
  241. if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
  242. if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
  243. //if (!requert.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  244. //var jwt = new JwtSecurityToken(id_token.GetString());
  245. //if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
  246. //var id = jwt.Payload.Sub;
  247. var client = _azureCosmos.GetCosmosClient();
  248. List<ExamInfo> examInfo = new List<ExamInfo>();
  249. //var query = $"select value(c) from c ";
  250. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.id = '{id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
  251. {
  252. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  253. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  254. {
  255. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  256. {
  257. //obj.TryGetProperty("progress", out JsonElement progress);
  258. examInfo.Add(obj.ToObject<ExamInfo>());
  259. }
  260. }
  261. }
  262. return Ok(new { examInfo });
  263. }
  264. catch (Exception e)
  265. {
  266. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/FindSummary()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
  267. return BadRequest();
  268. }
  269. }
  270. /// <summary>
  271. /// 学生回答问题
  272. /// </summary>
  273. /// <param name="request"></param>
  274. /// <returns></returns>
  275. [ProducesDefaultResponseType]
  276. //[AuthToken(Roles = "Teacher")]
  277. [HttpPost("upsert-record")]
  278. public async Task<IActionResult> upsertRecord(JsonElement request)
  279. {
  280. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  281. //if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  282. if (!request.TryGetProperty("answer", out JsonElement answer)) return BadRequest();
  283. if (!request.TryGetProperty("studentId", out JsonElement studentId)) return BadRequest();
  284. if (!request.TryGetProperty("subjectId", out JsonElement subjectId)) return BadRequest();
  285. if (!request.TryGetProperty("classId", out JsonElement classId)) return BadRequest();
  286. if (!request.TryGetProperty("multipleRule", out JsonElement multipleRule)) return BadRequest();
  287. //if (!request.TryGetProperty("answers ", out JsonElement tandardAnswer)) return BadRequest();
  288. if (!request.TryGetProperty("paperId", out JsonElement paperId)) return BadRequest();
  289. //根据不同评测的类型返回对应的编码
  290. if (!request.TryGetProperty("code", out JsonElement school)) return BadRequest();
  291. try
  292. {
  293. var client = _azureCosmos.GetCosmosClient();
  294. List<ExamClassResult> examClassResults = new List<ExamClassResult>();
  295. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
  296. queryText: $"select value(c) from c where c.examId = '{id}' and c.subjectId = '{subjectId}' and c.info.id = '{classId}'",
  297. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{school}") }))
  298. {
  299. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  300. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  301. {
  302. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  303. {
  304. examClassResults.Add(obj.ToObject<ExamClassResult>());
  305. }
  306. }
  307. }
  308. ExamClassResult classResult = new ExamClassResult() ;
  309. List<PaperSimple> standerAnswers = new List<PaperSimple>();
  310. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
  311. queryText: $"select A0.point,A0.answers from c join A0 in c.papers where c.id = '{id}'and A0.id = '{paperId}'",
  312. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{school}") }))
  313. {
  314. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  315. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  316. {
  317. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  318. {
  319. standerAnswers.Add(obj.ToObject<PaperSimple>());
  320. }
  321. }
  322. }
  323. List<List<string>> ans = answer.ToObject<List<List<string>>>();
  324. List<List<string>> standard = new List<List<string>>();
  325. List<double> points = new List<double>();
  326. int rule = int.Parse(multipleRule.ToString());
  327. foreach (PaperSimple simple in standerAnswers) {
  328. standard = simple.answers;
  329. points = simple.point;
  330. }
  331. List<Task<string>> tasks = new List<Task<string>>();
  332. foreach (ExamClassResult result in examClassResults) {
  333. int index = result.studentIds.IndexOf(studentId.ToString());
  334. //classResult.studentAnswers[index] = ans;
  335. if (index == -1)
  336. {
  337. List<double> ansPoint = new List<double>();
  338. foreach (List<string> num in standard)
  339. {
  340. //ans.Add(new List<string>());
  341. ansPoint.Add(-1);
  342. }
  343. result.studentIds.Add(studentId.ToString());
  344. result.studentScores.Add(ansPoint);
  345. result.studentAnswers.Add(new List<string>());
  346. result.sum.Add(0);
  347. }
  348. //int flagCount = 0;
  349. /*foreach (List<string> str in ans) {
  350. if (str.Count == 0) {
  351. flagCount++;
  352. }
  353. } */
  354. int newIndex = result.studentIds.IndexOf(studentId.ToString());
  355. /*if (flagCount != standard.Count)
  356. {*/
  357. /* StringBuilder builder = new StringBuilder();
  358. builder.Append(result.examId + "/");
  359. builder.Append(result.subjectId + "/");
  360. builder.Append(studentId);*/
  361. string FileName = result.examId + "/" + result.subjectId + "/" + studentId;
  362. string blob = FileName + "/" + "ans.json";
  363. tasks.Add(_azureStorage.UploadFileByContainer(school.ToString(), ans.ToJsonString(), "exam", FileName + "/" + "ans.json", false));
  364. result.studentAnswers[newIndex].Add(blob);
  365. //}
  366. for (int i = 0; i < ans.Count; i++)
  367. {
  368. //result.studentAnswers[index][i] = ans[i];
  369. //算分处理
  370. if (standard[i].Count > 0)
  371. {
  372. if (ans[i].Count == standard[i].Count && standard[i].Count == 1)
  373. {
  374. foreach (string right in ans[i])
  375. {
  376. if (standard[i].Contains(right))
  377. {
  378. result.studentScores[newIndex][i] = points[i];
  379. }
  380. else
  381. {
  382. result.studentScores[newIndex][i] = 0;
  383. }
  384. }
  385. }
  386. else
  387. {
  388. if (rule > 0)
  389. {
  390. int falseCount = 0;
  391. if (ans[i].Count > 0)
  392. {
  393. foreach (string obj in ans[i])
  394. {
  395. if (!standard[i].Contains(obj))
  396. {
  397. falseCount++;
  398. }
  399. }
  400. switch (rule)
  401. {
  402. case 1:
  403. if (ans[i].Count == standard[i].Count)
  404. {
  405. if (falseCount == 0)
  406. {
  407. result.studentScores[newIndex][i] = points[i];
  408. }
  409. else
  410. {
  411. result.studentScores[newIndex][i] = 0;
  412. }
  413. }
  414. else
  415. {
  416. result.studentScores[newIndex][i] = 0;
  417. }
  418. break;
  419. case 2:
  420. if (falseCount > 0)
  421. {
  422. result.studentScores[newIndex][i] = 0;
  423. }
  424. else
  425. {
  426. if (ans[i].Count == standard[i].Count)
  427. {
  428. result.studentScores[newIndex][i] = points[i];
  429. }
  430. else
  431. {
  432. result.studentScores[newIndex][i] = points[i] / 2;
  433. }
  434. }
  435. break;
  436. case 3:
  437. if (falseCount > 0)
  438. {
  439. result.studentScores[newIndex][i] = 0;
  440. }
  441. else
  442. {
  443. if (ans[i].Count == standard[i].Count)
  444. {
  445. result.studentScores[newIndex][i] = points[i];
  446. }
  447. else
  448. {
  449. result.studentScores[newIndex][i] = System.Math.Round((double)ans[i].Count / standard[i].Count * points[i], 1);
  450. }
  451. }
  452. break;
  453. case 4:
  454. if (ans[i].Count == standard[i].Count)
  455. {
  456. result.studentScores[newIndex][i] = points[i];
  457. }
  458. else
  459. {
  460. double persent = (double)(standard[i].Count - 2 * falseCount) / standard[i].Count;
  461. if (persent <= 0)
  462. {
  463. result.studentScores[newIndex][i] = 0;
  464. }
  465. else
  466. {
  467. result.studentScores[newIndex][i] = System.Math.Round(persent * points[i], 1);
  468. }
  469. }
  470. break;
  471. }
  472. }
  473. else {
  474. result.studentScores[newIndex][i] = 0;
  475. }
  476. }
  477. }
  478. }
  479. }
  480. /*if (result.studentScores.Contains(-1)) {
  481. }*/
  482. bool flag = true;
  483. foreach (List<double> scores in result.studentScores)
  484. {
  485. foreach (double score in scores)
  486. {
  487. if (score == -1)
  488. {
  489. flag = false;
  490. break;
  491. }
  492. }
  493. }
  494. if (flag)
  495. {
  496. ExamInfo exam = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{school}"));
  497. result.progress = true;
  498. exam.subjects.ForEach(s =>
  499. {
  500. if (s.id.Equals(subjectId.ToString()))
  501. {
  502. s.classCount += 1;
  503. }
  504. });
  505. await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(exam, id.ToString(), new PartitionKey($"Exam-{school}"));
  506. }
  507. result.sum[newIndex] = result.studentScores[newIndex].Sum();
  508. classResult = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(result, result.id, new PartitionKey($"{result.code}"));
  509. }
  510. await Task.WhenAll(tasks);
  511. return Ok(new { classResult });
  512. }
  513. catch (Exception e)
  514. {
  515. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/upsertRecord()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
  516. return BadRequest();
  517. }
  518. }
  519. [ProducesDefaultResponseType]
  520. //[AuthToken(Roles = "Teacher")]
  521. [HttpPost("upsert-record-by-teacher")]
  522. public async Task<IActionResult> upsertRecordByTeacher(JsonElement request)
  523. {
  524. //ResponseBuilder builder = ResponseBuilder.custom();
  525. try
  526. {
  527. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  528. if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  529. if (!request.TryGetProperty("point", out JsonElement point)) return BadRequest();
  530. if (!request.TryGetProperty("studentId", out JsonElement studentId)) return BadRequest();
  531. if (!request.TryGetProperty("classId", out JsonElement classId)) return BadRequest();
  532. //此参数表明此次操作对象为个人还是校本的评测内容
  533. if (!request.TryGetProperty("code", out JsonElement school)) return BadRequest();
  534. if (!request.TryGetProperty("subjectId", out JsonElement subjectId)) return BadRequest();
  535. //要先处理状态,判断卷子是否存在,并判断卷子归属的考试是否允许再次提交
  536. //List<ExamInfo> exams = await _azureCosmos.FindByDict<ExamInfo>(new Dictionary<string, object> { { "id", request.examCode } });
  537. List<double> ans = point.ToObject<List<double>>();
  538. var client = _azureCosmos.GetCosmosClient();
  539. List<ExamClassResult> examClassResults = new List<ExamClassResult>();
  540. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
  541. queryText: $"select value(c) from c where c.examId = '{id}' and c.subjectId = '{subjectId}' and c.info.id = '{classId}'",
  542. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{school}") }))
  543. {
  544. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  545. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  546. {
  547. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  548. {
  549. examClassResults.Add(obj.ToObject<ExamClassResult>());
  550. }
  551. }
  552. }
  553. ExamClassResult classResult = new ExamClassResult();
  554. //ExamInfo classResult = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"{code}"));
  555. //ExamClassResult classResult = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamClassResult>(id.ToString(), new PartitionKey($"{code}"));
  556. /*foreach (double index in ans) {
  557. classResult.studentScores.in
  558. }*/
  559. foreach (ExamClassResult result in examClassResults) {
  560. int index = result.studentIds.IndexOf(studentId.ToString());
  561. for (int i = 0; i < ans.Count; i++)
  562. {
  563. result.studentScores[index][i] = ans[i];
  564. }
  565. if (!result.progress)
  566. {
  567. bool flag = true;
  568. foreach (List<double> scores in result.studentScores)
  569. {
  570. foreach (double score in scores)
  571. {
  572. if (score == -1)
  573. {
  574. flag = false;
  575. break;
  576. }
  577. }
  578. }
  579. if (flag)
  580. {
  581. ExamInfo exam = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{school}"));
  582. result.progress = true;
  583. exam.subjects.ForEach(s =>
  584. {
  585. if (s.id.Equals(subjectId.ToString()))
  586. {
  587. s.classCount += 1;
  588. }
  589. });
  590. await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(exam, id.ToString(), new PartitionKey($"Exam-{school}"));
  591. }
  592. }
  593. else
  594. {
  595. ExamInfo exam = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{school}"));
  596. exam.updateTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  597. await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(exam, id.ToString(), new PartitionKey($"Exam-{school}"));
  598. }
  599. result.sum[index] = result.studentScores[index].Sum();
  600. classResult = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(result, result.id, new PartitionKey($"{result.code}"));
  601. }
  602. return Ok(new { classResult });
  603. }
  604. catch (Exception ex)
  605. {
  606. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/upsertRecordByTeacher()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  607. return BadRequest();
  608. }
  609. /*if (exams.IsNotEmpty())
  610. {
  611. ExamInfo examInfo = exams[0];
  612. //提交答案时间必须是状态已发布,且时间在起止时间内
  613. if (examInfo.startTime <= DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() && examInfo.status == 200 &&
  614. examInfo.endTime >= DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
  615. {
  616. return builder.Data(await _azureCosmos.SaveOrUpdate(request)).build();
  617. }
  618. else
  619. {
  620. return builder.Error(ResponseCode.FAILED, "请在作答时间段内提交答案!").build();
  621. }
  622. }
  623. else
  624. {
  625. return builder.Error(ResponseCode.DATA_EXIST, "考试不存在!").build();
  626. }*/
  627. }
  628. /// <summary>
  629. /// 查询评测详细信息(教师或者学生通用)
  630. /// </summary>
  631. /// <param name="request"></param>
  632. /// <returns></returns>
  633. [ProducesDefaultResponseType]
  634. //[AuthToken(Roles = "Teacher")]
  635. [HttpPost("find-summary-record")]
  636. public async Task<IActionResult> findSummaryRecord(JsonElement requert)
  637. {
  638. //var (id, school) = HttpContext.GetAuthTokenInfo();
  639. try
  640. {
  641. if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
  642. //if (!requert.TryGetProperty("code", out JsonElement school_code)) return BadRequest();
  643. if (!requert.TryGetProperty("subjectId", out JsonElement subjectId)) return BadRequest();
  644. if (!requert.TryGetProperty("code", out JsonElement school_code)) return BadRequest();
  645. if (!requert.TryGetProperty("classId", out JsonElement classId)) return BadRequest();
  646. // 如果只有学生id则返回学生参加过的考试 只返回相关摘要信息
  647. var client = _azureCosmos.GetCosmosClient();
  648. //string code = school_code.ToString().Substring(5);
  649. //ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"{school_code}"));
  650. List<object> examClassResults = new List<object>();
  651. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"select c.id, c.code,c.info,c.studentIds,c.studentAnswers,c.studentScores from c where c.examId = '{id}' and c.subjectId = '{subjectId}' and c.info.id = '{classId}'",
  652. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{school_code}") }))
  653. {
  654. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  655. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  656. {
  657. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  658. {
  659. examClassResults.Add(obj.ToObject<object>());
  660. }
  661. }
  662. }
  663. /*if (StringHelper.getKeyCount(requert) == 1 && requert.TryGetProperty("code", out JsonElement code))
  664. {
  665. List<object> props = new List<object>();
  666. await foreach (var item in client.GetContainer("TEAMModelOS", "Student").GetItemQueryStreamIterator(queryText: $"select c.id, c.code, c.examCode, c.status ,c.mark, c.score from c where c.id = {id}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamRecord-{school_code}") }))
  667. {
  668. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  669. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  670. {
  671. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  672. {
  673. props.Add(obj.ToObject<object>());
  674. }
  675. }
  676. }
  677. return Ok(new { props });
  678. }
  679. else
  680. {
  681. if (requert.TryGetProperty("examCode", out JsonElement _))
  682. {
  683. //List<string> props = new List<string> { "id", "code", "examCode", "status", "mark", "score" };
  684. //List<ExamRecord> examRecords = await _azureCosmos.FindByDict<ExamRecord>(request, props);
  685. //return builder.Data(examRecords).Extend(new Dictionary<string, object> { { "props", props } }).build();
  686. List<object> props = new List<object>();
  687. await foreach (var item in client.GetContainer("TEAMModelOS", "Student").GetItemQueryStreamIterator(queryText: $"select c.id, c.code, c.examCode, c.status ,c.mark, c.score from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamRecord-{school_code}") }))
  688. {
  689. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  690. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  691. {
  692. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  693. {
  694. props.Add(obj.ToObject<object>());
  695. }
  696. }
  697. }
  698. return Ok(new { props });
  699. }
  700. }*/
  701. return Ok(new { examClassResults });
  702. }
  703. catch (Exception ex)
  704. {
  705. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/findSummaryRecord()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  706. return BadRequest();
  707. }
  708. }
  709. //学生端查询评测列表
  710. [ProducesDefaultResponseType]
  711. //[AuthToken(Roles = "Student")]
  712. [HttpPost("find-summary-by-student")]
  713. public async Task<IActionResult> findSummaryStudent(JsonElement requert)
  714. {
  715. //ResponseBuilder builder = ResponseBuilder.custom();
  716. //var (id, school) = HttpContext.GetAuthTokenInfo();
  717. try
  718. {
  719. if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
  720. //if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
  721. if (!requert.TryGetProperty("studentId", out JsonElement studentId)) return BadRequest();
  722. if (!requert.TryGetProperty("code", out JsonElement school)) return BadRequest();
  723. var client = _azureCosmos.GetCosmosClient();
  724. var query = $"select c.id,c.code,A0.id paperId,A0.code paperCode,A0.name paperName,A0.multipleRule,A0.scope,A0.blob from c join A0 in c.papers where c.id ='{id}'";
  725. List<object> papers = new List<object>();
  726. List<object> subjects = new List<object>();
  727. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{school}") }))
  728. {
  729. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  730. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  731. {
  732. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  733. {
  734. papers.Add(obj.ToObject<object>());
  735. }
  736. }
  737. }
  738. var querySubject = $"select A0.id,A0.name from c join A0 in c.subjects where c.id ='{id}'";
  739. //List<object> props = new List<object>();
  740. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: querySubject, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{school}") }))
  741. {
  742. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  743. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  744. {
  745. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  746. {
  747. subjects.Add(obj.ToObject<object>());
  748. }
  749. }
  750. }
  751. var queryAnswers = $"select c.id,c.code,c.studentIds,c.subjectId,c.studentAnswers,c.studentScores,c.sum from c where c.examId ='{id}' and array_contains(c.studentIds,'{studentId}') and c.pk = 'ExamClassResult' ";
  752. List<ExamClassResult> answers = new List<ExamClassResult>();
  753. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: queryAnswers,
  754. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{school}") }))
  755. {
  756. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  757. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  758. {
  759. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  760. {
  761. answers.Add(obj.ToObject<ExamClassResult>());
  762. }
  763. }
  764. }
  765. List<List<string>> stuAns = new List<List<string>>();
  766. List<List<double>> stuScore = new List<List<double>>();
  767. List<double> total = new List<double>();
  768. if (answers.Count > 0)
  769. {
  770. foreach (ExamClassResult result in answers) {
  771. int index = result.studentIds.IndexOf(studentId.ToString());
  772. if (index == -1)
  773. {
  774. break;
  775. }
  776. stuAns.Add(result.studentAnswers[index]);
  777. stuScore.Add(result.studentScores[index]);
  778. total.Add(result.sum.Where(s => s <= 59).Count());
  779. total.Add(result.sum.Where(s => s > 59 && s <= 70 ).Count());
  780. total.Add(result.sum.Where(s => s > 70 && s <= 80).Count());
  781. total.Add(result.sum.Where(s => s > 80 && s <= 90).Count());
  782. total.Add(result.sum.Where(s => s > 90 && s <= 100).Count());
  783. }
  784. }
  785. return Ok(new { papers, subjects,stuScore, stuAns, total });
  786. }
  787. catch (Exception ex)
  788. {
  789. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/find-summary-by-student()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  790. return BadRequest();
  791. }
  792. }
  793. //查询学生活动列表
  794. [ProducesDefaultResponseType]
  795. //[AuthToken(Roles = "Student")]
  796. [HttpPost("find-all-by-student")]
  797. public async Task<IActionResult> findAllStudent(JsonElement requert)
  798. {
  799. //ResponseBuilder builder = ResponseBuilder.custom();
  800. //var (id, school) = HttpContext.GetAuthTokenInfo();
  801. try
  802. {
  803. if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
  804. if (!requert.TryGetProperty("studentId", out JsonElement studentId)) return BadRequest();
  805. //if (!requert.TryGetProperty("school", out JsonElement school)) return BadRequest();
  806. var client = _azureCosmos.GetCosmosClient();
  807. var query = $"select c.id,c.code,c.name,c.startTime,c.endTime,c.type,c.progress,c.school,c.scope from c where array_contains(c.targetClassIds,'{id}') and c.progress != 'pending' ";
  808. List<object> props = new List<object>();
  809. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: query))
  810. {
  811. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  812. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  813. {
  814. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  815. {
  816. props.Add(obj.ToObject<object>());
  817. }
  818. }
  819. }
  820. var queryClass = $"select c.examId,c.subjectId,c.studentIds,c.studentAnswers,c.studentScores from c where array_contains(c.studentIds,'{studentId}') and c.pk = 'ExamClassResult'";
  821. List<ExamClassResult> Classes = new List<ExamClassResult>();
  822. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: queryClass))
  823. {
  824. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  825. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  826. {
  827. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  828. {
  829. Classes.Add(obj.ToObject<ExamClassResult>());
  830. }
  831. }
  832. }
  833. List<ExamClassResult> result = new List<ExamClassResult>();
  834. foreach (ExamClassResult classResult in Classes) {
  835. int index = classResult.studentIds.IndexOf(studentId.ToString());
  836. ExamClassResult result1 = new ExamClassResult();
  837. result1.examId = classResult.examId;
  838. result1.subjectId = classResult.subjectId;
  839. result1.studentAnswers.Add(classResult.studentAnswers[index]);
  840. result1.studentScores.Add(classResult.studentScores[index]);
  841. result.Add(result1);
  842. }
  843. return Ok(new {props, result });
  844. }
  845. catch (Exception ex)
  846. {
  847. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/findAllStudent\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  848. return BadRequest();
  849. }
  850. }
  851. //查询学生活动列表
  852. [ProducesDefaultResponseType]
  853. //[AuthToken(Roles = "Student")]
  854. [HttpPost("find-score-by-student")]
  855. public async Task<IActionResult> findScoreByStudent(JsonElement requert)
  856. {
  857. //ResponseBuilder builder = ResponseBuilder.custom();
  858. //var (id, school) = HttpContext.GetAuthTokenInfo();
  859. try
  860. {
  861. if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
  862. //if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
  863. var client = _azureCosmos.GetCosmosClient();
  864. var query = $"select c.examId,c.subjectId,c.studentScores from c where array_contains(c.studentIds,'{id}') ";
  865. List<object> props = new List<object>();
  866. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: query))
  867. {
  868. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  869. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  870. {
  871. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  872. {
  873. props.Add(obj.ToObject<object>());
  874. }
  875. }
  876. }
  877. return Ok(props);
  878. }
  879. catch (Exception ex)
  880. {
  881. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/findAllStudent\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  882. return BadRequest();
  883. }
  884. }
  885. //查询学生活动列表
  886. [ProducesDefaultResponseType]
  887. //[AuthToken(Roles = "Student")]
  888. [HttpPost("finish")]
  889. public async Task<IActionResult> finish(JsonElement requert)
  890. {
  891. //ResponseBuilder builder = ResponseBuilder.custom();
  892. //var (id, school) = HttpContext.GetAuthTokenInfo();
  893. try
  894. {
  895. if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
  896. if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
  897. var client = _azureCosmos.GetCosmosClient();
  898. ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{code}"));
  899. info.progress = "finish";
  900. info = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(info, info.id, new PartitionKey($"Exam-{code}"));
  901. return Ok(info);
  902. }
  903. catch (Exception ex)
  904. {
  905. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/finish\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  906. return BadRequest();
  907. }
  908. }
  909. }
  910. }