ActivityService.cs 65 KB

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