ActivityService.cs 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  1. using Azure.Cosmos;
  2. using Azure.Storage.Blobs.Models;
  3. using Azure.Storage.Sas;
  4. using DocumentFormat.OpenXml.Bibliography;
  5. using DocumentFormat.OpenXml.Drawing;
  6. using DocumentFormat.OpenXml.Drawing.Charts;
  7. using DocumentFormat.OpenXml.Math;
  8. using DocumentFormat.OpenXml.Spreadsheet;
  9. using DocumentFormat.OpenXml.Wordprocessing;
  10. using HTEXLib.COMM.Helpers;
  11. using OpenXmlPowerTools;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Diagnostics;
  15. using System.Linq;
  16. using System.Net.NetworkInformation;
  17. using System.Text;
  18. using System.Text.Json;
  19. using System.Threading.Tasks;
  20. using TEAMModelOS.SDK.DI;
  21. using TEAMModelOS.SDK.Extension;
  22. using TEAMModelOS.SDK.Models;
  23. using TEAMModelOS.Services;
  24. using static TEAMModelOS.SDK.Models.Cosmos.Student.StudentAnalysis;
  25. using Activity = TEAMModelOS.SDK.Models.Activity;
  26. namespace TEAMModelOS.SDK
  27. {
  28. public static class ActivityService
  29. {
  30. public static async Task<List<ActivityScoreLevel>> ActivityScores (AzureCosmosFactory _azureCosmos,JsonElement _activityId,string teacherId= null) {
  31. List<ActivityScoreLevel> scoreLevels = new List<ActivityScoreLevel>();
  32. Azure.Response responseContest = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).ReadItemStreamAsync(_activityId.GetString(), new PartitionKey("Contest"));
  33. if (responseContest.Status == 200)
  34. {
  35. long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
  36. Contest contest = JsonDocument.Parse(responseContest.Content).RootElement.ToObject<Contest>();
  37. string sql = $"select value c from c ";
  38. if (!string.IsNullOrWhiteSpace(teacherId)) {
  39. sql=$"{sql} where c.id ='{teacherId}'";
  40. }
  41. var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityEnroll>(sql, $"ActivityEnroll-{_activityId}");
  42. //List<ActivityTeacherScoreLevel> teacherScoreLevels = new List<ActivityTeacherScoreLevel>();
  43. List<ActivityTeacherScore> teacherScores = new List<ActivityTeacherScore>();
  44. if (result.list.IsNotEmpty())
  45. {
  46. if (contest.sign.type==1)
  47. {
  48. var teams = result.list.Where(x => !string.IsNullOrEmpty(x.contest?.cipher)).GroupBy(z => z.contest.cipher);
  49. foreach (var team in teams)
  50. {
  51. var members = team.ToList();
  52. var leader = members.FindAll(z => z.contest.leader==1)?.FirstOrDefault();
  53. if (leader==null)
  54. {
  55. leader=members.First();
  56. }
  57. double score = leader.upload?.score??-1;
  58. if (leader.upload?.showScore==1)
  59. {
  60. score= leader.upload.maskScore;
  61. }
  62. teacherScores.Add(new ActivityTeacherScore
  63. {
  64. uploadId=leader.upload?.uploadId,
  65. uploadName=!string.IsNullOrWhiteSpace(leader.upload?.name) ? leader.upload?.name : $"{leader.contest.teamName}",
  66. score=score,
  67. tmdid=leader.id,
  68. nickname=leader.tmdName,
  69. name=leader.contest.enrollInfos.Find(z => z.code.Equals("name"))?.val,
  70. picture=leader.tmdPicture,
  71. school=leader.schoolId,
  72. schoolName=leader.schoolName,
  73. schoolPicture=leader.schoolPicture,
  74. cipher=leader.contest.cipher,
  75. teamName=leader.contest.teamName,
  76. type=leader.contest.type,
  77. members=members.Select(z => new IdNameCode { id=z.id, name=z.contest.enrollInfos.Find(x => x.code.Equals("name"))?.val, picture=z.tmdPicture, nickname=z.tmdName }).ToList(),
  78. });
  79. }
  80. }
  81. else
  82. {
  83. ///个人组
  84. foreach (var item in result.list)
  85. {
  86. double score = item.upload?.score??-1;
  87. if (item.upload?.showScore==1)
  88. {
  89. score= item.upload.maskScore;
  90. }
  91. teacherScores.Add(new ActivityTeacherScore
  92. {
  93. uploadId=item.upload?.uploadId,
  94. uploadName=!string.IsNullOrWhiteSpace(item.upload?.name) ? item.upload?.name : $"{item.contest.enrollInfos.Find(z => z.code.Equals("name"))?.val}",
  95. score=score,
  96. tmdid=item.id,
  97. nickname=item.tmdName,
  98. name=item.contest.enrollInfos.Find(z => z.code.Equals("name"))?.val,
  99. picture=item.tmdPicture,
  100. school=item.schoolId,
  101. schoolName=item.schoolName,
  102. schoolPicture=item.schoolPicture,
  103. type=item.contest.type,
  104. });
  105. }
  106. }
  107. if(contest.modules.Contains("score") && contest.score!= null)
  108. {
  109. if (contest.score.showType==1)
  110. {
  111. teacherScores= teacherScores.Where(x => x.score>=0).OrderByDescending(x => x.score).ToList();
  112. if (contest.score.levelType==1)
  113. {
  114. var levels = contest.score.scoreLevels.OrderBy(x => x.order).ToList();
  115. foreach (var level in levels)
  116. {
  117. var datas = teacherScores.Take(level.top);
  118. var scores = datas.ToJsonString().ToObject<List<ActivityTeacherScoreLevel>>();
  119. scores.ForEach(z => { z.scoreLevel=level.lable; });
  120. scoreLevels.Add(new ActivityScoreLevel { lable=level.lable, scores=scores });
  121. teacherScores.RemoveAll(x => scores.Select(v => v.uploadId).Contains(x.uploadId));
  122. }
  123. }
  124. else
  125. {
  126. var levels = contest.score.scoreLevels.OrderByDescending(x => x.max);
  127. foreach (var level in levels)
  128. {
  129. scoreLevels.Add(new ActivityScoreLevel { lable=level.lable });
  130. foreach (var item in teacherScores)
  131. {
  132. string label = string.Empty;
  133. if (level.max==100)
  134. {
  135. if (item.score>level.min && item.score<=level.max)
  136. {
  137. label=level.lable;
  138. }
  139. }
  140. else
  141. {
  142. if (item.score>level.min && item.score<level.max)
  143. {
  144. label=level.lable;
  145. }
  146. }
  147. if (!string.IsNullOrWhiteSpace(label))
  148. {
  149. var score = item.ToJsonString().ToObject<ActivityTeacherScoreLevel>();
  150. score.scoreLevel=label;
  151. score.score=item.score;
  152. var data = scoreLevels.Find(x => x.lable.Equals(label));
  153. if (data!=null)
  154. {
  155. data.scores.Add(score);
  156. }
  157. else
  158. {
  159. scoreLevels.Add(new ActivityScoreLevel { lable=label, scores= new List<ActivityTeacherScoreLevel>() { score } });
  160. }
  161. }
  162. }
  163. }
  164. }
  165. }
  166. else
  167. {
  168. if (contest.score.top>-1)
  169. {
  170. teacherScores= teacherScores.Where(x => x.score>=0).OrderByDescending(x => x.score).Take(contest.score.top).ToList();
  171. }
  172. else
  173. {
  174. teacherScores= teacherScores.Where(x => x.score>=0).ToList();
  175. }
  176. var scores = new List<ActivityTeacherScoreLevel>();
  177. foreach (var item in teacherScores)
  178. {
  179. double score = item.score;
  180. var teacher = item.ToJsonString().ToObject<ActivityTeacherScoreLevel>();
  181. teacher.scoreLevel=$"{score}";
  182. teacher.score=score;
  183. scores.Add(teacher);
  184. }
  185. scoreLevels.Add(new ActivityScoreLevel { lable="", scores=scores });
  186. }
  187. }
  188. }
  189. }
  190. return scoreLevels;
  191. }
  192. public static async Task<(List<ExpertContestTaskDto> expertContestTasks, List<ExpertContestTaskDto> activityEnrollsInvalid, List<ExpertContestTaskDto> expertContestTasksDB)>
  193. AllocationTask(AzureCosmosFactory _azureCosmos, IEnumerable<ExpertPeriodSubjectDto> experts, Contest contest, HashSet<string> periodSubjectKeys, string distribute, int taskCount)
  194. {
  195. //先获取已经分配完成的
  196. List<ExpertContestTaskDto> worksDB = new List<ExpertContestTaskDto>();
  197. IEnumerable<ExpertContestTaskDto> complete = new List<ExpertContestTaskDto>();
  198. string taskSQL = $"select value c from c where c.pk='ActivityExpertTask'";
  199. var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityExpertTask>(taskSQL, $"ActivityExpertTask-{contest.id}");
  200. if (result.list.IsNotEmpty())
  201. {
  202. foreach (var item in result.list)
  203. {
  204. worksDB.AddRange(item.contestTasks.Select(z =>
  205. new ExpertContestTaskDto
  206. {
  207. expertName=item.name ,
  208. expertPicture=item.picture,
  209. expertTmdname=item.tmdname,
  210. expertId = item.id,
  211. available = 1,
  212. uploadId = z.uploadId,
  213. name = z.name,
  214. uploadTypes = z.uploadTypes,
  215. count = z.count,
  216. cipher=z.cipher,
  217. type=z.type,
  218. leader=z.leader,
  219. members=z.members,
  220. tmdid=z.tmdid,
  221. score=z.score,
  222. status=z.status,
  223. detailScore=z.detailScore,
  224. activityId=contest.id
  225. }));
  226. }
  227. //处理已经分配完成(taskCount)的作品
  228. complete = worksDB.GroupBy(task => task.uploadId).Where(group => group.Count() >= taskCount).SelectMany(group => group);
  229. }
  230. string enrollSQL = "select value c from c where c.pk='ActivityEnroll'";
  231. //已经满足分配的无需再去处理检查。
  232. if (complete!=null && complete.Count()>0)
  233. {
  234. var uploadIds = complete.Select(z => z.uploadId).ToHashSet();
  235. enrollSQL =$"{enrollSQL} where c.upload.uploadId not in ({string.Join(",", uploadIds.Select(z => $"'{z}'"))})";
  236. }
  237. //检查报名,学段和科目是否匹配
  238. var resultActivityEnroll = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityEnroll>(enrollSQL, $"ActivityEnroll-{contest.id}");
  239. List<ExpertContestTaskDto> expertContestTasks = new List<ExpertContestTaskDto>();
  240. foreach (ActivityEnroll enroll in resultActivityEnroll.list)
  241. {
  242. //如果是队长统一上传
  243. if (contest.upload.captainUpload == 1 && !string.IsNullOrWhiteSpace(enroll.contest?.cipher))
  244. {
  245. var team = resultActivityEnroll.list.FindAll(z => z.contest != null && z.contest.type == 1 && enroll.contest?.type == 1 && z.contest.cipher.Equals(enroll.contest.cipher));
  246. //获取队长信息
  247. var leaders = team.FindAll(z => z.contest.leader == 1);
  248. if (leaders.IsNotEmpty())
  249. {
  250. leaders = new List<ActivityEnroll>() { enroll };
  251. }
  252. List<IdNameCode> members = team.Select(z => new IdNameCode { id = z.id, code = z.schoolId, picture = z.tmdPicture, nickname = z.tmdName, name = z.contest?.enrollInfos?.Find(e => e.code.Equals("name")).val }).ToList();
  253. //队长的报名信息
  254. var leader = leaders?.First();
  255. string name = leader?.contest?.teamName;
  256. var period = leader?.contest?.enrollInfos?.Find(z => z.code.Equals("period"));
  257. var subject = leader?.contest?.enrollInfos?.Find(z => z.code.Equals("subject"));
  258. string uploadId = string.Empty;
  259. if (string.IsNullOrEmpty(name))
  260. {
  261. name = $"{leader?.contest?.enrollInfos?.Find(z => z.code.Equals("name"))?.val}({team.Count})";
  262. }
  263. int count = 0;
  264. int available = -1;
  265. var checkResult = ActivityService.CheckPeriodSubject(distribute, period, subject, periodSubjectKeys);
  266. if (checkResult.available == 0)
  267. {
  268. if (leader?.upload != null && leader.upload.sokrates.IsNotEmpty())
  269. {
  270. count += leader.upload.sokrates.Count;
  271. }
  272. if (leader?.upload != null && leader.upload.files.IsNotEmpty())
  273. {
  274. count += leader.upload.files.Count;
  275. }
  276. if (leader?.upload != null && leader.upload.lessons.IsNotEmpty())
  277. {
  278. count += leader.upload.lessons.Count;
  279. }
  280. if (leader?.upload!=null && leader.upload.complexes.IsNotEmpty())
  281. {
  282. count+=leader.upload.complexes.Count();
  283. }
  284. if (count <= 0)
  285. {
  286. uploadId = enroll.contest.cipher;
  287. available = 5;
  288. }
  289. else
  290. {
  291. uploadId = leader?.upload?.uploadId;
  292. available = checkResult.available;
  293. }
  294. }
  295. else
  296. {
  297. uploadId = enroll.contest.cipher;
  298. available = checkResult.available;
  299. }
  300. ExpertContestTaskDto expertContestTask = expertContestTasks.Find(z => !string.IsNullOrWhiteSpace(z.uploadId) && z.uploadId.Equals(leader.upload));
  301. if (expertContestTask == null)
  302. {
  303. expertContestTasks.Add(new ExpertContestTaskDto
  304. {
  305. uploadId = leader.upload?.uploadId,
  306. name = $"{leader.schoolName}-{name}",
  307. // uploadTypes = new List<string> { leader?.upload.type },
  308. uploadTypes =leader.upload!=null ? new HashSet<string>() { leader.upload.type } : leader.upload.uploadType,
  309. count = count,
  310. cipher = leader.contest?.cipher,
  311. type = 1,
  312. leader = 1,
  313. tmdid = leader.id,
  314. status = -1,
  315. score = -1,
  316. //detailScore=new List<RuleConfig>()
  317. members = members,
  318. periodSubjectKey = checkResult.periodSubjectKey,
  319. period = period?.val,
  320. subject = subject?.val,
  321. available = available,
  322. activityId=contest.id,
  323. });
  324. }
  325. else
  326. {
  327. expertContestTask.available = available;
  328. expertContestTask.name = name;
  329. expertContestTask.count = count;
  330. expertContestTask.members = members;
  331. expertContestTask.periodSubjectKey = checkResult.periodSubjectKey;
  332. expertContestTask.activityId=contest?.id;
  333. }
  334. }
  335. else
  336. {
  337. //如果不是队长统一上传
  338. //学段
  339. var period = enroll.contest?.enrollInfos?.Find(z => z.code.Equals("period"));
  340. //科目
  341. var subject = enroll.contest?.enrollInfos?.Find(z => z.code.Equals("subject"));
  342. string periodSubjectKey = string.Empty;
  343. string name = enroll.contest?.enrollInfos?.Find(z => z.code.Equals("name"))?.val;
  344. string uploadId = string.Empty;
  345. if (!string.IsNullOrEmpty(name))
  346. {
  347. name = $"({name})";
  348. }
  349. else
  350. {
  351. name = string.Empty;
  352. }
  353. int count = 0;
  354. int available = -1;
  355. var checkResult = ActivityService.CheckPeriodSubject(distribute, period, subject, periodSubjectKeys);
  356. if (checkResult.available == 0)
  357. {
  358. if (enroll.upload != null && enroll.upload.sokrates.IsNotEmpty())
  359. {
  360. count += enroll.upload.sokrates.Count;
  361. }
  362. if (enroll.upload != null && enroll.upload.files.IsNotEmpty())
  363. {
  364. count += enroll.upload.files.Count;
  365. }
  366. if (enroll.upload != null && enroll.upload.lessons.IsNotEmpty())
  367. {
  368. count += enroll.upload.lessons.Count;
  369. }
  370. if (enroll.upload != null && enroll.upload.complexes.IsNotEmpty())
  371. {
  372. count+=enroll.upload.complexes.Count();
  373. }
  374. if (count <= 0)
  375. {
  376. available = 5;
  377. uploadId = enroll.id;
  378. }
  379. else
  380. {
  381. available = checkResult.available;
  382. uploadId = enroll.upload.uploadId;
  383. }
  384. }
  385. else
  386. {
  387. uploadId = enroll.id;
  388. available = checkResult.available;
  389. }
  390. ExpertContestTaskDto expertContestTask = expertContestTasks.Find(z => !string.IsNullOrWhiteSpace(z.uploadId) && z.uploadId.Equals(enroll.upload));
  391. if (expertContestTask == null)
  392. {
  393. expertContestTasks.Add(new ExpertContestTaskDto
  394. {
  395. uploadId = uploadId,
  396. name = $"{enroll.schoolName}-{name}",
  397. //uploadTypes = new List<string> { enroll.upload?.type },
  398. uploadTypes =enroll.upload!=null ? new HashSet<string>() { enroll.upload.type } :enroll.upload.uploadType,
  399. count = count,
  400. cipher = enroll.contest?.cipher,
  401. type = 1,
  402. leader = 1,
  403. tmdid = enroll.id,
  404. status = -1,
  405. score = -1,
  406. periodSubjectKey = checkResult.periodSubjectKey,
  407. period = period?.val,
  408. subject = subject?.val,
  409. available = available,
  410. activityId = contest?.id,
  411. });
  412. }
  413. else
  414. {
  415. expertContestTask.available = available;
  416. expertContestTask.name = name;
  417. expertContestTask.count = count;
  418. expertContestTask.periodSubjectKey = checkResult.periodSubjectKey;
  419. expertContestTask.activityId=contest?.id;
  420. }
  421. }
  422. }
  423. List<ExpertContestTaskDto> invalids = expertContestTasks.FindAll(z => z.available!=0);
  424. List<ExpertContestTaskDto> works = expertContestTasks.FindAll(z => z.available==0);
  425. var data = AssignWorksToExperts(works, worksDB, experts, taskCount);
  426. if (invalids.IsNotEmpty()) {
  427. invalids.AddRange(data.assignmentsInvalid);
  428. }
  429. List<ExpertContestTaskDto> okTask = new List<ExpertContestTaskDto>();
  430. okTask.AddRange(data.assignmentsAdd);
  431. okTask.AddRange(worksDB);
  432. var groups= okTask.GroupBy(z => z.uploadId).Select(x => new { key = x.Key, list = x.ToList() });
  433. foreach (var item in groups) {
  434. if (item.list.Count()<taskCount) {
  435. ExpertContestTaskDto taskDto= item.list.First().ToJsonString().ToObject<ExpertContestTaskDto>();
  436. taskDto.expertName=null;
  437. taskDto.expertId=null;
  438. taskDto.expertPicture=null;
  439. taskDto.expertTmdname=null;
  440. //,8分配次数不足
  441. taskDto.available=8;
  442. invalids.Add(taskDto);
  443. }
  444. }
  445. return (data.assignmentsAdd, invalids, worksDB);
  446. }
  447. public static (int available, string periodSubjectKey) CheckPeriodSubject(string distribute , EnrollInfo period, EnrollInfo subject, HashSet<string> periodSubjectKeys) {
  448. int available = -1;
  449. string periodSubjectKey= string.Empty;
  450. if (distribute.Equals("period"))
  451. {
  452. if (period != null)
  453. {
  454. periodSubjectKey = $"{period.val}-";
  455. }
  456. else
  457. {
  458. available = 2;
  459. }
  460. }
  461. else if (distribute.Equals("subject"))
  462. {
  463. if (subject != null)
  464. {
  465. periodSubjectKey = $"-{subject.val}";
  466. }
  467. else
  468. {
  469. available = 3;
  470. }
  471. }
  472. else if (distribute.Equals("periodAndSubject"))
  473. {
  474. if (period != null && subject != null)
  475. {
  476. periodSubjectKey = $"{period.val}-{subject.val}";
  477. }
  478. else
  479. {
  480. available = 4;
  481. }
  482. }
  483. else
  484. {
  485. periodSubjectKey = "-";
  486. }
  487. if (!string.IsNullOrWhiteSpace(periodSubjectKey)) {
  488. if (periodSubjectKeys.Contains(periodSubjectKey))
  489. {
  490. available = 0;
  491. }
  492. else
  493. {
  494. //学段学科不匹配
  495. available = 6;
  496. }
  497. }
  498. return (available, periodSubjectKey);
  499. }
  500. /// <summary>
  501. /// 将作品按分配次数,分配给不同的专家
  502. /// </summary>
  503. /// <param name="works"></param>
  504. /// <param name="experts"></param>
  505. /// <param name="N"></param>
  506. /// <returns></returns>
  507. static (List<ExpertContestTaskDto> assignmentsAdd, List<ExpertContestTaskDto> assignmentsInvalid) AssignWorksToExperts(List<ExpertContestTaskDto> works,List<ExpertContestTaskDto> worksDB, IEnumerable<ExpertPeriodSubjectDto> experts, int N)
  508. {
  509. //增加的
  510. var assignmentsAdd = new List<ExpertContestTaskDto>();
  511. //未分配到的
  512. var assignmentsInvalid = new List<ExpertContestTaskDto>();
  513. var random = new Random();
  514. //用于处理数据库和新分配的结果中检查已经分配过的作品和专家
  515. var assignmentsAll = worksDB.ToJsonString().ToObject<List<ExpertContestTaskDto>>();
  516. foreach (var work in works)
  517. {
  518. for (int i = 0; i < N; i++)
  519. {
  520. //分配次数已经Ok,分配结果完善的,不需要再去处理
  521. if (assignmentsAll.Count(z => z.uploadId.Equals(work.uploadId))>=N) {
  522. continue;
  523. }
  524. var availableExperts = experts
  525. .OrderBy(expert => assignmentsAll.Count(a => a.expertId == expert.expertId))
  526. .Where(expert => expert.periodSubjects.Contains(work.periodSubjectKey) && !assignmentsAll.Any(a => a.uploadId == work.uploadId && a.expertId == expert.expertId))
  527. .ToList();
  528. if (availableExperts.Count > 0)
  529. {
  530. var selectedExpert = availableExperts[random.Next(availableExperts.Count)];
  531. var newWork= work.DeepCopy<ExpertContestTaskDto>();
  532. newWork.expertId = selectedExpert.expertId;
  533. newWork.expertName = selectedExpert.expertName;
  534. newWork.expertPicture = selectedExpert.expertPicture;
  535. newWork.expertTmdname = selectedExpert.expertTmdname;
  536. newWork.available = 1;
  537. newWork.turn = i + 1;
  538. assignmentsAdd.Add(newWork);
  539. assignmentsAll.Add(newWork);
  540. }
  541. else
  542. {
  543. var newWork = work.DeepCopy<ExpertContestTaskDto>();
  544. newWork.expertId =null;
  545. newWork.available = 7;
  546. newWork.turn = i + 1;
  547. //作品在第几轮未匹配到
  548. assignmentsInvalid.Add(newWork);
  549. //Console.WriteLine($"No available expert for WorkId {work.uploadId} and subject {work.periodSubjectKey} in attempt {i + 1}.");
  550. break;
  551. }
  552. }
  553. }
  554. return (assignmentsAdd, assignmentsInvalid);
  555. }
  556. /// <summary>
  557. /// 删除活动关联的数据
  558. /// </summary>
  559. /// <param name="_azureCosmos"></param>
  560. /// <param name="activity"></param>
  561. /// <returns></returns>
  562. public static async Task DeleteActivityRelated(AzureCosmosFactory _azureCosmos,Activity activity)
  563. {
  564. //删除模块,Contest, Training ,Research, ReviewRule规则(ReviewRule-disposable"; 存为活动)
  565. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).DeleteItemStreamAsync(activity.id, new PartitionKey("Contest"));
  566. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).DeleteItemStreamAsync(activity.id, new PartitionKey("Training"));
  567. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).DeleteItemStreamAsync(activity.id, new PartitionKey("Research"));
  568. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).DeleteItemStreamAsync(activity.id, new PartitionKey("ReviewRule-disposable"));
  569. //删除邀请教师 ActivityTeacher,
  570. var resultTeacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
  571. .GetList<IdCode>("select c.id ,c.code from c where c.pk='ActivityEnroll' and c.", $"ActivityTeacher-{activity.id}");
  572. if (resultTeacher.list.IsNotEmpty())
  573. {
  574. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).DeleteItemsStreamAsync(resultTeacher.list.Select(z => z.id).ToList(), $"ActivityTeacher-{activity.id}");
  575. }
  576. //删除报名数据 ActivityEnroll
  577. var resultEnroll = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
  578. .GetList<IdCode>("select c.id ,c.code from c where c.pk='ActivityEnroll' and c.", $"ActivityEnroll-{activity.id}");
  579. if (resultEnroll.list.IsNotEmpty())
  580. {
  581. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).DeleteItemsStreamAsync(resultEnroll.list.Select(z => z.id).ToList(), $"ActivityEnroll-{activity.id}");
  582. }
  583. //删除专家数据 ActivityExpert
  584. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).DeleteItemStreamAsync(activity.id, new PartitionKey("ActivityExpert"));
  585. }
  586. /// <summary>
  587. /// 生成组队口令
  588. /// </summary>
  589. /// <param name="client"></param>
  590. /// <param name="_dingDing"></param>
  591. /// <param name="_option"></param>
  592. /// <param name="_activityId"></param>
  593. /// <returns></returns>
  594. /// <exception cref="Exception"></exception>
  595. public static async Task<string> GenCipher(CosmosClient client, DingDing _dingDing, TEAMModelOS.Models.Option _option, string _activityId)
  596. {
  597. string _num09 = "123456789";
  598. string no = $"{Utils.CreatSaltString(7, _num09)}";
  599. for (int i = 0; i < 10; i++)
  600. {
  601. List<SheetConfig> sheets = new List<SheetConfig>();
  602. bool hasCurrFrom = false;
  603. string cipherSQL = $"select value c.id from c where c.contest!=null and c.activityId='{_activityId}' and c.contest.type=1 and c.contest.cipher='{no}' ";
  604. var cipherResult = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<string>(cipherSQL, $"ActivityEnroll-{_activityId}");
  605. if (cipherResult.list.IsNotEmpty() && cipherResult.list.Count>0) {
  606. hasCurrFrom = true;
  607. }
  608. if (hasCurrFrom)
  609. {
  610. if (i == 9)
  611. {
  612. string msg = $"{_option.Location},ActivityService/GenCipher\n 组队口令生成异常,重复生成次数超过10次";
  613. await _dingDing.SendBotMsg($"OS,{_option.Location},{msg}", GroupNames.醍摩豆服務運維群組);
  614. throw new Exception(msg);
  615. }
  616. else
  617. {
  618. no = $"{Utils.CreatSaltString(7, _num09)}";
  619. }
  620. }
  621. else { break; }
  622. }
  623. return no;
  624. }
  625. public static async Task<IEnumerable<ActivityDto>> AreaActivityList(AzureCosmosFactory _azureCosmos, AzureStorageFactory _azureStorage, JsonElement request, string _areaId, int isCount = 0)
  626. {
  627. string yearSql = string.Empty;
  628. if (isCount==0) {
  629. yearSql = $" and c.year={DateTimeOffset.Now.Year}";
  630. if (request.TryGetProperty("year", out JsonElement _year))
  631. {
  632. yearSql = $" and c.year={_year}";
  633. }
  634. }
  635. string sql = $"select value c from c where c.owner='{_areaId}' {yearSql} ";
  636. var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ActivityDto>(sql, "Activity");
  637. result.list.ForEach(z => {
  638. var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(z.owner, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
  639. z.sas=blob_sas;
  640. z.url=blob_uri;
  641. });
  642. return result.list.OrderByDescending(z => z.stime);
  643. }
  644. public static async Task<List<ActivityDto>> SchoolActivityList(AzureCosmosFactory _azureCosmos, AzureStorageFactory _azureStorage, JsonElement request, string school, int isCount = 0) {
  645. School schoolbase = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(school, new PartitionKey("Base"));
  646. List<ActivityDto> activities = new List<ActivityDto>();
  647. string yearSql = string.Empty;
  648. if (isCount==0)
  649. {
  650. yearSql = $" and c.year={DateTimeOffset.Now.Year}";
  651. if (request.TryGetProperty("year", out JsonElement _year))
  652. {
  653. yearSql = $" and c.year={_year}";
  654. }
  655. }
  656. //获取开放的
  657. {
  658. //完全开放 所有的学校
  659. string sqlOpen = $"select value c from c where c.scope='public' {yearSql} and (c.publish=1 or c.publish=2 ) and( ARRAY_LENGTH(c.invitedSchools)=0 or IS_DEFINED(c.invitedSchools) = false ) ";
  660. var resultOpen = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ActivityDto>(sqlOpen, "Activity");
  661. activities.AddRange(resultOpen.list);
  662. //部分学校
  663. string sqlSchool = $"select value c from c join s in c.invitedSchools where c.scope='public' {yearSql} and (c.publish=1 or c.publish=2 ) and s.id='{school}' ";
  664. var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ActivityDto>(sqlSchool, "Activity");
  665. resultSchool.list.ForEach(z =>
  666. {
  667. var confirmedSchool = z.confirmedSchools.Find(z => z.id.Equals(school));
  668. if (confirmedSchool==null)
  669. {
  670. z.confirmedSchools.Add(new ActivityConfirmedSchool
  671. {
  672. id=schoolbase.id,
  673. name=schoolbase.name,
  674. picture=schoolbase.picture,
  675. status=0
  676. });
  677. }
  678. });
  679. activities.AddRange(resultSchool.list);
  680. }
  681. //获取区级下放的
  682. {
  683. if (!string.IsNullOrWhiteSpace(schoolbase.areaId))
  684. {
  685. //区级所有学校
  686. string sqlOpen = $"select value c from c where c.scope='area'{yearSql} and (c.publish=1 or c.publish=2 ) and c.owner='{schoolbase.areaId}' and( ARRAY_LENGTH(c.invitedSchools)=0 or IS_DEFINED(c.invitedSchools) = false) ";
  687. var resultOpen = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ActivityDto>(sqlOpen, "Activity");
  688. resultOpen.list.ForEach(z =>
  689. {
  690. var confirmedSchool = z.confirmedSchools.Find(z => z.id.Equals(school));
  691. if (confirmedSchool==null)
  692. {
  693. z.confirmedSchools.Add(new ActivityConfirmedSchool
  694. {
  695. id=schoolbase.id,
  696. name=schoolbase.name,
  697. picture=schoolbase.picture,
  698. status=0
  699. });
  700. }
  701. });
  702. activities.AddRange(resultOpen.list);
  703. //区级部分学校
  704. string sqlSchool = $"select value c from c join s in c.invitedSchools where c.scope='area'{yearSql} and (c.publish=1 or c.publish=2 ) and c.owner='{schoolbase.areaId}' and s.id='{school}' ";
  705. var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ActivityDto>(sqlSchool, "Activity");
  706. resultSchool.list.ForEach(z =>
  707. {
  708. var confirmedSchool = z.confirmedSchools.Find(z => z.id.Equals(school));
  709. if (confirmedSchool==null)
  710. {
  711. z.confirmedSchools.Add(new ActivityConfirmedSchool
  712. {
  713. id=schoolbase.id,
  714. name=schoolbase.name,
  715. picture=schoolbase.picture,
  716. status=0
  717. });
  718. }
  719. });
  720. activities.AddRange(resultSchool.list);
  721. }
  722. }
  723. //获取学校自己的
  724. {
  725. string sqlSchool = $"select value c from c where c.scope='school'{yearSql} and c.owner='{school}' ";
  726. var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ActivityDto>(sqlSchool, "Activity");
  727. activities.AddRange(resultSchool.list);
  728. }
  729. long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
  730. activities.ForEach(z =>
  731. {
  732. var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(z.owner, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
  733. z.sas=blob_sas;
  734. z.url = blob_uri;
  735. if (z.etime<now)
  736. {
  737. z.publish=2;
  738. }
  739. });
  740. return activities;
  741. }
  742. public static async Task<List<TeacherActivityDto>> TeacherActivityList(AzureCosmosFactory _azureCosmos,AzureStorageFactory _azureStorage, JsonElement request, string tmdid, int isCount = 0)
  743. {
  744. List<TeacherActivityDto> activities = new List<TeacherActivityDto>();
  745. HashSet<string> inviteActivityIds = new HashSet<string>();
  746. string yearSql = string.Empty;
  747. if (isCount==0)
  748. {
  749. yearSql = $" and c.year={DateTimeOffset.Now.Year}";
  750. if (request.TryGetProperty("year", out JsonElement _year) && int.TryParse($"{_year}", out int year))
  751. {
  752. yearSql = $" and c.year={year}";
  753. }
  754. }
  755. //先获取邀请制的
  756. string sqlInvite = $"select value c from c join t in c.inviteTeachers where t.id='{tmdid}' and c.pk='ActivityTeacher'";
  757. var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityTeacher>(sqlInvite);
  758. inviteActivityIds= result.list.Where(x=>!string.IsNullOrWhiteSpace(x.activityId)).Select(z => z.activityId).ToHashSet();
  759. if (inviteActivityIds.Count>0)
  760. {
  761. string sqlActivity = $"select value c from c where c.id in ({string.Join(",", inviteActivityIds.Select(z => $"'{z}'"))}) {yearSql} ";
  762. var resultActivity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<TeacherActivityDto>(sqlActivity, "Activity");
  763. if (resultActivity.list.IsNotEmpty())
  764. {
  765. activities.AddRange(resultActivity.list);
  766. }
  767. }
  768. Teacher teacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>(tmdid, new PartitionKey("Base"));
  769. string schoolOwnerIn = string.Empty;
  770. string schoolIdIn = string.Empty;
  771. if (teacher.schools.IsNotEmpty())
  772. {
  773. schoolIdIn = $"and i.id in ({string.Join(",", teacher.schools.Select(z => $"'{z.schoolId}'"))})";
  774. schoolOwnerIn= $"and c.owner in ({string.Join(",", teacher.schools.Select(z => $"'{z.schoolId}'"))})";
  775. }
  776. //获取开放的
  777. {
  778. //完全开放 所有的学校
  779. string sqlOpen = $"select value c from c where c.scope='public' and (c.publish=1 or c.publish=2 ) and( ARRAY_LENGTH(c.invitedSchools)=0 or IS_DEFINED(c.invitedSchools) = false ) {yearSql} ";
  780. var resultOpen = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<TeacherActivityDto>(sqlOpen, "Activity");
  781. activities.AddRange(resultOpen.list);
  782. if (!string.IsNullOrWhiteSpace(schoolIdIn))
  783. { //部分学校
  784. string sqlSchool = $"select value c from c join i in c.confirmedSchools where c.scope='public' and c.joinMode='enroll' and (c.publish=1 or c.publish=2 ) and i.status=1 {yearSql} {schoolIdIn} ";
  785. var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<TeacherActivityDto>(sqlSchool, "Activity");
  786. activities.AddRange(resultSchool.list);
  787. }
  788. }
  789. string areaOwnerIn = string.Empty;
  790. var hasAreaSchools = teacher.schools.FindAll(z => !string.IsNullOrWhiteSpace(z.areaId));
  791. if (hasAreaSchools.IsNotEmpty())
  792. {
  793. areaOwnerIn = $"and c.owner in ({string.Join(",", hasAreaSchools.Select(z => $"'{z.areaId}'"))})";
  794. schoolIdIn = $"and i.id in ({string.Join(",", hasAreaSchools.Select(z => $"'{z.schoolId}'"))})";
  795. }
  796. //获取所有区级的
  797. if (!string.IsNullOrWhiteSpace(areaOwnerIn) && !string.IsNullOrEmpty(schoolIdIn))
  798. {
  799. string sqlOpen = $"select value c from c join i in c.confirmedSchools where c.scope='area' and c.joinMode='enroll' and (c.publish=1 or c.publish=2 ) and i.status=1 {yearSql} {areaOwnerIn} {schoolIdIn} ";
  800. var resultOpen = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<TeacherActivityDto>(sqlOpen, "Activity");
  801. activities.AddRange(resultOpen.list);
  802. }
  803. //获取所有学校的
  804. if (!string.IsNullOrWhiteSpace(schoolOwnerIn))
  805. {
  806. string sqlSchool = $"select value c from c where c.scope='school' and c.joinMode='enroll' and (c.publish=1 or c.publish=2 ) {yearSql} {schoolOwnerIn} ";
  807. var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<TeacherActivityDto>(sqlSchool, "Activity");
  808. activities.AddRange(resultSchool.list);
  809. }
  810. long now=DateTimeOffset.Now.ToUnixTimeMilliseconds();
  811. activities.ForEach(z =>
  812. {
  813. var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(z.owner, BlobContainerSasPermissions.Read);
  814. z.sas=blob_sas;
  815. z.url=blob_uri;
  816. if (z.etime<now)
  817. {
  818. z.publish=2;
  819. }
  820. });
  821. if (activities.IsNotEmpty())
  822. {
  823. string sql = $"select value c from c where c.pk='ActivityEnroll' and contains(c.code,'ActivityEnroll-') and c.id='{tmdid}' and c.activityId in ({string.Join(",", activities.Select(z => $"'{z.id}'"))})";
  824. var resultEnroll = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityEnroll>(sql);
  825. foreach (var enroll in resultEnroll.list)
  826. {
  827. var activityDto = activities.Find(z => z.id.Equals(enroll.activityId));
  828. if (activityDto!=null)
  829. {
  830. if (enroll.contest!=null && enroll.contest.enrollTime>0)
  831. {
  832. activityDto.contestSign=1;
  833. activityDto.signTime=enroll.contest.enrollTime;
  834. activityDto.contestType=enroll.contest.type;
  835. }
  836. if (enroll.upload!=null && (enroll.upload.files.IsNotEmpty() || enroll.upload.sokrates.IsNotEmpty() || enroll.upload.lessons.IsNotEmpty()) )
  837. {
  838. activityDto.contestUpload=1;
  839. activityDto.uploadTime=enroll.upload.uploadTime;
  840. activityDto.uploadType=enroll.upload.type;
  841. }
  842. if (enroll.upload!=null &&enroll.upload.complexes.IsNotEmpty())
  843. {
  844. activityDto.contestUpload=1;
  845. activityDto.uploadTime=enroll.upload.uploadTime;
  846. activityDto.uploadTypes=enroll.upload.uploadType;
  847. }
  848. }
  849. }
  850. }
  851. return activities;
  852. }
  853. public static async Task<(ReviewRule reviewRule, int invalidCode, string msg)> UpsertReviewRule(ReviewRuleTree reviewRuleTree,Activity activity, Contest contest, AzureCosmosFactory _azureCosmos)
  854. {
  855. var nodes = new List<RuleConfig>();
  856. nodes= TreeToList(reviewRuleTree.trees, nodes);
  857. ReviewRule reviewRule = new ReviewRule() {
  858. id= activity.id,
  859. code="ReviewRule-disposable",
  860. pk="ReviewRule",
  861. name=reviewRuleTree.name,
  862. desc=reviewRuleTree.desc,
  863. owner=activity.owner,
  864. type="disposable",
  865. configs=nodes,
  866. sourceName=activity.name,
  867. taskCount=reviewRuleTree.taskCount,
  868. scoreRule=reviewRuleTree.scoreRule,
  869. distribute=reviewRuleTree.distribute,
  870. scoreDetail=reviewRuleTree.scoreDetail,
  871. };
  872. //代码顺序不能动
  873. var checkReult = CheckReviewRule(reviewRule, contest);
  874. if (checkReult.invalidCode==200) {
  875. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).UpsertItemAsync(reviewRule, new Azure.Cosmos.PartitionKey(reviewRule.code));
  876. if (reviewRuleTree.upsertAsTemplate==1)
  877. {
  878. reviewRule.code="ReviewRule-template";
  879. reviewRule.type="template";
  880. reviewRule.taskCount = reviewRuleTree.taskCount;
  881. reviewRule.scoreRule = reviewRuleTree.scoreRule;
  882. reviewRule.distribute = reviewRuleTree.distribute;
  883. reviewRule.scoreDetail = reviewRuleTree.scoreDetail;
  884. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).UpsertItemAsync(reviewRule, new Azure.Cosmos.PartitionKey(reviewRule.code));
  885. }
  886. }
  887. return (reviewRule,checkReult.invalidCode,checkReult.msg);
  888. }
  889. public static (int invalidCode, string msg) CheckReviewRule(ReviewRule reviewRule,Contest contest)
  890. {
  891. int invalidCode = -1;
  892. string msg = "";
  893. if (reviewRule.taskCount<=0) {
  894. invalidCode=28;
  895. msg="作品分配次数至少一次!";
  896. }
  897. if (reviewRule.taskCount==1 )
  898. {
  899. if (reviewRule.scoreRule.Equals("only"))
  900. {
  901. invalidCode=200;
  902. }
  903. else
  904. {
  905. invalidCode=21;//分配次数一次,必须匹配only
  906. msg="分配次数1次,必须匹配【默认统分】规则";
  907. }
  908. }
  909. if (reviewRule.taskCount>=2 )
  910. {
  911. if ((reviewRule.scoreRule.Equals("avg")||reviewRule.scoreRule.Equals("top"))) {
  912. invalidCode=200;
  913. }
  914. else
  915. {
  916. invalidCode=22;//分配次数2次,必须匹配avg,top
  917. msg="分配次数2次,必须匹配【按平均分】,【按最高分】";
  918. }
  919. }
  920. if (reviewRule.taskCount>=3 )
  921. {if ((reviewRule.scoreRule.Equals("avg")||reviewRule.scoreRule.Equals("top")||reviewRule.scoreRule.Equals("rmLowAvg")||reviewRule.scoreRule.Equals("rmTopAvg")))
  922. {
  923. invalidCode=200;
  924. }
  925. else
  926. {
  927. invalidCode=23;//分配次数2次,必须匹配avg,top,rmLowAvg,rmTopAvg
  928. msg="分配次数3次,必须匹配必须匹配【按平均分】,【按最高分】,【去掉最低分的平均分】,【去掉最高分的平均分】";
  929. }
  930. }
  931. if (reviewRule.taskCount>=4 )
  932. {
  933. if ((reviewRule.scoreRule.Equals("avg")||reviewRule.scoreRule.Equals("top")||reviewRule.scoreRule.Equals("rmLowAvg")||reviewRule.scoreRule.Equals("rmTopAvg")||reviewRule.scoreRule.Equals("rmLowTopAvg")))
  934. {
  935. invalidCode=200;
  936. }
  937. else
  938. {
  939. invalidCode=24;//分配次数2次,必须匹配avg,top,rmLowAvg,rmTopAvg,rmLowTopAvg
  940. msg="分配次数4次,必须匹配必须匹配【按平均分】,【按最高分】,【去掉最低分的平均分】,【去掉最高分的平均分】,【去掉最高分和最低分的平均分】";
  941. }
  942. }
  943. if (invalidCode==200) {
  944. if (!string.IsNullOrWhiteSpace(reviewRule.distribute))
  945. {
  946. if (reviewRule.distribute.Equals("period"))
  947. {
  948. var period = contest.sign?.fields?.Find(z => z.field.Equals("period"));
  949. if (period!= null)
  950. {
  951. invalidCode = 200;
  952. }
  953. else
  954. {
  955. invalidCode=25;
  956. msg="作品分配匹配规则为【学段】,但报名填写表单未配置。";
  957. }
  958. }
  959. else if (reviewRule.distribute.Equals("subject"))
  960. {
  961. var subject = contest.sign?.fields?.Find(z => z.field.Equals("subject"));
  962. if (subject!= null)
  963. {
  964. invalidCode = 200;
  965. }
  966. else
  967. {
  968. invalidCode=26;
  969. msg="作品分配匹配规则为【学科】,但报名填写表单未配置。";
  970. }
  971. }
  972. else if (reviewRule.distribute.Equals("periodAndSubject"))
  973. {
  974. var period = contest.sign?.fields?.Find(z => z.field.Equals("period"));
  975. var subject = contest.sign?.fields?.Find(z => z.field.Equals("subject"));
  976. if (subject!= null && period!= null)
  977. {
  978. invalidCode = 200;
  979. }
  980. else
  981. {
  982. invalidCode=27;
  983. msg="作品分配匹配规则为【学段,学科】,但报名填写表单未配置。";
  984. }
  985. }
  986. else if (reviewRule.distribute.Equals("none"))
  987. {
  988. invalidCode=200;
  989. }
  990. else
  991. {
  992. invalidCode=30;
  993. msg=$"作品分配匹配规则未识别【{reviewRule.distribute}】。";
  994. }
  995. }
  996. else {
  997. invalidCode=29;
  998. msg="作品分配匹配规则不能为空。";
  999. }
  1000. }
  1001. return (invalidCode,msg);
  1002. }
  1003. public static List<RuleConfig> TreeToList(List<RuleConfigTree> trees, List<RuleConfig> nodes) {
  1004. trees = trees.OrderBy(x => x.order).ToList();
  1005. List<RuleConfig> list = new List<RuleConfig>();
  1006. trees.ForEach(x => {
  1007. List<string> cids = new List<string>();
  1008. if (x.children.IsNotEmpty())
  1009. {
  1010. x.children.ForEach(y => cids.Add(y.id));
  1011. }
  1012. var node = new RuleConfig
  1013. {
  1014. id = x.id,
  1015. pid = x.pid,
  1016. cids= cids,
  1017. label = x.label,
  1018. desc = x.desc,
  1019. score = x.score,
  1020. order = x.order,
  1021. };
  1022. list.Add(node);
  1023. });
  1024. nodes.AddRange(list);
  1025. foreach (RuleConfigTree tree in trees)
  1026. {
  1027. if (null != tree.children && tree.children.Count > 0)
  1028. {
  1029. TreeToList(tree.children, nodes);
  1030. }
  1031. }
  1032. return nodes;
  1033. }
  1034. public static List<RuleConfigTree> ListToTree(List<RuleConfig> noes)
  1035. {
  1036. List<RuleConfigTree> list = noes.ToJsonString().ToObject<List<RuleConfigTree>>();
  1037. var res = from r in list group r by r.id into g select g;
  1038. Dictionary<string, RuleConfigTree> blockDict = new Dictionary<string, RuleConfigTree>();
  1039. foreach (var s in res)
  1040. {
  1041. blockDict.TryAdd(s.First().id, s.First());
  1042. }
  1043. return GetChild(list, blockDict);
  1044. }
  1045. private static List<RuleConfigTree> GetChild(List<RuleConfigTree> list, Dictionary<string, RuleConfigTree> dict)
  1046. {
  1047. List<RuleConfigTree> trees = new List<RuleConfigTree>();
  1048. trees = trees.OrderBy(x => x.order).ToList();
  1049. foreach (RuleConfigTree node in list)
  1050. {
  1051. bool flag = dict.TryGetValue(node.pid, out RuleConfigTree syllabus);
  1052. if (flag && syllabus != null)
  1053. {
  1054. syllabus.children.Add(node);
  1055. }
  1056. else
  1057. {
  1058. trees.Add(node);
  1059. }
  1060. }
  1061. return trees;
  1062. }
  1063. }
  1064. }