ActivityService.cs 55 KB

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