ManageController.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. using IES.ExamLibrary.Models;
  2. using IES.ExamServer.DI;
  3. using IES.ExamServer.DI.SignalRHost;
  4. using IES.ExamServer.Filters;
  5. using IES.ExamServer.Helper;
  6. using IES.ExamServer.Helpers;
  7. using IES.ExamServer.Models;
  8. using Microsoft.AspNetCore.Mvc;
  9. using Microsoft.AspNetCore.SignalR;
  10. using Microsoft.Extensions.Caching.Memory;
  11. using Microsoft.Extensions.Configuration;
  12. using System.Linq.Expressions;
  13. using System.Net.Http;
  14. using System.Net.Http.Json;
  15. using System.Text.Json;
  16. using System.Text.Json.Nodes;
  17. namespace IES.ExamServer.Controllers
  18. {
  19. [ApiController]
  20. [Route("manage")]
  21. public class ManageController:BaseController
  22. {
  23. private readonly IConfiguration _configuration;
  24. private readonly IHttpClientFactory _httpClientFactory;
  25. private readonly IMemoryCache _memoryCache;
  26. private readonly ILogger<ManageController> _logger;
  27. private readonly LiteDBFactory _liteDBFactory;
  28. private readonly CenterServiceConnectionService _connectionService;
  29. private readonly int DelayMicro = 10;//微观数据延迟
  30. private readonly int DelayMacro = 100;//宏观数据延迟
  31. private readonly IHubContext<SignalRExamServerHub> _signalRExamServerHub;
  32. public ManageController(LiteDBFactory liteDBFactory,ILogger<ManageController> logger, IConfiguration configuration,
  33. IHttpClientFactory httpClientFactory, IMemoryCache memoryCache, CenterServiceConnectionService connectionService, IHubContext<SignalRExamServerHub> signalRExamServerHub)
  34. {
  35. _logger = logger;
  36. _configuration=configuration;
  37. _httpClientFactory=httpClientFactory;
  38. _memoryCache=memoryCache;
  39. _liteDBFactory=liteDBFactory;
  40. _connectionService=connectionService;
  41. _signalRExamServerHub=signalRExamServerHub;
  42. }
  43. ///通过线上回传数据需要鉴权验证等操作。
  44. ///通过离线包回传数据需要加密操作
  45. /// <summary>
  46. /// 清理缓存,列出缓存占用空间,type =list列出,type=clear清理,不能清理近期及正在激活的数据,并且提示清理中暂未上传或者导出的数据。
  47. /// </summary>
  48. /// <param name="json"></param>
  49. /// <returns></returns>
  50. [HttpPost("clean-cache")]
  51. [AuthToken("admin", "teacher", "visitor")]
  52. public async Task<IActionResult> CleanCache(JsonNode json)
  53. {
  54. return Ok();
  55. }
  56. [HttpPost("download-package")]
  57. [AuthToken("admin","teacher", "visitor")]
  58. public async Task<IActionResult> DownloadPackage(JsonNode json)
  59. {
  60. //C#.NET 6 后端与前端流式通信
  61. //https://www.doubao.com/chat/collection/687687510791426?type=Thread
  62. //下载日志记录:1.步骤,检查,2.获取描述信息,3.分类型,4下载文件,5.前端处理,6.返回结果 , 正在下载...==> [INFO]https://www.doubao.com/chat/collection/687687510791426?type=Thread [Size=180kb] Ok...
  63. //进度条 展示下载文件总大小和已下载,末尾展示 文件总个数和已下载个数
  64. //https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.7/signalr.min.js
  65. /* int data = 0,blob=0,webview=0, groupList=0
  66. {
  67. "evaluationId":"idssss",
  68. "shortCode":"1234567890",
  69. "ownerId":"hbcn/tmdid",
  70. "data":1,
  71. "blob":1,
  72. "webview":1,
  73. "groupList":1
  74. }
  75. */
  76. //如果要访问中心,则需要教师登录联网。
  77. var token = GetAuthTokenInfo();
  78. if (token.scope.Equals(ExamConstant.ScopeTeacher))
  79. {
  80. if (_connectionService.centerIsConnected)
  81. {
  82. Teacher? teacher = _liteDBFactory.GetLiteDatabase().GetCollection<Teacher>().FindOne(x => x.id!.Equals(token.id));
  83. if (teacher != null)
  84. {
  85. string? CenterUrl = _configuration.GetValue<string>("ExamServer:CenterUrl");
  86. var client = _httpClientFactory.CreateClient();
  87. if (client.DefaultRequestHeaders.Contains(Constant._X_Auth_AuthToken))
  88. {
  89. client.DefaultRequestHeaders.Remove(Constant._X_Auth_AuthToken);
  90. }
  91. client.DefaultRequestHeaders.Add(Constant._X_Auth_AuthToken, teacher.x_auth_token);
  92. HttpResponseMessage message = await client.PostAsJsonAsync($"{CenterUrl}/blob/sas-read", new { containerName = $"{json["ownerId"]}" });
  93. string sas = string.Empty;
  94. string url = string.Empty;
  95. string cnt = string.Empty;
  96. if (message.IsSuccessStatusCode)
  97. {
  98. //url sas timeout name
  99. string content = await message.Content.ReadAsStringAsync();
  100. JsonNode? jsonNode = content.ToObject<JsonNode>();
  101. if (jsonNode != null)
  102. {
  103. sas = $"{jsonNode["sas"]}";
  104. cnt = $"{jsonNode["name"]}";
  105. }
  106. }
  107. var httpClient= _httpClientFactory.CreateClient();
  108. if ($"{json["data"]}".Equals("1"))
  109. {
  110. await httpClient.GetAsync($"{url}/{cnt}/exam/{json["evaluationId"]}/package/evaluation.json");
  111. }
  112. if ($"{json["groupList"]}".Equals("1"))
  113. {
  114. await httpClient.GetAsync($"{url}/{cnt}/exam/{json["evaluationId"]}/package/grouplist.json");
  115. }
  116. if ($"{json["blob"]}".Equals("1"))
  117. {
  118. await httpClient.GetAsync($"{url}/{cnt}/exam/{json["evaluationId"]}/paper");
  119. }
  120. if ($"{json["webview"]}".Equals("1"))
  121. {
  122. //await httpClient.GetAsync($"{url}/{cnt}/exam/{json["evaluationId"]}/evaluation.json");
  123. }
  124. }
  125. }
  126. }
  127. return Ok();
  128. }
  129. [HttpPost("check-evaluation")]
  130. [AuthToken("admin", "teacher", "visitor")]
  131. public async Task<IActionResult> CheckEvaluation(JsonNode json)
  132. {
  133. string shortCode = $"{json["shortCode"]}";
  134. string evaluationId = $"{json["evaluationId"]}";
  135. string checkCenter = $"{json["checkCenter"]}";
  136. string deviceId = $"{json["deviceId"]}";
  137. string centerCode = string.Empty, centerMsg = string.Empty;
  138. Expression<Func<EvaluationClient, bool>> predicate = x => true;
  139. var token = GetAuthTokenInfo();
  140. int checkTotal = 0, checkSuccess = 0, checkError = 0, checkWarning = 0;
  141. int msg_status = Constant._Message_status_info;
  142. if (!string.IsNullOrEmpty(shortCode) || !string.IsNullOrEmpty(evaluationId))
  143. {
  144. if (!string.IsNullOrEmpty(shortCode))
  145. {
  146. predicate= predicate.And(x => !string.IsNullOrWhiteSpace(x.shortCode) && x.shortCode.Equals(shortCode));
  147. }
  148. if (!string.IsNullOrWhiteSpace(evaluationId))
  149. {
  150. predicate= predicate.And(x => x.id!.Equals(evaluationId));
  151. }
  152. }
  153. else
  154. {
  155. return Ok(new { code = 400, msg = "评测ID或提取码均未填写!" });
  156. }
  157. IEnumerable<EvaluationClient>? evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Find(predicate);
  158. EvaluationClient? evaluationLocal = null;
  159. EvaluationClient? evaluationCloud = null;
  160. if (evaluationClients!=null && evaluationClients.Count()>0)
  161. {
  162. evaluationLocal= evaluationClients.First();
  163. }
  164. //从数据中心搜索
  165. if ("1".Equals($"{checkCenter}") )
  166. {
  167. if (_connectionService.centerIsConnected)
  168. {
  169. if (token.scope.Equals(ExamConstant.ScopeTeacher) || token.scope.Equals(ExamConstant.ScopeVisitor))//由于已经绑定学校,访客教师也可以访问中心。
  170. {
  171. Teacher? teacher = _liteDBFactory.GetLiteDatabase().GetCollection<Teacher>().FindOne(x => x.id!.Equals(token.id));
  172. if (teacher != null)
  173. {
  174. string? CenterUrl = _configuration.GetValue<string>("ExamServer:CenterUrl");
  175. var client = _httpClientFactory.CreateClient();
  176. if (client.DefaultRequestHeaders.Contains(Constant._X_Auth_AuthToken))
  177. {
  178. client.DefaultRequestHeaders.Remove(Constant._X_Auth_AuthToken);
  179. }
  180. client.DefaultRequestHeaders.Add(Constant._X_Auth_AuthToken, teacher.x_auth_token);
  181. try
  182. {
  183. HttpResponseMessage message = await client.PostAsJsonAsync($"{CenterUrl}/evaluation-sync/find-sync-info", new { shortCode, evaluationId });
  184. if (message.IsSuccessStatusCode)
  185. {
  186. string content = await message.Content.ReadAsStringAsync();
  187. JsonNode? jsonNode = content.ToObject<JsonNode>();
  188. if (jsonNode != null)
  189. {
  190. centerCode = $"{jsonNode["code"]}";
  191. centerMsg = $"{jsonNode["msg"]}";
  192. if ($"{jsonNode["code"]}".Equals("200"))
  193. {
  194. evaluationCloud = jsonNode["evaluation"]?.ToObject<EvaluationClient>();
  195. }
  196. }
  197. else
  198. {
  199. centerCode = "500";
  200. centerMsg = "数据转换异常";
  201. }
  202. }
  203. else
  204. {
  205. centerCode = $"{message.StatusCode}";
  206. centerMsg = "数据中心访问异常";
  207. }
  208. }
  209. catch (Exception ex)
  210. {
  211. centerCode = $"500";
  212. centerMsg = $"数据中心访问异常:{ex.Message}";
  213. }
  214. }
  215. else
  216. {
  217. centerCode = $"401";
  218. centerMsg = "当前登录账号未找到";
  219. }
  220. }
  221. }
  222. else
  223. {
  224. centerCode = $"404";
  225. centerMsg = "云端数据中心未连接";
  226. }
  227. if (centerCode.Equals("200"))
  228. {
  229. msg_status=Constant._Message_status_success;
  230. checkTotal++;
  231. checkSuccess++;
  232. }
  233. else
  234. {
  235. msg_status=Constant._Message_status_warning;
  236. checkTotal++;
  237. checkWarning++;
  238. }
  239. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  240. new MessageContent { dataId=evaluationCloud?.id, dataName=evaluationCloud?.name, messageType=Constant._Message_type_message, status=msg_status, content=$"云端数据检测结果:{centerMsg},状态:{centerCode}" });
  241. }
  242. //数据,文件,页面 0 没有更新,1 有更新
  243. int data = 0, blob = 0, webview = 0, groupList = 0, status = 0;
  244. long dataSize = 0, blobSize = 0, webviewSize = 0, studentCount = 0;
  245. if (evaluationLocal== null && evaluationCloud==null)
  246. {
  247. //线上线下没有数据
  248. status=1;
  249. }
  250. else if (evaluationLocal!=null && evaluationCloud!=null)
  251. {
  252. //线上线下有数据
  253. status = 2;
  254. if ((!string.IsNullOrWhiteSpace(evaluationLocal.blobHash) && !evaluationLocal.blobHash.Equals(evaluationCloud.blobHash))
  255. ||(evaluationLocal.blobTime<evaluationCloud.blobTime)
  256. ||(evaluationLocal.blobCount!= evaluationCloud.blobCount)
  257. ||(evaluationLocal.blobSize!= evaluationCloud.blobSize))
  258. {
  259. blob=1;
  260. blobSize=evaluationCloud.blobSize;
  261. }
  262. if ((evaluationLocal.dataTime<evaluationCloud.dataTime)
  263. ||(evaluationLocal.dataSize!=evaluationCloud.dataSize)
  264. ||(evaluationLocal.paperCount!= evaluationCloud.paperCount)
  265. )
  266. {
  267. data=1;
  268. dataSize=evaluationCloud.dataSize;
  269. }
  270. //if ((evaluationLocal.webviewCount!=evaluationCloud.webviewCount)
  271. // ||(evaluationLocal.webviewSize!= evaluationCloud.webviewSize)
  272. // ||(evaluationLocal.webviewTime!= evaluationCloud.webviewTime)
  273. // ||(!string.IsNullOrWhiteSpace(evaluationLocal.webviewPath)&& !evaluationLocal.webviewPath.Equals(evaluationCloud.webviewPath)))
  274. //{
  275. // webview=1;
  276. // webviewSize=evaluationCloud.webviewSize;
  277. //}
  278. if ((evaluationLocal.studentCount!= evaluationCloud.studentCount)||(!$"{evaluationLocal.grouplistHash}".Equals(evaluationCloud.grouplistHash)))
  279. {
  280. groupList=1;
  281. studentCount=evaluationCloud.studentCount;
  282. }
  283. }
  284. else if (evaluationLocal!=null && evaluationCloud==null)
  285. {
  286. //线下有数据,线上没有数据,可能没联网。
  287. status = 3;
  288. }
  289. else if (evaluationLocal==null && evaluationCloud!=null)
  290. {
  291. //线下没有数据,线上有数据
  292. evaluationLocal= evaluationCloud;
  293. blob=1;
  294. data=1;
  295. webview=1;
  296. groupList=1;
  297. blobSize=evaluationCloud.blobSize;
  298. dataSize=evaluationCloud.dataSize;
  299. // webviewSize=evaluationCloud.webviewSize;
  300. studentCount=evaluationCloud.studentCount;
  301. status = 4;
  302. _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Insert(evaluationLocal);
  303. }
  304. if (evaluationLocal!=null)
  305. {
  306. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  307. new MessageContent { dataId=evaluationLocal.id, dataName=evaluationLocal.name, messageType=Constant._Message_type_message, status=0, content="开始检查评测信息文件.." });
  308. //校验本地文件数据
  309. string packagePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "package");
  310. if (!Directory.Exists(packagePath))
  311. {
  312. Directory.CreateDirectory(packagePath);
  313. }
  314. string evaluationPath = Path.Combine(packagePath, evaluationLocal.id!);
  315. string evaluationDataPath = Path.Combine(evaluationPath, "data");
  316. // await Task.Delay(DelayMacro);
  317. //await Task.Delay(DelayMacro);
  318. string path_groupList = Path.Combine(evaluationDataPath, "groupList.json");
  319. msg_status =Constant._Message_status_info;
  320. if (!System.IO.File.Exists(path_groupList))
  321. {
  322. groupList=1;
  323. msg_status=Constant._Message_status_error;
  324. checkTotal++;
  325. checkError++;
  326. }
  327. else
  328. {
  329. msg_status=Constant._Message_status_success;
  330. checkTotal++;
  331. checkSuccess++;
  332. }
  333. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  334. new MessageContent { dataId=evaluationLocal.id, dataName=evaluationLocal.name, messageType= Constant._Message_type_check, status=msg_status, content=$"评测名单文件:{path_groupList}" });
  335. //await Task.Delay(DelayMacro);
  336. string path_source = Path.Combine(evaluationDataPath, "source.json");
  337. msg_status = Constant._Message_status_info;
  338. if (!System.IO.File.Exists(path_source))
  339. {
  340. data=1;
  341. msg_status=Constant._Message_status_error;
  342. checkTotal++;
  343. checkError++;
  344. }
  345. else
  346. {
  347. msg_status=Constant._Message_status_success;
  348. checkTotal++;
  349. checkSuccess++;
  350. }
  351. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  352. new MessageContent { dataId=evaluationLocal.id, dataName=evaluationLocal.name, messageType= Constant._Message_type_check, status=msg_status, content=$"评测原始数据:{path_source}" });
  353. msg_status =Constant._Message_status_info;
  354. try
  355. {
  356. //TODO 重整本地文件路径。 文件可能不存在D:\VisualStudioProjects\TEAMModelOS\TEAMModelOS.Extension\IES.Exam\IES.ExamServer\wwwroot\package\exam\6af32bbd-144e-4366-8bc0-61ba4c85677c\evaluation.json
  357. string path_evaluation = Path.Combine(evaluationDataPath, "evaluation.json");
  358. if (!System.IO.File.Exists(path_evaluation))
  359. {
  360. blob=1;
  361. data=1;
  362. msg_status=Constant._Message_status_error;
  363. checkTotal++;
  364. checkError++;
  365. }
  366. else
  367. {
  368. msg_status=Constant._Message_status_success;
  369. checkTotal++;
  370. checkSuccess++;
  371. }
  372. //数据格式: [消息][信息/错误/警告][15:43]=>[开始检查评测信息文件...]
  373. //数据格式: [检查][成功/失败][15:43]=>[评测数据文件:/wwwroot/package/623a9fe6-5445-0938-ff77-aeb80066ef27/evaluation.json]
  374. //数据格式: [下载][成功/失败][15:43]=>[评测数据文件:/wwwroot/package/623a9fe6-5445-0938-ff77-aeb80066ef27/evaluation.json][1024kb][15ms]
  375. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  376. new MessageContent { dataId=evaluationLocal.id, dataName=evaluationLocal.name, messageType= Constant._Message_type_check, status=msg_status, content=$"评测数据文件:{path_evaluation}" });
  377. if (System.IO.File.Exists(path_evaluation))
  378. {
  379. string evaluation_str = await System.IO.File.ReadAllTextAsync(path_evaluation);
  380. JsonNode? evaluation_data = evaluation_str.ToObject<JsonNode>();
  381. if (evaluation_data==null)
  382. {
  383. blob=1;
  384. data=1;
  385. }
  386. else
  387. {
  388. EvaluationClient? evaluationClient = evaluation_data["evaluationClient"]?.ToObject<EvaluationClient>();
  389. if (evaluationClient!=null)
  390. {
  391. if (!string.IsNullOrWhiteSpace(evaluationLocal.blobHash) && evaluationLocal.blobHash.Equals(evaluationClient.blobHash)
  392. &&(evaluationLocal.blobTime==evaluationClient.blobTime)
  393. &&(evaluationLocal.blobCount== evaluationClient.blobCount)
  394. &&(evaluationLocal.blobSize== evaluationClient.blobSize)
  395. && (evaluationLocal.dataTime==evaluationClient.dataTime)
  396. &&(evaluationLocal.dataSize==evaluationClient.dataSize)
  397. //&&(evaluationLocal.webviewCount==evaluationClient.webviewCount)
  398. //&&(evaluationLocal.webviewSize== evaluationClient.webviewSize)
  399. //&&(evaluationLocal.webviewTime== evaluationClient.webviewTime)
  400. //&&!string.IsNullOrWhiteSpace(evaluationLocal.webviewPath)
  401. //&& evaluationLocal.webviewPath.Equals(evaluationClient.webviewPath)
  402. )
  403. {
  404. msg_status=Constant._Message_status_info;
  405. }
  406. else
  407. {
  408. data=1;
  409. msg_status=Constant._Message_status_error;
  410. }
  411. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  412. new MessageContent { dataId=evaluationLocal.id, dataName=evaluationLocal.name, messageType=Constant._Message_type_message, status=msg_status, content="校验本地试卷文件..." });
  413. }
  414. else { data=1; }
  415. List<EvaluationExam>? evaluationExams = evaluation_data["evaluationExams"]?.ToObject<List<EvaluationExam>>();
  416. if (evaluationExams.IsEmpty())
  417. {
  418. blob=1;
  419. data=1;
  420. }
  421. else
  422. {
  423. foreach (var evaluationExam in evaluationExams!)
  424. {
  425. string path_papers = Path.Combine(evaluationPath, "exams");
  426. var papers_files = FileHelper.ListAllFiles(path_papers);
  427. int paperIndex = 0;
  428. foreach (var paper in evaluationExam.papers)
  429. {
  430. paperIndex++;
  431. List<MessageContent> contents = new List<MessageContent>();
  432. int paper_error_count = 0;
  433. foreach (var blobInfo in paper.blobs)
  434. {
  435. msg_status=Constant._Message_status_info;
  436. if (!string.IsNullOrWhiteSpace(blobInfo.path))
  437. {
  438. var file = papers_files.Find(x => x.Contains(blobInfo.path));
  439. if (file!=null)
  440. {
  441. msg_status=1;
  442. msg_status=Constant._Message_status_success;
  443. }
  444. else
  445. {
  446. msg_status=Constant._Message_status_error;
  447. paper_error_count++;
  448. }
  449. }
  450. else
  451. {
  452. msg_status=Constant._Message_status_warning; ;
  453. paper_error_count++;
  454. }
  455. contents.Add(new MessageContent
  456. {
  457. dataId=evaluationLocal.id,
  458. dataName=evaluationLocal.name,
  459. messageType=Constant._Message_type_check,
  460. status=msg_status,
  461. content=$"试卷文件信息:{paper.paperName}"
  462. });
  463. }
  464. int paper_msg_status = Constant._Message_status_info;
  465. if (paper_error_count>0)
  466. {
  467. blob=1;
  468. paper_msg_status=Constant._Message_status_error;
  469. }
  470. else
  471. {
  472. paper_msg_status=Constant._Message_status_success;
  473. }
  474. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  475. new MessageContent
  476. {
  477. dataId=evaluationLocal.id,
  478. dataName=evaluationLocal.name,
  479. messageType=Constant._Message_type_message,
  480. status=paper_msg_status,
  481. content=$"试卷名称:[{paperIndex}]{evaluationExam.examName}-{evaluationExam.subjectName}-{paper.paperName}\r\n文件数量:{paper.blobs.Count()},检测成功数量:{contents.Count(x => x.status==Constant._Message_status_success)},检测异常数量{contents.Count(x => x.status==Constant._Message_status_error)}",
  482. contents=contents
  483. });
  484. }
  485. }
  486. }
  487. }
  488. }
  489. }
  490. catch (Exception e)
  491. {
  492. _logger.LogData<object>(new { code = 500, msg = e.Message, data = new { content = e.StackTrace } }, evaluationLocal.id!);
  493. }
  494. //检查需要更新的项目:
  495. if (data==1)
  496. {
  497. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  498. new MessageContent
  499. {
  500. dataId=evaluationLocal.id,
  501. dataName=evaluationLocal.name,
  502. messageType=Constant._Message_type_message,
  503. status=Constant._Message_status_warning,
  504. content=$"检查到评测数据需要更新。[{dataSize}]"
  505. });
  506. }
  507. if (blob==1)
  508. {
  509. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  510. new MessageContent
  511. {
  512. dataId=evaluationLocal.id,
  513. dataName=evaluationLocal.name,
  514. messageType=Constant._Message_type_message,
  515. status=Constant._Message_status_warning,
  516. content=$"检查到评测试卷需要更新。[{blobSize}]"
  517. });
  518. }
  519. if (webview==1)
  520. {
  521. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  522. new MessageContent
  523. {
  524. dataId=evaluationLocal.id,
  525. dataName=evaluationLocal.name,
  526. messageType=Constant._Message_type_message,
  527. status=Constant._Message_status_warning,
  528. content=$"检查到评测作答页面需要更新。[{webviewSize}]"
  529. });
  530. }
  531. if (groupList==1)
  532. {
  533. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  534. new MessageContent
  535. {
  536. dataId=evaluationLocal.id,
  537. dataName=evaluationLocal.name,
  538. messageType=Constant._Message_type_message,
  539. status=Constant._Message_status_warning,
  540. content=$"检查到评测名单需要更新。[{studentCount}]"
  541. });
  542. }
  543. }
  544. int finalStatus = Constant._Message_status_success;
  545. if (checkWarning>0)
  546. {
  547. finalStatus = Constant._Message_status_warning;
  548. }
  549. if (checkError>0)
  550. {
  551. finalStatus = Constant._Message_status_error;
  552. }
  553. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  554. new MessageContent
  555. {
  556. dataId=evaluationLocal?.id,
  557. dataName=evaluationLocal?.name,
  558. messageType=Constant._Message_type_message,
  559. status=Constant._Message_status_warning,
  560. content=$"最终检测结果:总数({checkTotal}),成功({checkSuccess}),警告({checkWarning}),异常({checkError})。"
  561. });
  562. return Ok(new
  563. {
  564. code = 200,
  565. evaluation = evaluationLocal,
  566. data,
  567. blob,
  568. webview,
  569. dataSize,
  570. blobSize,
  571. webviewSize,
  572. status,
  573. groupList,
  574. studentCount,
  575. checkTotal,
  576. checkSuccess,
  577. checkError,
  578. checkWarning,
  579. });
  580. }
  581. /// <summary>
  582. /// 激活或者取消激活考试
  583. /// </summary>
  584. /// <param name="json"></param>
  585. /// <returns></returns>
  586. [HttpPost("activate-evaluation")]
  587. [AuthToken("admin", "teacher", "visitor")]
  588. public IActionResult ActivateEvaluation(JsonNode json)
  589. {
  590. string id = $"{json["id"]}";
  591. string shortCode = $"{json["shortCode"]}";
  592. string activateStr = $"{json["activate"]}";
  593. if (!string.IsNullOrWhiteSpace(id) && !string.IsNullOrWhiteSpace(shortCode))
  594. {
  595. EvaluationClient? evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindOne(x => x.id!.Equals(id) && !string.IsNullOrWhiteSpace(x.shortCode) && x.shortCode.Equals(shortCode));
  596. if (evaluationClient != null)
  597. {
  598. IEnumerable<EvaluationClient> evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Find(x=>x.activate==1);
  599. if (evaluationClients != null && evaluationClients.Count() > 0)
  600. {
  601. foreach(EvaluationClient item in evaluationClients)
  602. {
  603. item.activate = 0;
  604. _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Upsert(item);
  605. }
  606. }
  607. int activate = 0;
  608. if (int.TryParse(activateStr, out int _activate)) {
  609. activate = _activate;
  610. }
  611. evaluationClient.activate = activate;
  612. _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Upsert(evaluationClient);
  613. }
  614. }
  615. return Ok();
  616. }
  617. /// <summary>
  618. /// 加载本地的活动列表
  619. /// </summary>
  620. /// <param name="json"></param>
  621. /// <returns></returns>
  622. [HttpPost("list-local-c")]
  623. [AuthToken("admin", "teacher", "visitor")]
  624. public IActionResult ListLocalEvaluation(JsonNode json)
  625. {
  626. IEnumerable<EvaluationClient>? evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindAll().OrderByDescending(x=>x.activate).ThenByDescending(x=>x.stime);
  627. if (evaluationClients != null)
  628. {
  629. var result = evaluationClients.Select(client =>
  630. {
  631. var properties = client.GetType().GetProperties();
  632. var anonymousObject = new Dictionary<string, object?>();
  633. foreach (var property in properties)
  634. {
  635. if (!property.Name.Equals("password") && !property.Name.Equals("openCode"))
  636. {
  637. anonymousObject[property.Name] = property.GetValue(client);
  638. }
  639. }
  640. return anonymousObject;
  641. });
  642. return Ok(new { code = 200, evaluation = result });
  643. }
  644. else {
  645. return Ok(new { code = 200, evaluation = new Dictionary<string, object?>() });
  646. }
  647. }
  648. }
  649. }