TriggerExam.cs 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. using Azure.Cosmos;
  2. using Azure.Messaging.ServiceBus;
  3. using Microsoft.Azure.Documents;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Text.Json;
  9. using System.Threading.Tasks;
  10. using TEAMModelOS.SDK.DI;
  11. using TEAMModelOS.SDK.Extension;
  12. using TEAMModelOS.SDK;
  13. using TEAMModelOS.SDK.Models;
  14. using TEAMModelOS.SDK.Models.Cosmos;
  15. using TEAMModelOS.SDK.Models.Cosmos.Common;
  16. using TEAMModelOS.SDK.Models.Service;
  17. using HTEXLib.COMM.Helpers;
  18. namespace TEAMModelFunction
  19. {
  20. public class TriggerExam
  21. {
  22. public static async void Trigger(AzureCosmosFactory _azureCosmos, AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
  23. CosmosClient client, Document input, string code, long stime, long etime, string school)
  24. {
  25. ExamInfo info = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
  26. List<ExamClassResult> examClassResults = new List<ExamClassResult>();
  27. List<ExamSubject> examSubjects = new List<ExamSubject>();
  28. try
  29. {
  30. if (info.scope.Equals("teacher", StringComparison.OrdinalIgnoreCase) || info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
  31. {
  32. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{info.creatorId}") }))
  33. {
  34. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  35. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  36. {
  37. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  38. {
  39. examClassResults.Add(obj.ToObject<ExamClassResult>());
  40. }
  41. }
  42. }
  43. }
  44. else
  45. {
  46. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{school}") }))
  47. {
  48. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  49. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  50. {
  51. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  52. {
  53. examClassResults.Add(obj.ToObject<ExamClassResult>());
  54. }
  55. }
  56. }
  57. }
  58. List<ChangeRecord> records = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", info.progress } });
  59. //处理科目信息
  60. List<string> sub = new List<string>();
  61. foreach (ExamSubject subject in info.subjects)
  62. {
  63. sub.Add(subject.id);
  64. }
  65. //ChangeRecord record = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ChangeRecord>(input.Id, new Azure.Cosmos.PartitionKey($"{info.progress}"));
  66. switch (info.progress)
  67. {
  68. case "pending":
  69. var message = new ServiceBusMessage(new { id = input.Id, progress = "going", code = code }.ToJsonString());
  70. message.ApplicationProperties.Add("name", "Exam");
  71. if (records.Count > 0)
  72. {
  73. await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
  74. long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
  75. records[0].sequenceNumber = start;
  76. await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
  77. //await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
  78. }
  79. else
  80. {
  81. long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
  82. ChangeRecord changeRecord = new ChangeRecord
  83. {
  84. RowKey = input.Id,
  85. PartitionKey = "pending",
  86. sequenceNumber = start,
  87. msgId = message.MessageId
  88. };
  89. await _azureStorage.Save<ChangeRecord>(changeRecord);
  90. //await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
  91. }
  92. break;
  93. case "going":
  94. List<string> classes = ExamService.getClasses(info.classes,info.stuLists);
  95. (List<TmdInfo> tmdids, List<StuInfo> studentss,List<ClassListInfo> classLists) = await TriggerStuActivity.GetStuList(client, _dingDing, classes, info.school);
  96. List<StuActivity> stuActivities = new List<StuActivity>();
  97. List<StuActivity> tmdActivities = new List<StuActivity>();
  98. try
  99. {
  100. if (tmdids.IsNotEmpty())
  101. {
  102. tmdids.ForEach(x =>
  103. {
  104. tmdActivities.Add(new StuActivity
  105. {
  106. pk = "Activity",
  107. id = info.id,
  108. code = $"Activity-{x.id}",
  109. type = "Exam",
  110. name = info.name,
  111. startTime = info.startTime,
  112. endTime = info.endTime,
  113. scode = info.code,
  114. scope = info.scope,
  115. school = info.school,
  116. creatorId = info.creatorId,
  117. subjects = sub,
  118. blob = null,
  119. owner = info.owner,
  120. createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
  121. taskStatus = -1,
  122. classIds = classes
  123. });;
  124. });
  125. }
  126. if (studentss.IsNotEmpty())
  127. {
  128. studentss.ForEach(x =>
  129. {
  130. stuActivities.Add(new StuActivity
  131. {
  132. pk = "Activity",
  133. id = info.id,
  134. code = $"Activity-{x.code.Replace("Base-", "")}-{x.id}",
  135. type = "Exam",
  136. name = info.name,
  137. startTime = info.startTime,
  138. endTime = info.endTime,
  139. scode = info.code,
  140. scope = info.scope,
  141. school = info.school,
  142. creatorId = info.creatorId,
  143. subjects = sub,
  144. blob = null,
  145. owner = info.owner,
  146. classIds = classes,
  147. createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
  148. taskStatus = -1
  149. });
  150. });
  151. }
  152. await TriggerStuActivity.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities,null);
  153. //向学生或醍摩豆账号发起通知
  154. #region
  155. //Notice notice = new Notice()
  156. //{
  157. // msgId = info.id,
  158. // creation = info.startTime,
  159. // expire = info.endTime,
  160. // creatorId = info.creatorId,
  161. // stuids = studentss,
  162. // tmdids = tmdids,
  163. // type = "notice",//评测参加通知
  164. // priority = "normal",
  165. // school = info.school,
  166. // scope = info.scope,
  167. // //data = new { }.ToJsonString()
  168. // body = new Body { sid = info.id, scode = info.code, spk = info.pk, biztype = "exam-join" }
  169. //};
  170. //var messageBlob = new ServiceBusMessage(notice.ToJsonString());
  171. //messageBlob.ApplicationProperties.Add("name", "Notice");
  172. //await _serviceBus.GetServiceBusClient().SendMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageBlob);
  173. #endregion
  174. if (examClassResults.Count == 0)
  175. {
  176. try
  177. {
  178. foreach (string cla in classes)
  179. {
  180. int m = 0;
  181. foreach (ExamSubject subject in info.subjects)
  182. {
  183. string classCode = "";
  184. if (string.IsNullOrEmpty(info.school) || !info.scope.Equals("school", StringComparison.OrdinalIgnoreCase))
  185. {
  186. classCode = "ExamClassResult-" + info.creatorId;
  187. }
  188. else
  189. {
  190. classCode = "ExamClassResult-" + info.school;
  191. }
  192. ExamClassResult result = new ExamClassResult
  193. {
  194. code = classCode,
  195. examId = info.id,
  196. id = Guid.NewGuid().ToString(),
  197. subjectId = subject.id,
  198. year = info.year,
  199. scope = info.scope
  200. };
  201. result.info.id = cla;
  202. List<string> ans = new List<string>();
  203. List<List<string>> anses = new List<List<string>>();
  204. List<List<Details>> marks = new List<List<Details>>();
  205. List<double> ansPoint = new List<double>();
  206. List<string> ids = new List<string>();
  207. foreach (double p in info.papers[m].point)
  208. {
  209. //Details details = new Details();
  210. //ans.Add(new List<string>());
  211. anses.Add(new List<string>());
  212. marks.Add(new List<Details>());
  213. ansPoint.Add(-1);
  214. }
  215. var sresponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"Class-{info.school}"));
  216. if (sresponse.Status == 200)
  217. {
  218. using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
  219. Class classroom = json.ToObject<Class>();
  220. School sc = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(info.school, new Azure.Cosmos.PartitionKey("Base"));
  221. foreach (Period period in sc.period)
  222. {
  223. if (period.id.Equals(classroom.periodId))
  224. {
  225. foreach (Semester semester in period.semesters)
  226. {
  227. if (semester.start == 1)
  228. {
  229. int year = DateTimeOffset.UtcNow.Year;
  230. int month = DateTimeOffset.UtcNow.Month;
  231. int day = DateTimeOffset.UtcNow.Day;
  232. int time = 0;
  233. if (month == semester.month)
  234. {
  235. time = day >= semester.day ? 0 : 1;
  236. }
  237. else
  238. {
  239. time = month > semester.month ? 0 : 1;
  240. }
  241. int eyear = year - time;
  242. result.gradeId = (eyear - classroom.year).ToString();
  243. }
  244. }
  245. }
  246. }
  247. //result.info.id = classroom.id;
  248. result.info.name = classroom.name;
  249. //result.gradeId = classroom.year.ToString();
  250. //处理班级人数
  251. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: $"select c.id from c where c.classId = '{classroom.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Base-{info.school}") }))
  252. {
  253. using var json_stu = await JsonDocument.ParseAsync(item.ContentStream);
  254. if (json_stu.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  255. {
  256. var accounts = json_stu.RootElement.GetProperty("Documents").EnumerateArray();
  257. while (accounts.MoveNext())
  258. {
  259. JsonElement account = accounts.Current;
  260. ids.Add(account.GetProperty("id").GetString());
  261. }
  262. }
  263. }
  264. }
  265. if (info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
  266. {
  267. var stuResponse = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"StuList"));
  268. if (stuResponse.Status == 200)
  269. {
  270. using var json = await JsonDocument.ParseAsync(stuResponse.ContentStream);
  271. StuList stuList = json.ToObject<StuList>();
  272. //result.info.id = stuList.id;
  273. result.info.name = stuList.name;
  274. //处理发布对象为自选名单(个人)
  275. foreach (Students stus in stuList.students)
  276. {
  277. if (!ids.Contains(stus.id))
  278. {
  279. ids.Add(stus.id);
  280. }
  281. }
  282. if (stuList.tmids.Count > 0)
  283. {
  284. foreach (string tid in stuList.tmids)
  285. {
  286. ids.Add(tid);
  287. }
  288. }
  289. }
  290. }
  291. else
  292. {
  293. var stuResponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"StuList-{info.school}"));
  294. if (stuResponse.Status == 200)
  295. {
  296. using var json = await JsonDocument.ParseAsync(stuResponse.ContentStream);
  297. StuList stuList = json.ToObject<StuList>();
  298. //result.info.id = stuList.id;
  299. result.info.name = stuList.name;
  300. //处理发布对象为自选名单(校本)
  301. foreach (Students stus in stuList.students)
  302. {
  303. if (!ids.Contains(stus.id))
  304. {
  305. ids.Add(stus.id);
  306. }
  307. }
  308. }
  309. }
  310. foreach (string stu in ids)
  311. {
  312. result.mark.Add(marks);
  313. result.studentIds.Add(stu);
  314. result.studentAnswers.Add(ans);
  315. result.studentScores.Add(ansPoint);
  316. result.ans.Add(anses);
  317. result.sum.Add(0);
  318. }
  319. //result.progress = info.progress;
  320. result.school = info.school;
  321. m++;
  322. await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(result, new Azure.Cosmos.PartitionKey($"{result.code}"));
  323. }
  324. }
  325. }
  326. catch (Exception ex)
  327. {
  328. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测going初始化异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  329. }
  330. finally {
  331. // 发送信息通知
  332. var messageEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
  333. messageEnd.ApplicationProperties.Add("name", "Exam");
  334. if (records.Count > 0)
  335. {
  336. long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
  337. await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
  338. records[0].sequenceNumber = end;
  339. await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
  340. //await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
  341. }
  342. else
  343. {
  344. long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
  345. ChangeRecord changeRecord = new ChangeRecord
  346. {
  347. RowKey = input.Id,
  348. PartitionKey = "going",
  349. sequenceNumber = end,
  350. msgId = messageEnd.MessageId
  351. };
  352. await _azureStorage.Save<ChangeRecord>(changeRecord);
  353. //await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
  354. }
  355. }
  356. }
  357. else
  358. {
  359. //处理单科结算时科目与试卷信息匹配的问题
  360. int gno = 0;
  361. foreach (ExamSubject subject in info.subjects)
  362. {
  363. if (subject.classCount == classes.Count)
  364. {
  365. await createClassResultAsync(info, examClassResults, subject, gno, _azureCosmos, _dingDing, _azureStorage);
  366. }
  367. gno++;
  368. }
  369. }
  370. }
  371. catch (Exception e)
  372. {
  373. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测going状态异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
  374. }
  375. break;
  376. case "finish":
  377. int fno = 0;
  378. try
  379. {
  380. foreach (ExamSubject subject in info.subjects)
  381. {
  382. await createClassResultAsync(info, examClassResults, subject, fno, _azureCosmos, _dingDing, _azureStorage);
  383. fno++;
  384. }
  385. //计算单次考试简易统计信息
  386. List<ExamResult> examResults = new List<ExamResult>();
  387. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamResult>(
  388. queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamResult-{info.id}") }))
  389. {
  390. examResults.Add(item);
  391. }
  392. List<Task<ItemResponse<ExamClassResult>>> tasks = new List<Task<ItemResponse<ExamClassResult>>>();
  393. //结算单科单班的标准差和平均分
  394. foreach (ExamClassResult classResult in examClassResults)
  395. {
  396. //标记单科单班总得分
  397. double subScore = 0;
  398. //标准差
  399. double sPowSum = 0;
  400. var scount = classResult.studentIds.Count;
  401. foreach (List<double> sc in classResult.studentScores)
  402. {
  403. List<double> newSc = new List<double>();
  404. foreach (double ssc in sc)
  405. {
  406. if (ssc == -1)
  407. {
  408. newSc.Add(0);
  409. }
  410. else
  411. {
  412. newSc.Add(ssc);
  413. }
  414. }
  415. subScore += newSc.Sum();
  416. }
  417. foreach (string sid in classResult.studentIds)
  418. {
  419. double ssc = classResult.studentScores[classResult.studentIds.IndexOf(sid)].Sum();
  420. sPowSum += Math.Pow(ssc - scount > 0 ? Math.Round(subScore * 1.0 / scount, 2) : 0, 2);
  421. }
  422. classResult.standard = Math.Round(scount > 0 ? Math.Pow(sPowSum / scount, 0.5) : 0, 2);
  423. classResult.average = scount > 0 ? Math.Round(subScore / scount, 2) : 0;
  424. classResult.progress = true;
  425. tasks.Add(client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(classResult, classResult.id, new Azure.Cosmos.PartitionKey($"{classResult.code}")));
  426. }
  427. await Task.WhenAll(tasks);
  428. //记录某次考试所有学生得分总分
  429. double score = 0;
  430. double allScore = 0;
  431. int stuCount = 0;
  432. //标准差
  433. double powSum = 0;
  434. List<string> losStu = new List<string>();
  435. //先与第一个值取并集
  436. if (examResults.Count > 0)
  437. {
  438. losStu = losStu.Union(examResults[0].lostStus).ToList();
  439. foreach (ExamResult examResult in examResults)
  440. {
  441. if (info.id == examResult.examId)
  442. {
  443. foreach (List<double> sc in examResult.studentScores)
  444. {
  445. score += sc.Sum();
  446. }
  447. stuCount = examResult.studentIds.Count;
  448. }
  449. //powSum += Math.Pow(score - examResult.studentIds.Count > 0 ? Math.Round(score * 1.0 / examResult.studentIds.Count, 2) : 0, 2);
  450. //取交集
  451. losStu = losStu.Intersect(examResult.lostStus).ToList();
  452. }
  453. }
  454. double NewsRateScore = stuCount > 0 ? Math.Round(score * 1.0 / stuCount, 2) : 0;
  455. foreach (PaperSimple simple in info.papers)
  456. {
  457. allScore += simple.point.Sum();
  458. }
  459. //计算全科标准差
  460. foreach (string id in examResults[0].studentIds)
  461. {
  462. double sc = 0;
  463. foreach (ExamResult result in examResults)
  464. {
  465. sc += result.studentScores[result.studentIds.IndexOf(id)].Sum();
  466. }
  467. powSum += Math.Pow(sc - NewsRateScore, 2);
  468. }
  469. info.standard = Math.Round(examResults[0].studentIds.Count > 0 ? Math.Pow(powSum / examResults[0].studentIds.Count, 0.5) : 0, 2);
  470. double NewsRate = allScore > 0 ? Math.Round(NewsRateScore / allScore * 100, 2) : 0;
  471. info.lostStu = losStu;
  472. /*//补充历史数据的容器名称
  473. if (string.IsNullOrEmpty(info.cn)) {
  474. if (info.scope.Equals("school"))
  475. {
  476. info.cn = info.school;
  477. }
  478. else {
  479. info.cn = info.creatorId;
  480. }
  481. }*/
  482. //判断均分是否发生变化,便于实时的更新评测基本信息
  483. if (info.sRate != NewsRate || info.average != NewsRateScore)
  484. {
  485. info.sRate = NewsRate;
  486. info.average = NewsRateScore;
  487. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync<ExamInfo>(info, info.id, new Azure.Cosmos.PartitionKey(info.code));
  488. }
  489. }
  490. catch (Exception e)
  491. {
  492. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测finish状态异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
  493. }
  494. break;
  495. }
  496. }
  497. catch (Exception e)
  498. {
  499. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测结算异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
  500. }
  501. }
  502. //处理全部学生选题计数
  503. public static async Task examRecordCount(ExamInfo info, ExamSubject subject, DingDing _dingDing, int no, ExamResult result, List<ExamClassResult> classResults, AzureCosmosFactory _azureCosmos)
  504. {
  505. try
  506. {
  507. List<double> scores = new List<double>();
  508. foreach (List<double> sc in result.studentScores)
  509. {
  510. scores.Add(sc.Sum());
  511. }
  512. //确定高分组 最低分数
  513. scores.Sort((s1, s2) => { return s2.CompareTo(s1); });
  514. double rhwCount = Math.Floor(scores.Count * 0.27);
  515. double rhw = rhwCount > 0 ? scores[int.Parse(rhwCount.ToString("0"))] : 0;
  516. //确定低分组 最高分数
  517. //scores.Sort((s1, s2) => { return s1.CompareTo(s2); });
  518. double rhlCount = Math.Ceiling(scores.Count * 0.73);
  519. double rhl = rhlCount > 0 ? scores[int.Parse(rhlCount.ToString("0"))-1] : 0;
  520. //存放高分组学生ID
  521. List<string> phId = new List<string>();
  522. List<string> plId = new List<string>();
  523. List<List<List<string>>> opth = new List<List<List<string>>>();
  524. List<List<List<string>>> optl = new List<List<List<string>>>();
  525. await knowledgeCount(info, subject, _dingDing, no, classResults, rhwCount, rhw, rhlCount, rhl, _azureCosmos);
  526. await fieldCount(info, subject, _dingDing, no, classResults, rhwCount, rhw, rhlCount, rhl, _azureCosmos);
  527. int PHCount = 0;
  528. int PLCount = 0;
  529. foreach (ExamClassResult classResult in classResults)
  530. {
  531. if (classResult.subjectId.Equals(subject.id))
  532. {
  533. foreach (string id in classResult.studentIds)
  534. {
  535. int index = classResult.studentIds.IndexOf(id);
  536. if (classResult.studentScores.Count > 0)
  537. {
  538. if (classResult.studentScores[index].Sum() >= rhw && PHCount < rhwCount)
  539. {
  540. if (classResult.ans.Count > 0)
  541. {
  542. opth.Add(classResult.ans[index]);
  543. PHCount++;
  544. continue;
  545. }
  546. }
  547. if (classResult.studentScores[index].Sum() <= rhl && PLCount < (scores.Count - rhlCount))
  548. {
  549. if (classResult.ans.Count > 0)
  550. {
  551. optl.Add(classResult.ans[index]);
  552. PLCount++;
  553. continue;
  554. }
  555. }
  556. }
  557. }
  558. }
  559. }
  560. result.phc = getMore(info, no, opth);
  561. result.plc = getMore(info, no, optl);
  562. }
  563. catch (Exception ex)
  564. {
  565. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测作答记录结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  566. }
  567. }
  568. public static async Task knowledgeCount(ExamInfo info, ExamSubject subject, DingDing _dingDing, int no, List<ExamClassResult> classResults,
  569. double rhwCount, double rhw, double rhlCount, double rhl, AzureCosmosFactory _azureCosmos)
  570. {
  571. try
  572. {
  573. int phcount = 0;
  574. int plcount = 0;
  575. //存放并去重知识点
  576. HashSet<string> kname = new HashSet<string>();
  577. if (info.papers[no].knowledge.Count > 0)
  578. {
  579. info.papers[no].knowledge.ForEach(kno =>
  580. {
  581. kno.ForEach(k =>
  582. {
  583. kname.Add(k);
  584. });
  585. });
  586. List<string> knowledgeName = new List<string>();
  587. foreach (string cla in kname)
  588. {
  589. knowledgeName.Add(cla);
  590. }
  591. for (int k = 0; k < knowledgeName.Count; k++)
  592. {
  593. if (null == knowledgeName[k])
  594. {
  595. knowledgeName.Remove(knowledgeName[k]);
  596. }
  597. }
  598. foreach (ExamClassResult classResult in classResults)
  599. {
  600. if (classResult.subjectId.Equals(subject.id))
  601. {
  602. //List<int> phc = new List<int>();
  603. List<int> ph = new List<int>();
  604. List<int> pl = new List<int>();
  605. List<int> pc = new List<int>();
  606. List<double> persent = new List<double>();
  607. for (int i = 0; i < knowledgeName.Count; i++)
  608. {
  609. //初始化单个知识点得分
  610. double score = 0;
  611. double allScore = 0;
  612. int n = 0;
  613. int phCount = 0;
  614. int plCount = 0;
  615. int pCount = 0;
  616. foreach (List<string> str in info.papers[no].knowledge)
  617. {
  618. if (str.Contains(knowledgeName[i]))
  619. {
  620. var itemPersent = str.Count > 0 ? 1 / Convert.ToDouble(str.Count) : 0;
  621. allScore += info.papers[no].point.Count > 0 ? info.papers[no].point[n] * itemPersent : 0;
  622. foreach (string id in classResult.studentIds)
  623. {
  624. int index = classResult.studentIds.IndexOf(id);
  625. if (classResult.studentScores.Count > 0)
  626. {
  627. if (classResult.studentScores[index].Count > 0)
  628. {
  629. score += classResult.studentScores[index][n] == -1 ? 0 : classResult.studentScores[index][n];
  630. if (classResult.studentScores[index].Sum() >= rhw && phcount < rhwCount)
  631. {
  632. if (classResult.studentScores[index][n] <= 0)
  633. {
  634. phCount++;
  635. }
  636. phcount++;
  637. continue;
  638. }
  639. if (classResult.studentScores[index].Sum() <= rhl && plcount < (info.stuCount - rhlCount))
  640. {
  641. if (classResult.studentScores[index][n] <= 0)
  642. {
  643. plCount++;
  644. }
  645. plcount++;
  646. continue;
  647. }
  648. if (classResult.studentScores[index][n] <= 0)
  649. {
  650. pCount++;
  651. }
  652. }
  653. }
  654. }
  655. }
  656. n++;
  657. }
  658. pc.Add(pCount);
  659. ph.Add(phCount);
  660. pl.Add(plCount);
  661. double per = classResult.studentIds.Count > 0 ? Math.Round(score / classResult.studentIds.Count, 2) : 0;
  662. persent.Add(allScore > 0 ? per / allScore : 0);
  663. }
  664. classResult.phc = ph;
  665. classResult.plc = pl;
  666. classResult.pc = pc;
  667. classResult.krate = persent;
  668. }
  669. //await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(classResult, classResult.id, new Azure.Cosmos.PartitionKey($"{classResult.code}"));
  670. }
  671. }
  672. }
  673. catch (Exception ex)
  674. {
  675. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测知识点结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  676. }
  677. }
  678. public static async Task fieldCount(ExamInfo info, ExamSubject subject, DingDing _dingDing, int no, List<ExamClassResult> classResults,
  679. double rhwCount, double rhw, double rhlCount, double rhl, AzureCosmosFactory _azureCosmos)
  680. {
  681. try
  682. {
  683. int phcount = 0;
  684. int plcount = 0;
  685. //存放并去重知识点
  686. List<int> knowledgeName = new List<int>();
  687. knowledgeName.Add(1);
  688. knowledgeName.Add(2);
  689. knowledgeName.Add(3);
  690. knowledgeName.Add(4);
  691. knowledgeName.Add(5);
  692. knowledgeName.Add(6);
  693. foreach (ExamClassResult classResult in classResults)
  694. {
  695. if (classResult.subjectId.Equals(subject.id))
  696. {
  697. //List<int> phc = new List<int>();
  698. List<int> ph = new List<int>();
  699. List<int> pl = new List<int>();
  700. List<int> pc = new List<int>();
  701. List<double> persent = new List<double>();
  702. for (int i = 0; i < knowledgeName.Count; i++)
  703. {
  704. //初始化单个知识点得分
  705. double score = 0;
  706. double allScore = 0;
  707. int n = 0;
  708. int phCount = 0;
  709. int plCount = 0;
  710. int pCount = 0;
  711. if (info.papers[no].field.Count > 0)
  712. {
  713. foreach (int str in info.papers[no].field)
  714. {
  715. if (str == knowledgeName[i])
  716. {
  717. var itemPersent = 1;
  718. allScore += info.papers[no].point.Count > 0 ? info.papers[no].point[n] * itemPersent : 0;
  719. foreach (string id in classResult.studentIds)
  720. {
  721. int index = classResult.studentIds.IndexOf(id);
  722. if (classResult.studentScores.Count > 0)
  723. {
  724. if (classResult.studentScores[index].Count > 0)
  725. {
  726. score += classResult.studentScores[index][n] == -1 ? 0 : classResult.studentScores[index][n];
  727. if (classResult.studentScores[index].Sum() >= rhw && phcount < rhwCount)
  728. {
  729. if (classResult.studentScores[index][n] <= 0)
  730. {
  731. phCount++;
  732. }
  733. phcount++;
  734. continue;
  735. }
  736. if (classResult.studentScores[index].Sum() <= rhl && plcount < (info.stuCount - rhlCount))
  737. {
  738. if (classResult.studentScores[index][n] <= 0)
  739. {
  740. plCount++;
  741. }
  742. plcount++;
  743. continue;
  744. }
  745. if (classResult.studentScores[index][n] <= 0)
  746. {
  747. pCount++;
  748. }
  749. }
  750. }
  751. }
  752. }
  753. n++;
  754. }
  755. pc.Add(pCount);
  756. ph.Add(phCount);
  757. pl.Add(plCount);
  758. double per = classResult.studentIds.Count > 0 ? Math.Round(score / classResult.studentIds.Count, 2) : 0;
  759. persent.Add(allScore > 0 ? per / allScore : 0);
  760. }
  761. }
  762. classResult.fphc = ph;
  763. classResult.fplc = pl;
  764. classResult.fpc = pc;
  765. classResult.frate = persent;
  766. }
  767. //await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(classResult, classResult.id, new Azure.Cosmos.PartitionKey($"{classResult.code}"));
  768. }
  769. }
  770. catch (Exception ex)
  771. {
  772. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测认知层次结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  773. }
  774. }
  775. //处理选题计数
  776. public static List<Dictionary<string, int>> getMore(ExamInfo info, int no, List<List<List<string>>> list)
  777. {
  778. List<Dictionary<string, int>> recorde = new List<Dictionary<string, int>>();
  779. try
  780. {
  781. for (int i = 0; i < info.papers[no].answers.Count; i++)
  782. {
  783. if (info.papers[no].answers[i].Count <= 0)
  784. {
  785. recorde.Add(new Dictionary<string, int>());
  786. continue;
  787. }
  788. Dictionary<string, int> optCount = new Dictionary<string, int>();
  789. foreach (List<List<string>> stu in list)
  790. {
  791. if (stu.Count == info.papers[no].answers.Count)
  792. {
  793. var item = stu[i];
  794. foreach (string opt in item)
  795. {
  796. if (optCount.ContainsKey(opt))
  797. {
  798. optCount[opt] = optCount[opt] + 1;
  799. }
  800. else
  801. {
  802. optCount[opt] = 1;
  803. }
  804. }
  805. }
  806. }
  807. recorde.Add(optCount);
  808. }
  809. return recorde;
  810. }
  811. catch (Exception)
  812. {
  813. return recorde;
  814. }
  815. }
  816. public static async Task createClassResultAsync(ExamInfo info, List<ExamClassResult> examClassResults, ExamSubject subject, int no, AzureCosmosFactory _azureCosmos, DingDing _dingDing, AzureStorageFactory _azureStorage)
  817. {
  818. //保证试卷信息与科目信息同步
  819. ExamResult result = new ExamResult();
  820. //人数总和
  821. int Count = 0;
  822. int m = 0;
  823. double score = 0;
  824. //标准差
  825. double powSum = 0;
  826. double allScore = info.papers[no].point.Sum();
  827. List<ClassRange> classRanges = new List<ClassRange>();
  828. List<string> lostStu = new List<string>();
  829. List<double> csRate = new List<double>();
  830. List<List<List<string>>> opt = new List<List<List<string>>>();
  831. foreach (ExamClassResult classResult in examClassResults)
  832. {
  833. double classSrate = 0;
  834. if (classResult.subjectId.Equals(subject.id))
  835. {
  836. foreach (List<List<string>> op in classResult.ans)
  837. {
  838. opt.Add(op);
  839. }
  840. //记录缺考学生索引位置
  841. int index = 0;
  842. foreach (List<double> scores in classResult.studentScores)
  843. {
  844. List<double> newScores = new List<double>();
  845. int count = 0;
  846. foreach (double sc in scores)
  847. {
  848. newScores.Add(sc > -1 ? sc : 0);
  849. if (sc == -1)
  850. {
  851. count++;
  852. }
  853. }
  854. if (count == scores.Count)
  855. {
  856. lostStu.Add(classResult.studentIds[index]);
  857. //mcount++;
  858. }
  859. classSrate += newScores.Sum();
  860. score += newScores.Sum();
  861. result.studentScores.Add(newScores);
  862. index++;
  863. }
  864. //处理班级信息
  865. ClassRange range = new ClassRange();
  866. range.id = classResult.info.id;
  867. range.name = classResult.info.name;
  868. range.gradeId = classResult.gradeId;
  869. List<int> ran = new List<int>();
  870. int stuCount = classResult.studentIds.Count;
  871. Count += stuCount;
  872. if (m == 0)
  873. {
  874. ran.Add(0);
  875. ran.Add(stuCount - 1);
  876. }
  877. else
  878. {
  879. ran.Add(Count - stuCount);
  880. ran.Add(Count - 1);
  881. }
  882. m++;
  883. range.range = ran;
  884. classRanges.Add(range);
  885. //处理学生ID
  886. foreach (string id in classResult.studentIds)
  887. {
  888. result.studentIds.Add(id);
  889. }
  890. if (allScore > 0)
  891. {
  892. csRate.Add(classResult.studentIds.Count > 0 ? Math.Round(classSrate * 1.0 / classResult.studentIds.Count, 2) : 0 / allScore);
  893. }
  894. else
  895. {
  896. csRate.Add(0);
  897. }
  898. //powSum += Math.Pow(classSrate - result.average, 2);
  899. //处理选项计数内容
  900. }
  901. }
  902. await examRecordCount(info, subject, _dingDing, no, result, examClassResults, _azureCosmos);
  903. result.record = getMore(info, no, opt);
  904. result.average = result.studentIds.Count > 0 ? Math.Round(score * 1.0 / result.studentIds.Count, 2) : 0;
  905. foreach (ExamClassResult classResult in examClassResults)
  906. {
  907. //double classSrate = 0;
  908. if (classResult.subjectId.Equals(subject.id))
  909. {
  910. foreach (string id in classResult.studentIds)
  911. {
  912. double sc = classResult.studentScores[classResult.studentIds.IndexOf(id)].Sum();
  913. powSum += Math.Pow(sc - result.average, 2);
  914. }
  915. }
  916. }
  917. result.standard = Math.Round(result.studentIds.Count > 0 ? Math.Pow(powSum / result.studentIds.Count, 0.5) : 0, 2);
  918. result.csRate = csRate;
  919. result.lostStus = lostStu;
  920. result.sRate = allScore > 0 ? Math.Round(result.average / allScore * 100, 2) : 0;
  921. result.classes = classRanges;
  922. result.code = "ExamResult-" + info.id;
  923. result.school = info.school;
  924. result.id = subject.id;
  925. result.examId = info.id;
  926. result.subjectId = subject.id;
  927. result.year = info.year;
  928. result.paper = info.papers[no];
  929. //result.point = info.papers[j].point;
  930. result.scope = info.scope;
  931. result.name = info.name;
  932. result.time = info.startTime;
  933. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").UpsertItemAsync(result, new Azure.Cosmos.PartitionKey($"ExamResult-{info.id}"));
  934. }
  935. }
  936. }