ActivityService.cs 55 KB

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