TriggerExam.cs 55 KB

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