ManageController.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. using IES.ExamLib.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 DataCenterConnectionService _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, DataCenterConnectionService 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")]
  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.dataCenterIsConnected)
  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-short-code")]
  130. [AuthToken("admin", "teacher", "visitor")]
  131. public async Task<IActionResult> CheckShortCode(JsonNode json)
  132. {
  133. string shortCode = $"{json["shortCode"]}";
  134. string evaluationId = $"{json["evaluationId"]}";
  135. string deviceId = $"{json["deviceId"]}";
  136. string centerCode= string.Empty, centerMsg= string.Empty;
  137. Expression<Func<EvaluationClient, bool>> predicate = x => true;
  138. int checkTotal = 0, checkSuccess = 0, checkError = 0, checkWarning = 0;
  139. int msg_status = Constant._Message_status_info;
  140. if (!string.IsNullOrEmpty(shortCode))
  141. {
  142. var codePredicate = ExpressionHelper.Or<EvaluationClient>(
  143. x => !string.IsNullOrWhiteSpace(x.shortCode) && x.shortCode == shortCode,
  144. x => !string.IsNullOrWhiteSpace(x.password) && x.password == shortCode
  145. );
  146. predicate= predicate.And(codePredicate);
  147. }
  148. else {
  149. return Ok(new { code = 400,msg="必须输入开卷码" });
  150. }
  151. if (!string.IsNullOrWhiteSpace(evaluationId))
  152. {
  153. predicate= predicate.And(x => x.id!.Equals(evaluationId));
  154. }
  155. IEnumerable<EvaluationClient>? evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Find(predicate);
  156. EvaluationClient? evaluationLocal = null;
  157. EvaluationClient? evaluationCloud = null;
  158. if (evaluationClients!=null && evaluationClients.Count()>0)
  159. {
  160. evaluationLocal= evaluationClients.First();
  161. }
  162. //如果要访问中心,则需要教师登录联网。
  163. var token = GetAuthTokenInfo();
  164. if (token.scope.Equals(ExamConstant.ScopeTeacher))
  165. {
  166. if (_connectionService.dataCenterIsConnected)
  167. {
  168. Teacher? teacher = _liteDBFactory.GetLiteDatabase().GetCollection<Teacher>().FindOne(x => x.id!.Equals(token.id));
  169. if (teacher != null)
  170. {
  171. string? CenterUrl = _configuration.GetValue<string>("ExamServer:CenterUrl");
  172. var client = _httpClientFactory.CreateClient();
  173. if (client.DefaultRequestHeaders.Contains(Constant._X_Auth_AuthToken))
  174. {
  175. client.DefaultRequestHeaders.Remove(Constant._X_Auth_AuthToken);
  176. }
  177. client.DefaultRequestHeaders.Add(Constant._X_Auth_AuthToken, teacher.x_auth_token);
  178. try {
  179. HttpResponseMessage message = await client.PostAsJsonAsync($"{CenterUrl}/evaluation-sync/find-sync-info", new { shortCode, evaluationId });
  180. if (message.IsSuccessStatusCode)
  181. {
  182. string content = await message.Content.ReadAsStringAsync();
  183. JsonNode? jsonNode = content.ToObject<JsonNode>();
  184. if (jsonNode != null)
  185. {
  186. centerCode = $"{jsonNode["code"]}";
  187. centerMsg = $"{jsonNode["msg"]}";
  188. if ($"{jsonNode["code"]}".Equals("200"))
  189. {
  190. evaluationCloud = jsonNode["evaluation"]?.ToObject<EvaluationClient>();
  191. }
  192. }
  193. else
  194. {
  195. centerCode = "500";
  196. centerMsg = "数据转换异常";
  197. }
  198. }
  199. else
  200. {
  201. centerCode = $"{message.StatusCode}";
  202. centerMsg = "数据中心访问异常";
  203. }
  204. } catch (Exception ex) {
  205. centerCode = $"500";
  206. centerMsg = $"数据中心访问异常:{ex.Message}";
  207. }
  208. }
  209. else
  210. {
  211. centerCode = $"401";
  212. centerMsg = "当前登录账号未找到";
  213. }
  214. }
  215. else
  216. {
  217. centerCode = $"404";
  218. centerMsg = "云端数据中心未连接";
  219. }
  220. if (centerCode.Equals("200"))
  221. {
  222. msg_status=Constant._Message_status_success;
  223. checkTotal++;
  224. checkSuccess++;
  225. }
  226. else
  227. {
  228. msg_status=Constant._Message_status_warning;
  229. checkTotal++;
  230. checkWarning++;
  231. }
  232. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  233. new MessageContent { dataId=evaluationCloud?.id, dataName=evaluationCloud?.name, messageType=Constant._Message_type_message, status=msg_status, content=$"云端数据检测结果:{centerMsg},状态:{centerCode}" });
  234. }
  235. //数据,文件,页面 0 没有更新,1 有更新
  236. int data = 0,blob=0,webview=0, groupList=0, status=0;
  237. long dataSize = 0, blobSize=0 , webviewSize=0, studentCount=0;
  238. if (evaluationLocal== null && evaluationCloud==null)
  239. {
  240. //线上线下没有数据
  241. status=1;
  242. }
  243. else if (evaluationLocal!=null && evaluationCloud!=null)
  244. {
  245. //线上线下有数据
  246. status = 2;
  247. if ((!string.IsNullOrWhiteSpace(evaluationLocal.blobHash) && !evaluationLocal.blobHash.Equals(evaluationCloud.blobHash))
  248. ||(evaluationLocal.blobTime<evaluationCloud.blobTime)
  249. ||(evaluationLocal.blobCount!= evaluationCloud.blobCount)
  250. ||(evaluationLocal.blobSize!= evaluationCloud.blobSize))
  251. {
  252. blob=1;
  253. blobSize=evaluationCloud.blobSize;
  254. }
  255. if ((evaluationLocal.dataTime<evaluationCloud.dataTime)
  256. ||(evaluationLocal.dataSize!=evaluationCloud.dataSize)
  257. ||(evaluationLocal.paperCount!= evaluationCloud.paperCount)
  258. )
  259. {
  260. data=1;
  261. dataSize=evaluationCloud.dataSize;
  262. }
  263. if ((evaluationLocal.webviewCount!=evaluationCloud.webviewCount)
  264. ||(evaluationLocal.webviewSize!= evaluationCloud.webviewSize)
  265. ||(evaluationLocal.webviewTime!= evaluationCloud.webviewTime)
  266. ||(!string.IsNullOrWhiteSpace(evaluationLocal.webviewPath)&& !evaluationLocal.webviewPath.Equals(evaluationCloud.webviewPath)))
  267. {
  268. webview=1;
  269. webviewSize=evaluationCloud.webviewSize;
  270. }
  271. if ((evaluationLocal.studentCount!= evaluationCloud.studentCount)||(!$"{evaluationLocal.grouplistHash}".Equals(evaluationCloud.grouplistHash)))
  272. {
  273. groupList=1;
  274. studentCount=evaluationCloud.studentCount;
  275. }
  276. }
  277. else if (evaluationLocal!=null && evaluationCloud==null)
  278. {
  279. //线下有数据,线上没有数据,可能没联网。
  280. status = 3;
  281. }
  282. else if (evaluationLocal==null && evaluationCloud!=null)
  283. {
  284. //线下没有数据,线上有数据
  285. evaluationLocal= evaluationCloud;
  286. blob=1;
  287. data=1;
  288. webview=1;
  289. groupList=1;
  290. blobSize=evaluationCloud.blobSize;
  291. dataSize=evaluationCloud.dataSize;
  292. webviewSize=evaluationCloud.webviewSize;
  293. studentCount=evaluationCloud.studentCount;
  294. status = 4;
  295. _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Insert(evaluationLocal);
  296. }
  297. if (evaluationLocal!=null)
  298. {
  299. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  300. new MessageContent {dataId=evaluationLocal.id,dataName=evaluationLocal.name,messageType=Constant._Message_type_message, status=0, content="开始检查评测信息文件.." });
  301. //校验本地文件数据
  302. string packagePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "package");
  303. if (!Directory.Exists(packagePath))
  304. {
  305. Directory.CreateDirectory(packagePath);
  306. }
  307. string evaluationPath = Path.Combine(packagePath, evaluationLocal.id!);
  308. string evaluationDataPath = Path.Combine(evaluationPath,"data");
  309. // await Task.Delay(DelayMacro);
  310. //await Task.Delay(DelayMacro);
  311. string path_groupList = Path.Combine(evaluationDataPath, "groupList.json");
  312. msg_status =Constant._Message_status_info;
  313. if (!System.IO.File.Exists(path_groupList))
  314. {
  315. groupList=1;
  316. msg_status=Constant._Message_status_error;
  317. checkTotal++;
  318. checkError++;
  319. }
  320. else
  321. {
  322. msg_status=Constant._Message_status_success;
  323. checkTotal++;
  324. checkSuccess++;
  325. }
  326. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  327. new MessageContent { dataId=evaluationLocal.id, dataName=evaluationLocal.name, messageType= Constant._Message_type_check, status=msg_status, content=$"评测名单文件:{path_groupList}" });
  328. //await Task.Delay(DelayMacro);
  329. string path_source = Path.Combine(evaluationDataPath, "source.json");
  330. msg_status = Constant._Message_status_info;
  331. if (!System.IO.File.Exists(path_source))
  332. {
  333. data=1;
  334. msg_status=Constant._Message_status_error;
  335. checkTotal++;
  336. checkError++;
  337. }
  338. else
  339. {
  340. msg_status=Constant._Message_status_success;
  341. checkTotal++;
  342. checkSuccess++;
  343. }
  344. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  345. new MessageContent { dataId=evaluationLocal.id, dataName=evaluationLocal.name, messageType= Constant._Message_type_check, status=msg_status, content=$"评测原始数据:{path_source}" });
  346. msg_status =Constant._Message_status_info;
  347. try {
  348. //TODO 重整本地文件路径。 文件可能不存在D:\VisualStudioProjects\TEAMModelOS\TEAMModelOS.Extension\IES.Exam\IES.ExamServer\wwwroot\package\exam\6af32bbd-144e-4366-8bc0-61ba4c85677c\evaluation.json
  349. string path_evaluation = Path.Combine(evaluationDataPath, "evaluation.json");
  350. if (!System.IO.File.Exists(path_evaluation))
  351. {
  352. blob=1;
  353. data=1;
  354. msg_status=Constant._Message_status_error;
  355. checkTotal++;
  356. checkError++;
  357. }
  358. else
  359. {
  360. msg_status=Constant._Message_status_success;
  361. checkTotal++;
  362. checkSuccess++;
  363. }
  364. //数据格式: [消息][信息/错误/警告][15:43]=>[开始检查评测信息文件...]
  365. //数据格式: [检查][成功/失败][15:43]=>[评测数据文件:/wwwroot/package/623a9fe6-5445-0938-ff77-aeb80066ef27/evaluation.json]
  366. //数据格式: [下载][成功/失败][15:43]=>[评测数据文件:/wwwroot/package/623a9fe6-5445-0938-ff77-aeb80066ef27/evaluation.json][1024kb][15ms]
  367. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  368. new MessageContent { dataId=evaluationLocal.id, dataName=evaluationLocal.name, messageType= Constant._Message_type_check, status=msg_status, content=$"评测数据文件:{path_evaluation}" });
  369. if (System.IO.File.Exists(path_evaluation))
  370. {
  371. string evaluation_str = await System.IO.File.ReadAllTextAsync(path_evaluation);
  372. JsonNode? evaluation_data = evaluation_str.ToObject<JsonNode>();
  373. if (evaluation_data==null)
  374. {
  375. blob=1;
  376. data=1;
  377. }
  378. else
  379. {
  380. EvaluationClient? evaluationClient = evaluation_data["evaluationClient"]?.ToObject<EvaluationClient>();
  381. if (evaluationClient!=null)
  382. {
  383. if ((!string.IsNullOrWhiteSpace(evaluationLocal.blobHash) && evaluationLocal.blobHash.Equals(evaluationClient.blobHash))
  384. &&(evaluationLocal.blobTime==evaluationClient.blobTime)
  385. &&(evaluationLocal.blobCount== evaluationClient.blobCount)
  386. &&(evaluationLocal.blobSize== evaluationClient.blobSize)&& (evaluationLocal.dataTime==evaluationClient.dataTime)
  387. &&(evaluationLocal.dataSize==evaluationClient.dataSize)&&(evaluationLocal.webviewCount==evaluationClient.webviewCount)
  388. &&(evaluationLocal.webviewSize== evaluationClient.webviewSize)
  389. &&(evaluationLocal.webviewTime== evaluationClient.webviewTime)
  390. &&(!string.IsNullOrWhiteSpace(evaluationLocal.webviewPath)&& evaluationLocal.webviewPath.Equals(evaluationClient.webviewPath)))
  391. {
  392. msg_status=Constant._Message_status_info;
  393. }
  394. else
  395. {
  396. data=1;
  397. msg_status=Constant._Message_status_error;
  398. }
  399. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  400. new MessageContent { dataId=evaluationLocal.id, dataName=evaluationLocal.name, messageType=Constant._Message_type_message, status=msg_status, content="校验本地试卷文件..." });
  401. }
  402. else { data=1; }
  403. List<EvaluationExam>? evaluationExams = evaluation_data["evaluationExams"]?.ToObject<List<EvaluationExam>>();
  404. if (evaluationExams.IsEmpty())
  405. {
  406. blob=1;
  407. data=1;
  408. }
  409. else
  410. {
  411. foreach (var evaluationExam in evaluationExams!)
  412. {
  413. string path_papers = Path.Combine(evaluationPath, "exams");
  414. var papers_files = FileHelper.ListAllFiles(path_papers);
  415. int paperIndex = 0;
  416. foreach (var paper in evaluationExam.papers)
  417. {
  418. paperIndex++;
  419. List<MessageContent> contents = new List<MessageContent>();
  420. int paper_error_count = 0;
  421. foreach (var blobInfo in paper.blobs)
  422. {
  423. msg_status=Constant._Message_status_info;
  424. if (!string.IsNullOrWhiteSpace(blobInfo.path))
  425. {
  426. var file = papers_files.Find(x => x.Contains(blobInfo.path));
  427. if (file!=null)
  428. {
  429. msg_status=1;
  430. msg_status=Constant._Message_status_success;
  431. }
  432. else
  433. {
  434. msg_status=Constant._Message_status_error;
  435. paper_error_count++;
  436. }
  437. }
  438. else
  439. {
  440. msg_status=Constant._Message_status_warning; ;
  441. paper_error_count++;
  442. }
  443. contents.Add(new MessageContent
  444. {
  445. dataId=evaluationLocal.id,
  446. dataName=evaluationLocal.name,
  447. messageType=Constant._Message_type_check,
  448. status=msg_status,
  449. content=$"试卷文件信息:{paper.paperName}"
  450. });
  451. }
  452. int paper_msg_status = Constant._Message_status_info;
  453. if (paper_error_count>0)
  454. {
  455. blob=1;
  456. paper_msg_status=Constant._Message_status_error;
  457. }
  458. else
  459. {
  460. paper_msg_status=Constant._Message_status_success;
  461. }
  462. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  463. new MessageContent
  464. {
  465. dataId=evaluationLocal.id,
  466. dataName=evaluationLocal.name,
  467. messageType=Constant._Message_type_message,
  468. status=paper_msg_status,
  469. 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)}",
  470. contents=contents
  471. });
  472. }
  473. }
  474. }
  475. }
  476. }
  477. }
  478. catch (Exception e) {
  479. _logger.LogData<object>(new {code=500,msg=e.Message,data = new { content= e.StackTrace } }, evaluationLocal.id!);
  480. }
  481. //检查需要更新的项目:
  482. if (data==1)
  483. {
  484. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  485. new MessageContent
  486. {
  487. dataId=evaluationLocal.id,
  488. dataName=evaluationLocal.name,
  489. messageType=Constant._Message_type_message,
  490. status=Constant._Message_status_warning,
  491. content=$"检查到评测数据需要更新。[{dataSize}]"
  492. });
  493. }
  494. if (blob==1)
  495. {
  496. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  497. new MessageContent
  498. {
  499. dataId=evaluationLocal.id,
  500. dataName=evaluationLocal.name,
  501. messageType=Constant._Message_type_message,
  502. status=Constant._Message_status_warning,
  503. content=$"检查到评测试卷需要更新。[{blobSize}]"
  504. });
  505. }
  506. if (webview==1)
  507. {
  508. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  509. new MessageContent
  510. {
  511. dataId=evaluationLocal.id,
  512. dataName=evaluationLocal.name,
  513. messageType=Constant._Message_type_message,
  514. status=Constant._Message_status_warning,
  515. content=$"检查到评测作答页面需要更新。[{webviewSize}]"
  516. });
  517. }
  518. if (groupList==1)
  519. {
  520. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  521. new MessageContent
  522. {
  523. dataId=evaluationLocal.id,
  524. dataName=evaluationLocal.name,
  525. messageType=Constant._Message_type_message,
  526. status=Constant._Message_status_warning,
  527. content=$"检查到评测名单需要更新。[{studentCount}]"
  528. });
  529. }
  530. }
  531. int finalStatus = Constant._Message_status_success;
  532. if (checkWarning>0)
  533. {
  534. finalStatus = Constant._Message_status_warning;
  535. }
  536. if (checkError>0)
  537. {
  538. finalStatus = Constant._Message_status_error;
  539. }
  540. await _signalRExamServerHub.SendMessage(_memoryCache, _logger, deviceId, Constant._Message_grant_type_check_file,
  541. new MessageContent {
  542. dataId=evaluationLocal?.id,
  543. dataName=evaluationLocal?.name,
  544. messageType=Constant._Message_type_message,
  545. status=Constant._Message_status_warning,
  546. content=$"最终检测结果:总数({checkTotal}),成功({checkSuccess}),警告({checkWarning}),异常({checkError})。"
  547. });
  548. return Ok(new {
  549. code = 200,
  550. evaluation = evaluationLocal,
  551. data,
  552. blob,
  553. webview,
  554. dataSize,
  555. blobSize,
  556. webviewSize,
  557. status,
  558. groupList,
  559. studentCount,
  560. checkTotal,
  561. checkSuccess,
  562. checkError,
  563. checkWarning,
  564. });
  565. }
  566. /// <summary>
  567. /// 激活或者取消激活考试
  568. /// </summary>
  569. /// <param name="json"></param>
  570. /// <returns></returns>
  571. [HttpPost("activate-evaluation")]
  572. [AuthToken("admin", "teacher", "visitor")]
  573. public IActionResult ActivateEvaluation(JsonNode json)
  574. {
  575. string id = $"{json["id"]}";
  576. string shortCode = $"{json["shortCode"]}";
  577. string activateStr = $"{json["activate"]}";
  578. if (!string.IsNullOrWhiteSpace(id) && !string.IsNullOrWhiteSpace(shortCode))
  579. {
  580. EvaluationClient? evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindOne(x => x.id!.Equals(id) && !string.IsNullOrWhiteSpace(x.shortCode) && x.shortCode.Equals(shortCode));
  581. if (evaluationClient != null)
  582. {
  583. IEnumerable<EvaluationClient> evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Find(x=>x.activate==1);
  584. if (evaluationClients != null && evaluationClients.Count() > 0)
  585. {
  586. foreach(EvaluationClient item in evaluationClients)
  587. {
  588. item.activate = 0;
  589. _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Upsert(item);
  590. }
  591. }
  592. int activate = 0;
  593. if (int.TryParse(activateStr, out int _activate)) {
  594. activate = _activate;
  595. }
  596. evaluationClient.activate = activate;
  597. _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Upsert(evaluationClient);
  598. }
  599. }
  600. return Ok();
  601. }
  602. /// <summary>
  603. /// 加载本地的活动列表
  604. /// </summary>
  605. /// <param name="json"></param>
  606. /// <returns></returns>
  607. [HttpPost("list-local-evaluation")]
  608. [AuthToken("admin", "teacher", "visitor")]
  609. public IActionResult ListLocalEvaluation(JsonNode json)
  610. {
  611. IEnumerable<EvaluationClient>? evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindAll().OrderByDescending(x=>x.activate).ThenByDescending(x=>x.stime);
  612. if (evaluationClients != null)
  613. {
  614. var result = evaluationClients.Select(client =>
  615. {
  616. var properties = client.GetType().GetProperties();
  617. var anonymousObject = new Dictionary<string, object?>();
  618. foreach (var property in properties)
  619. {
  620. if (!property.Name.Equals("password") && !property.Name.Equals("shortCode"))
  621. {
  622. anonymousObject[property.Name] = property.GetValue(client);
  623. }
  624. }
  625. return anonymousObject;
  626. });
  627. return Ok(new { code = 200, evaluation = result });
  628. }
  629. else {
  630. return Ok(new { code = 200, evaluation = new Dictionary<string, object?>() });
  631. }
  632. }
  633. }
  634. }