GroupListService.cs 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498
  1. using Azure.Cosmos;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Threading.Tasks;
  5. using TEAMModelOS.SDK.DI;
  6. using TEAMModelOS.SDK.Extension;
  7. using TEAMModelOS.SDK.Models.Cosmos.Common;
  8. using HTEXLib.COMM.Helpers;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Text.Json;
  12. using TEAMModelOS.Models;
  13. using Azure.Messaging.ServiceBus;
  14. using Microsoft.Extensions.Configuration;
  15. using TEAMModelOS.SDK.Models.Service;
  16. using System.Text.RegularExpressions;
  17. using TEAMModelOS.SDK.Models;
  18. using System.Net.Http;
  19. using DocumentFormat.OpenXml.Wordprocessing;
  20. using static TEAMModelOS.SDK.GroupListService;
  21. namespace TEAMModelOS.SDK
  22. {
  23. public class GroupListService
  24. {
  25. public static async Task DeleteGrouplistEvent(string id , string code,string tbname ,CosmosClient client, IConfiguration _configuration, AzureServiceBusFactory _serviceBus)
  26. {
  27. GroupChange change = new GroupChange();
  28. GroupList groupList = await client.GetContainer(Constant.TEAMModelOS, tbname).ReadItemAsync<GroupList>(id.ToString(), new PartitionKey(code));
  29. var tleave = groupList.members.FindAll(x => x.type == 1);
  30. if (tleave.IsNotEmpty())
  31. {
  32. if (groupList.type.Equals("research") || groupList.type.Equals("yxtrain"))
  33. {
  34. change.tchleave.AddRange(tleave);
  35. }
  36. else
  37. {
  38. change.tmdleave.AddRange(tleave);
  39. }
  40. }
  41. var sleave = groupList.members.FindAll(x => x.type == 2);
  42. if (sleave.IsNotEmpty())
  43. {
  44. change.stuleave.AddRange(sleave);
  45. }
  46. change.listid = groupList.id;
  47. change.scope = groupList.scope;
  48. change.originCode = $"{code}";
  49. change.school = groupList.school;
  50. change.creatorId = groupList.creatorId;
  51. change.type = groupList.type;
  52. change.status = "delete";
  53. if (change.tmdleave.IsNotEmpty() || change.tchleave.IsNotEmpty() || change.stuleave.IsNotEmpty())
  54. {
  55. var messageChange = new ServiceBusMessage(change.ToJsonString());
  56. messageChange.ApplicationProperties.Add("name", "GroupChange");
  57. var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
  58. await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
  59. }
  60. await client.GetContainer(Constant.TEAMModelOS, tbname).DeleteItemStreamAsync(id.ToString(), new PartitionKey(code));
  61. }
  62. /// <summary>
  63. /// 查询名单成员所在的名单列表,
  64. /// </summary>
  65. /// <param name="_coreAPIHttpService"></param>
  66. /// <param name="client"></param>
  67. /// <param name="_dingDing"></param>
  68. /// <param name="memberId">成员id </param>
  69. /// <param name="memberType">成员类型</param>
  70. /// <param name="school">成员所在的学校 ,可为空</param>
  71. /// <param name="groupTypes">过滤名单的类型集合,不传则是全部</param>
  72. /// <param name="graduate">毕业类型0在校,1毕业 , -1查全部。</param>
  73. /// <returns></returns>
  74. public static async Task<List<GroupListGrp>> GetMemberInGroupList(CoreAPIHttpService _coreAPIHttpService, CosmosClient client, DingDing _dingDing, string memberId, int memberType, string school,List<string> groupTypes,int graduate =-1) {
  75. List<GroupListGrp> groupLists = new List<GroupListGrp>();
  76. if (groupTypes.IsEmpty() || groupTypes.Contains("class")) {
  77. if (!string.IsNullOrWhiteSpace(school) && memberType == 2)
  78. {
  79. Student student = null;
  80. try
  81. {
  82. student = await client.GetContainer(Constant.TEAMModelOS, Constant.Student).ReadItemAsync<Student>(memberId, new PartitionKey($"Base-{school}"));
  83. }
  84. catch (CosmosException ex) when (ex.Status == 404)
  85. {
  86. return null;
  87. }
  88. if (!string.IsNullOrWhiteSpace(student.classId))
  89. {
  90. try
  91. {
  92. Class clazz = await client.GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<Class>(student.classId, new PartitionKey($"Class-{school}"));
  93. GroupListGrp groupList = new GroupListGrp
  94. {
  95. id = clazz.id,
  96. code = $"GroupList-{clazz.school}",
  97. name = clazz.name,
  98. periodId = clazz.periodId,
  99. pk = "GroupList",
  100. expire=0,
  101. year = clazz.year,
  102. school = clazz.school,
  103. scope = "school",
  104. type = "class",
  105. no = clazz.no,
  106. leader = clazz.teacher?.id,
  107. graduate=clazz.graduate,
  108. grades= new HashSet<int>() { clazz.year}
  109. };
  110. //graduate传入的状态>=0 表示指定状态查询,且传入的状态与数据库的状态一致。
  111. if (graduate >= 0 )
  112. {
  113. if (groupList.graduate == graduate) {
  114. groupLists.Add(groupList);
  115. }
  116. }
  117. //全部。
  118. else if(graduate == -1)
  119. {
  120. groupLists.Add(groupList);
  121. }
  122. }
  123. catch (CosmosException ex) when (ex.Status == 404)
  124. {
  125. }
  126. }
  127. }
  128. }
  129. string SummarySql = " c.id,c.code,c.name,c.no,c.periodId,c.scope,c.school,c.creatorId,c.type,c.year,c.tcount,c.scount,c.leader ,c.froms ,c.joinLock ,c.review,c.limitCount ,c.expire,c.qrcodeExpire ,c.qrcodeDays ,c.grades ";
  130. if (groupTypes.IsEmpty() || groupTypes.Contains("teach")) {
  131. //教学班
  132. string teachsql="";
  133. if (!string.IsNullOrWhiteSpace(school) && memberType == 2) {
  134. teachsql= $"SELECT distinct {SummarySql} FROM c join m in c.members where c.type='teach' and m.id='{memberId}' and m.code='{school}' and m.type=2 ";
  135. }
  136. if (memberType == 1)
  137. {
  138. teachsql=$"SELECT distinct {SummarySql} FROM c join m in c.members where c.type='teach' and m.id='{memberId}' and m.type=1 ";
  139. }
  140. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
  141. GetItemQueryIterator<GroupList>(queryText: teachsql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList-{school}") }))
  142. {
  143. HashSet<string> groupName = item.members.Where(x => !string.IsNullOrEmpty(x.groupName)).Select(y => y.groupName).ToHashSet();
  144. groupLists.Add(new GroupListGrp(item, groupName));
  145. }
  146. //个人名单
  147. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).
  148. GetItemQueryIterator<GroupList>(queryText: teachsql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList") }))
  149. {
  150. HashSet<string> groupName = item.members.Where(x => !string.IsNullOrEmpty(x.groupName)).Select(y => y.groupName).ToHashSet();
  151. groupLists.Add(new GroupListGrp(item, groupName));
  152. }
  153. }
  154. if (!string.IsNullOrWhiteSpace(school) && (groupTypes.IsEmpty() || groupTypes.Contains("research")))
  155. {
  156. //教研组
  157. string teachsql = $"SELECT distinct {SummarySql} FROM c join m in c.members where c.type='research' and m.id='{memberId}' and m.type=1 ";
  158. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
  159. GetItemQueryIterator<GroupList>(queryText: teachsql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList-{school}") }))
  160. {
  161. HashSet<string> groupName = item.members.Where(x => !string.IsNullOrEmpty(x.groupName)).Select(y => y.groupName).ToHashSet();
  162. groupLists.Add(new GroupListGrp(item, groupName));
  163. }
  164. }
  165. if (!string.IsNullOrWhiteSpace(school) && (groupTypes.IsEmpty() || groupTypes.Contains("yxtrain")))
  166. {
  167. //研修名单
  168. string teachsql = $"SELECT distinct {SummarySql} FROM c join m in c.members where c.type='yxtrain' and m.id='{memberId}' and m.type=1 ";
  169. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
  170. GetItemQueryIterator<GroupList>(queryText: teachsql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList-{school}") }))
  171. {
  172. HashSet<string> groupName = item.members.Where(x => !string.IsNullOrEmpty(x.groupName)).Select(y => y.groupName).ToHashSet();
  173. groupLists.Add(new GroupListGrp(item, groupName));
  174. }
  175. }
  176. return groupLists;
  177. }
  178. /// <summary>
  179. ///-1状态异常,0加入成功, 1加入学生或醍摩豆ID为空,2重复加入 ,3不允许跨校加入名单, 4表示个人名单未开放加入,状态=5 ,人数已满。状态=6 ,需要审核通过再加入。状态7 二维码设置已经过期
  180. /// </summary>
  181. /// <param name="client"></param>
  182. /// <param name="_stuListNo"></param>
  183. /// <param name="userid"></param>
  184. /// <param name="type"></param>
  185. /// <param name="school"></param>
  186. /// <returns></returns>
  187. public static async Task<(int status, GroupList stuList,Member member)> CodeJoinList(CosmosClient client,AzureRedisFactory _azureRedis, string _stuListNo, string userid, int type, string school,int year,string name ,string picture,string lang )
  188. {
  189. var queryNo = $"SELECT value(c) FROM c where c.no ='{_stuListNo}'";
  190. (int status, GroupList stuList,Member member) data = (-1, null,null);
  191. if (!string.IsNullOrEmpty(school))
  192. {
  193. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupList>(queryText: queryNo,
  194. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{school}") }))
  195. {
  196. data = JoinList(item, userid, type, school,year);
  197. break;
  198. }
  199. }
  200. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<GroupList>(queryText: queryNo,
  201. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList") }))
  202. {
  203. if (item.joinLock == 0) {
  204. //状态=4 表示未开放加入。
  205. return (4, item, null) ;
  206. }
  207. if (item.review ==1)
  208. {
  209. //状态=6 ,人数已满,需要审核通过再加入。
  210. long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  211. if (now>item.qrcodeExpire)
  212. {
  213. //二维码设置已经过期,只有需要审核的时候才检查二维码过期问题,目的是为了未正式加入人员的缓存
  214. return (7, item, null);
  215. }
  216. else
  217. {
  218. GroupWaitingList waitingList = new GroupWaitingList
  219. {
  220. stuListNo=_stuListNo,
  221. userid=userid,
  222. type=type,
  223. school= school,
  224. year = year,
  225. groupId = item.id,
  226. groupScope=item.scope,
  227. name = name,
  228. picture = picture,
  229. lang = lang,
  230. qrcodeExpire=item.qrcodeExpire,
  231. groupName= item.name,
  232. applyTime=now
  233. };
  234. string key = $"GroupList:GroupWaitingList:{item.scope}:{item.id}";
  235. string filed = !string.IsNullOrWhiteSpace(school) ? $"{school}_{userid}" : userid;
  236. await _azureRedis.GetRedisClient(8).HashSetAsync(key, filed, waitingList.ToJsonString());
  237. await _azureRedis.GetRedisClient(8).KeyExpireAsync(key, expiry: DateTimeOffset.FromUnixTimeMilliseconds(item.qrcodeExpire).UtcDateTime);
  238. string stuKey = !string.IsNullOrWhiteSpace(school) ? $"GroupList:StudentWaitinglist:{school}_{userid}" :$"GroupList:StudentWaitinglist:{userid}" ;
  239. string sutFiled = $"{item.scope}:{item.id}";
  240. await _azureRedis.GetRedisClient(8).HashSetAsync(stuKey, sutFiled, waitingList.ToJsonString());
  241. //三十天都不登录,则不需要查看申请清单,30*24=720
  242. await _azureRedis.GetRedisClient(8).KeyExpireAsync(stuKey, new TimeSpan(720 , 0, 0));
  243. return (6, item, null);
  244. }
  245. }
  246. if (item.members!=null &&item.limitCount>0 && item.members.Count>=item.limitCount) {
  247. //状态=5 ,人数已满
  248. return (5, item, null);
  249. }
  250. data = JoinList(item, userid, type, school,year);
  251. //TODO 需要考虑已经通过别的途径加入名单,但是缓存数据仍记录数据的问题。 还要考虑手动加入过的。或者在获取名未加入名单成员的临时缓存数据的时候过滤已经加入的。
  252. break;
  253. }
  254. return data;
  255. }
  256. /// <summary>
  257. /// 加入名单等候列表
  258. /// </summary>
  259. public class GroupWaitingList
  260. {
  261. /// <summary>
  262. ///
  263. /// </summary>
  264. public string stuListNo { get; set; }
  265. public string userid { get; set; }
  266. //学生类型,1醍摩豆id,2 校内账号
  267. public int type { get; set; }
  268. public string school { get; set; }
  269. public int year { get; set; }
  270. public string groupId { get; set; }
  271. public string groupScope { get; set; }
  272. public string name { get; set; }
  273. public string picture { get; set; }
  274. public string lang { get; set; }
  275. public long qrcodeExpire { get; set; }
  276. public string groupName { get; set; }
  277. public long applyTime{ get; set; }
  278. /// <summary>
  279. /// 申请状态,-1 申请中,0 通过,1 拒绝,2 已过期。
  280. /// </summary>
  281. public int status { get; set; } = -1;
  282. }
  283. public static (int status, GroupList stuList, Member member) JoinList(GroupList stuList, string userid, int type, string school,int year)
  284. {
  285. int status = -1;
  286. if (!string.IsNullOrWhiteSpace(stuList.school) && !string.IsNullOrWhiteSpace(school))
  287. {
  288. if (!stuList.school.Equals(school))
  289. {
  290. status = 3;//不允许跨校加入名单
  291. return (status, stuList,null);
  292. }
  293. }
  294. string irs = string.Empty;
  295. List<string> irsOrder = stuList.members.Select(x => x.irs)?.Where(y => !string.IsNullOrEmpty(y) && Regex.IsMatch(y, @"^\d*$")).OrderBy(x => int.Parse(x)).ToList();
  296. if (!irsOrder.Contains("0"))
  297. {
  298. irsOrder.Insert(0, "0");
  299. }
  300. if (irsOrder != null)
  301. {
  302. if (!irsOrder.Contains("0"))
  303. {
  304. irsOrder.Insert(0, "0");
  305. }
  306. }
  307. else { irsOrder = new List<string>() { "0" }; }
  308. for (int i = 0; i < irsOrder.Count; i++)
  309. {
  310. irs = $"{int.Parse(irsOrder[i]) + 1}";
  311. int index = i + 1;
  312. if (index <= irsOrder.Count - 1)
  313. {
  314. if (!irs.Equals(irsOrder[index]))
  315. {
  316. break;
  317. }
  318. }
  319. }
  320. Member member = null;
  321. if (string.IsNullOrEmpty($"{userid}"))
  322. {
  323. //加入学生或醍摩豆ID为空
  324. status = 1;
  325. }
  326. else
  327. {
  328. if (type == 1)
  329. {
  330. member = stuList.members.Find(x => x.type == 1 && x.id.Equals(userid));
  331. if (member != null)
  332. {
  333. //重复加入
  334. status = 2;
  335. }
  336. else
  337. {
  338. //加入成功
  339. status = 0;
  340. member = new Member { id = userid, type = type, irs = irs, no = irs,year=year };
  341. stuList.members.Add(member);
  342. }
  343. }
  344. else if (type == 2)
  345. {
  346. member = stuList.members.Find(x => x.type == 2 && x.id.Equals(userid) && x.code.Equals(school));
  347. if (member != null)
  348. {
  349. //重复加入
  350. status = 2;
  351. }
  352. else
  353. {
  354. status = 0;
  355. member = new Member { id = userid, code = school, type = type, irs = irs, no = irs, year = year };
  356. stuList.members.Add(member);
  357. }
  358. }
  359. }
  360. return (status, stuList, member);
  361. }
  362. public static async Task<GroupList> UpsertList(GroupList list, AzureCosmosFactory _azureCosmos, IConfiguration _configuration, AzureServiceBusFactory _serviceBus)
  363. {
  364. bool isnew = false;
  365. var client = _azureCosmos.GetCosmosClient();
  366. if (string.IsNullOrEmpty(list.id))
  367. {
  368. list.id = Guid.NewGuid().ToString();
  369. isnew = true;
  370. }
  371. string tbname = list.scope.Equals("private") ? "Teacher" : "School";
  372. var tmembers = list.members.Where(x => x.type == 1);
  373. var smembers = list.members.Where(x => x.type == 2);
  374. //处理年级
  375. HashSet<int> grades = new HashSet<int>();
  376. if (smembers.Any()) {
  377. grades = smembers.Where(z => z.year > 2000).Select(z=>z.year).ToHashSet();
  378. }
  379. list.grades = grades;
  380. list.scount = smembers.Count();
  381. list.tcount = tmembers.Count();
  382. //if (smembers.Count() > 0 && smembers.Select(x => x.code).ToHashSet().Count()>=2) {
  383. // //处理移除多个学校的名单,只保留一个学校的。
  384. // if (string.IsNullOrWhiteSpace(list.school))
  385. // {
  386. // HashSet<string> codes = smembers.Select(x => x.code).ToHashSet();
  387. // list.school = codes.First();
  388. // codes.Remove(codes.First());
  389. // list.members.RemoveAll(x => codes.Contains(x.code));
  390. // }
  391. // else {
  392. // list.members.RemoveAll(x => !x.code.Equals(list.school));
  393. // }
  394. //}
  395. if (string.IsNullOrWhiteSpace(list.school) && smembers.Count() >= 1)
  396. {
  397. list.school = smembers.First().code;
  398. }
  399. if (!string.IsNullOrWhiteSpace(list.school) && smembers.Count() == 0 && list.scope.Equals("private"))
  400. {
  401. list.school = null;
  402. }
  403. //学生名单,教研组会触发活动中间表刷新
  404. if (list.type.Equals("teach") || list.type.Equals("research") || list.type.Equals("yxtrain") || list.type.Equals("activity"))
  405. {
  406. GroupChange change = new GroupChange()
  407. {
  408. type = list.type,
  409. listid = list.id,
  410. scope = list.scope,
  411. originCode = list.school,
  412. school = list.school,
  413. creatorId = list.creatorId
  414. };
  415. GroupList oldList = null;
  416. if (!isnew)
  417. {
  418. try
  419. {
  420. oldList = await client.GetContainer(Constant.TEAMModelOS, tbname).ReadItemAsync<GroupList>(list.id, new PartitionKey(list.code));
  421. }
  422. catch (CosmosException)
  423. {
  424. oldList = null;
  425. }
  426. }
  427. if (list.members.IsNotEmpty() && (oldList == null || !oldList.members.IsNotEmpty()))
  428. {
  429. //加入的
  430. var tmdids = list.members.FindAll(x => x.type == 1);
  431. if (tmdids.IsNotEmpty())
  432. {
  433. if (list.type.Equals("research") || list.type.Equals("yxtrain"))
  434. {
  435. change.tchjoin.AddRange(tmdids);
  436. }
  437. else
  438. {
  439. change.tmdjoin.AddRange(tmdids);
  440. }
  441. }
  442. var stuids = list.members.FindAll(x => x.type == 2);
  443. if (stuids.IsNotEmpty())
  444. {
  445. change.stujoin.AddRange(stuids);
  446. }
  447. }
  448. else
  449. {
  450. if (list.members.IsNotEmpty())
  451. {
  452. var tmdids = list.members.FindAll(x => x.type == 1);
  453. var oldtmdids = oldList.members.FindAll(x => x.type == 1);
  454. //取各自的差集
  455. //新=》旧差集,表示新增
  456. var jointmdid = tmdids.Select(x => x.id).Except(oldtmdids.Select(y => y.id)).ToList();
  457. //旧=》新差集,表示离开
  458. var leavetmdid = oldtmdids.Select(x => x.id).Except(tmdids.Select(y => y.id)).ToList();
  459. if (list.type.Equals("research") || list.type.Equals("yxtrain"))
  460. {
  461. change.tchjoin.AddRange(tmdids.Where(x => jointmdid.Exists(y => y.Equals(x.id))));
  462. change.tchleave.AddRange(oldtmdids.Where(x => leavetmdid.Exists(y => y.Equals(x.id))));
  463. }
  464. else
  465. {
  466. change.tmdjoin.AddRange(tmdids.Where(x => jointmdid.Exists(y => y.Equals(x.id))));
  467. change.tmdleave.AddRange(oldtmdids.Where(x => leavetmdid.Exists(y => y.Equals(x.id))));
  468. }
  469. var stuids = list.members.FindAll(x => x.type == 2);
  470. var oldstuids = oldList.members.FindAll(x => x.type == 2);
  471. var joinstudent = stuids.Select(x => (x.id, x.code)).Except(oldstuids.Select(y => (y.id, y.code)), new CompareIdCode()).ToList();
  472. var leavestudent = oldstuids.Select(x => (x.id, x.code)).Except(stuids.Select(y => (y.id, y.code)), new CompareIdCode()).ToList();
  473. change.stujoin.AddRange(stuids.Where(x => joinstudent.Exists(y => y.id.Equals(x.id) && y.code.Equals(x.code))));
  474. change.stuleave.AddRange(oldstuids.Where(x => leavestudent.Exists(y => y.id.Equals(x.id) && y.code.Equals(x.code))));
  475. }
  476. else
  477. {
  478. //离开的
  479. if (oldList != null)
  480. {
  481. var tmdids = oldList.members.FindAll(x => x.type == 1);
  482. if (tmdids.IsNotEmpty())
  483. {
  484. if (list.type.Equals("research") || list.type.Equals("yxtrain"))
  485. {
  486. change.tchleave.AddRange(tmdids);
  487. }
  488. else
  489. {
  490. change.tmdleave.AddRange(tmdids);
  491. }
  492. }
  493. var stuids = oldList.members.FindAll(x => x.type == 2);
  494. if (stuids.IsNotEmpty())
  495. {
  496. change.stuleave.AddRange(stuids);
  497. }
  498. }
  499. }
  500. }
  501. if (change.tmdjoin.Count != 0 || change.tmdleave.Count != 0 || change.stujoin.Count != 0 || change.stuleave.Count != 0
  502. || change.tchjoin.Count != 0 || change.tchleave.Count != 0)
  503. {
  504. var messageChange = new ServiceBusMessage(change.ToJsonString());
  505. messageChange.ApplicationProperties.Add("name", "GroupChange");
  506. var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
  507. await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
  508. }
  509. }
  510. await client.GetContainer(Constant.TEAMModelOS, tbname).UpsertItemAsync(list, new PartitionKey(list.code));
  511. return list;
  512. }
  513. public static async Task<GroupList> CheckListNo(GroupList list, AzureCosmosFactory _azureCosmos, DingDing _dingDing, Option _option)
  514. {
  515. try
  516. {
  517. var client = _azureCosmos.GetCosmosClient();
  518. if (string.IsNullOrEmpty(list.no))
  519. {
  520. list.no = $"{Utils.CreatSaltString(6, "123456789")}";
  521. for (int i = 0; i < 10; i++)
  522. {
  523. List<string> noStus = new List<string>();
  524. var queryNo = $"SELECT c.no FROM c where c.no ='{list.no}'";
  525. if (list.scope.Equals("school"))
  526. {
  527. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: queryNo,
  528. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"{list.code}") }))
  529. {
  530. using var jsonNo = await JsonDocument.ParseAsync(item.ContentStream);
  531. if (jsonNo.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  532. {
  533. var accounts = jsonNo.RootElement.GetProperty("Documents").EnumerateArray();
  534. while (accounts.MoveNext())
  535. {
  536. JsonElement account = accounts.Current;
  537. noStus.Add(account.GetProperty("no").GetString());
  538. }
  539. }
  540. }
  541. }
  542. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryText: queryNo,
  543. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey("GroupList") }))
  544. {
  545. using var jsonNo = await JsonDocument.ParseAsync(item.ContentStream);
  546. if (jsonNo.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  547. {
  548. var accounts = jsonNo.RootElement.GetProperty("Documents").EnumerateArray();
  549. while (accounts.MoveNext())
  550. {
  551. JsonElement account = accounts.Current;
  552. noStus.Add(account.GetProperty("no").GetString());
  553. }
  554. }
  555. }
  556. if (noStus.Count == 0)
  557. {
  558. break;
  559. }
  560. else
  561. {
  562. if (i == 9)
  563. {
  564. string msg = $"OS,{_option.Location},school/course/upsert-list()\n 编号生成异常,重复生成次数超过10次";
  565. await _dingDing.SendBotMsg(msg, GroupNames.醍摩豆服務運維群組);
  566. throw new Exception(msg);
  567. }
  568. else
  569. {
  570. list.no = $"{Utils.CreatSaltString(6, "123456789")}";
  571. }
  572. }
  573. }
  574. }
  575. }
  576. catch (Exception ex)
  577. {
  578. }
  579. return list;
  580. }
  581. /// <summary>
  582. ///根据任意名单id获取名单摘要信息。
  583. /// </summary>
  584. /// <param name="client"></param>
  585. /// <param name="_dingDing"></param>
  586. /// <param name="classes"></param>
  587. /// <param name="school"></param>
  588. /// <param name="SummarySql"></param>
  589. /// <param name="graduate">毕业类型0在校,1毕业 , -1查全部。</param>
  590. /// <returns></returns>
  591. public static async Task<List<GroupListDto>> GetGroupListByListids(CosmosClient client, DingDing _dingDing, List<string> classes, string school,
  592. string SummarySql = " c.id,c.code,c.name,c.no,c.periodId,c.scope,c.school,c.creatorId,c.type,c.year,c.tcount,c.scount,c.leader ,c.froms ,c.joinLock ,c.review,c.limitCount ,c.expire ,c.qrcodeExpire,c.qrcodeDays ,c.grades ", int graduate = -1)
  593. {
  594. List<GroupListDto> groupLists = null;
  595. try
  596. {
  597. classes.RemoveAll(x => x == null);
  598. if (!classes.IsNotEmpty())
  599. {
  600. return null;
  601. }
  602. if (classes.Count == 1 && classes.First().Equals("TeacherAll") && !string.IsNullOrEmpty(school))
  603. {
  604. //默认的教研组
  605. GroupListDto groupList = new GroupListDto
  606. {
  607. id = "TeacherAll",
  608. name = "TeacherAll",
  609. code = $"GroupList-{school}",
  610. school = school,
  611. scope = "school",
  612. type = "yxtrain",
  613. };
  614. groupLists = new List<GroupListDto> { groupList };
  615. }
  616. else
  617. {
  618. Dictionary<string, List<GroupListDto>> groups = new Dictionary<string, List<GroupListDto>>();
  619. //List<Student> students = new List<Student>();
  620. string sql = string.Join(",", classes.Select(x => $"'{x}'"));
  621. if (!string.IsNullOrEmpty(school))
  622. {
  623. List<GroupListDto> schoolList = new List<GroupListDto>();
  624. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupListDto>(queryText: $"select {SummarySql} from c where c.id in ({sql})",
  625. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{school}") }))
  626. {
  627. schoolList.Add(item);
  628. }
  629. if (schoolList.IsNotEmpty())
  630. {
  631. groups.Add("School", schoolList);
  632. }
  633. //取差集,减少二次搜寻
  634. classes = classes.Except(schoolList.Select(y => y.id)).ToList();
  635. if (classes.IsNotEmpty())
  636. {
  637. if (!groupLists.IsNotEmpty())
  638. {
  639. groupLists = new List<GroupListDto>();
  640. }
  641. string insql = string.Join(",", classes.Select(x => $"'{x}'"));
  642. //搜寻没有关联学生的行政班
  643. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupListDto>(queryText:
  644. $"select c.id,c.code,c.name,c.no,c.periodId,c.scope,c.school,c.creatorId,c.type,c.year,c.tcount,c.scount,c.teacher.id as leader ,c.graduate from c where c.id in ({insql})",
  645. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Class-{school}") }))
  646. {
  647. ///行政班(学生搜寻classId动态返回)class
  648. GroupListDto group = new GroupListDto
  649. {
  650. id = item.id,
  651. code = $"GroupList-{school}",
  652. name = item.name,
  653. periodId = item.periodId,
  654. scope = "school",
  655. school = school,
  656. type = "class",
  657. year = item.year,
  658. expire = item.expire,
  659. leader = item.leader,
  660. no = item.no,
  661. pk = "GroupList",
  662. graduate = item.graduate,
  663. grades= new HashSet<int> { item.year }
  664. };
  665. //graduate传入的状态>=0 表示指定状态查询,且传入的状态与数据库的状态一致。
  666. if (graduate >= 0)
  667. {
  668. if (group.graduate == graduate)
  669. {
  670. groupLists.Add(group);
  671. }
  672. }
  673. //全部。
  674. else
  675. {
  676. groupLists.Add(group);
  677. }
  678. // groupLists.Add(group);
  679. }
  680. //取差集,减少二次搜寻
  681. classes = classes.Except(groupLists.Select(y => y.id)).ToList();
  682. }
  683. }
  684. if (classes.IsNotEmpty())
  685. {
  686. List<GroupListDto> privateList = new List<GroupListDto>();
  687. sql = string.Join(",", classes.Select(x => $"'{x}'"));
  688. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<GroupListDto>(queryText: $"select {SummarySql} from c where c.id in ({sql})",
  689. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList") }))
  690. {
  691. privateList.Add(item);
  692. //if (string.IsNullOrWhiteSpace(school))
  693. //{
  694. // privateList.Add(item);
  695. //}
  696. //else
  697. //{
  698. // if (!string.IsNullOrWhiteSpace(item.school))
  699. // {
  700. // if (item.school.Equals(school))
  701. // {
  702. // privateList.Add(item);
  703. // }
  704. // }
  705. // else
  706. // {
  707. // privateList.Add(item);
  708. // }
  709. //}
  710. }
  711. if (privateList.IsNotEmpty())
  712. {
  713. groups.Add("Teacher", privateList);
  714. }
  715. }
  716. if (groups.Count != 0)
  717. {
  718. if (groupLists.IsNotEmpty())
  719. {
  720. groupLists.AddRange(groups.SelectMany(x => x.Value).ToList());
  721. }
  722. else
  723. {
  724. groupLists = groups.SelectMany(x => x.Value).ToList();
  725. }
  726. }
  727. }
  728. } catch (Exception ex ) {
  729. await _dingDing.SendBotMsg($"{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  730. }
  731. return groupLists;
  732. }
  733. /// <summary>
  734. /// 根据任意名单id获取成员信息。rmembers是去重的信息,groups是名单及人员信息,同一个人可能在不同的名单内。
  735. /// </summary>
  736. /// <param name="_coreAPIHttpService"></param>
  737. /// <param name="client"></param>
  738. /// <param name="_dingDing"></param>
  739. /// <param name="classes"></param>
  740. /// <param name="school"></param>
  741. /// <param name="groupids"></param>
  742. /// <param name="graduate">毕业类型0在校,1毕业 , -1查全部。</param>
  743. /// <returns></returns>
  744. public static async Task<(List<RMember>rmembers, List<RGroupList> groups)> GetMemberByListids(CoreAPIHttpService _coreAPIHttpService, CosmosClient client, DingDing _dingDing,
  745. List<string> classes, string school, List<(string, List<string>)> groupids = null, int graduate = -1)
  746. {
  747. List<RMember> members = new List<RMember>();
  748. List<RGroupList> groupLists = new List<RGroupList>();
  749. if (classes != null)
  750. {
  751. classes.RemoveAll(x => x == null);
  752. }
  753. if (classes == null || classes.Count <= 0)
  754. {
  755. return (members, groupLists);
  756. }
  757. if (classes.Count == 1 && classes.First().Equals("TeacherAll") && !string.IsNullOrEmpty(school))
  758. {
  759. //默认的教研组
  760. members = new List<RMember>();
  761. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
  762. GetItemQueryIterator<TmdInfo>(queryText: $"SELECT c.id,c.name,c.picture FROM c ",
  763. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school}") }))
  764. {
  765. RMember member = new RMember
  766. {
  767. id = item.id,
  768. name = item.name,
  769. picture = item.picture,
  770. type = 1,
  771. // nickname=item.name,
  772. };
  773. members.Add(member);
  774. }
  775. RGroupList groupList = new RGroupList
  776. {
  777. id = "TeacherAll",
  778. name = "TeacherAll",
  779. code = $"GroupList-{school}",
  780. school = school,
  781. scope = "school",
  782. type = "TeacherAll",
  783. members = members
  784. };
  785. groupLists = new List<RGroupList> { groupList };
  786. }
  787. else
  788. {
  789. Dictionary<string, List<RGroupList>> groups = new Dictionary<string, List<RGroupList>>();
  790. List<Student> students = new List<Student>();
  791. string sql = string.Join(",", classes.Select(x => $"'{x}'"));
  792. if (!string.IsNullOrEmpty(school))
  793. {
  794. List<RGroupList> schoolList = new List<RGroupList>();
  795. string queryText = $"select value(c) from c where c.id in ({sql})";
  796. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<RGroupList>(queryText: queryText,
  797. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{school}") }))
  798. {
  799. schoolList.Add(item);
  800. }
  801. if (schoolList.IsNotEmpty())
  802. {
  803. groups.Add("School", schoolList);
  804. }
  805. //取差集,减少二次搜寻
  806. classes = classes.Except(schoolList.Select(y => y.id)).ToList();
  807. if (classes.IsNotEmpty())
  808. {
  809. sql = string.Join(",", classes.Select(x => $"'{x}'"));
  810. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryIterator<Student>(queryText: $"select value(c) from c where c.classId in ({sql})",
  811. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Base-{school}") }))
  812. {
  813. //graduate传入的状态>=0 表示指定状态查询,且传入的状态与数据库的状态一致。
  814. if (graduate >= 0)
  815. {
  816. if (item.graduate == graduate)
  817. {
  818. students.Add(item);
  819. }
  820. }
  821. //全部。
  822. else
  823. {
  824. students.Add(item);
  825. }
  826. // students.Add(item);
  827. }
  828. //取差集,减少二次搜寻
  829. classes = classes.Except(students.Select(y => y.classId)).ToList();
  830. }
  831. if (classes.IsNotEmpty())
  832. {
  833. string insql = string.Join(",", classes.Select(x => $"'{x}'"));
  834. //搜寻没有关联学生的行政班
  835. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School")
  836. .GetItemQueryIterator<RGroupList>(queryText: $"select c.id,c.code,c.name,c.no,c.periodId,c.scope,c.school,c.creatorId,c.type,c.year,c.tcount,c.scount,c.teacher.id as leader ,c.graduate from c where c.id in ({insql})",
  837. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Class-{school}") }))
  838. {
  839. ///行政班(学生搜寻classId动态返回)class
  840. List<RMember> smembers = new List<RMember>();
  841. RGroupList group = new RGroupList
  842. {
  843. id = item.id,
  844. code = $"GroupList-{school}",
  845. name = item.name,
  846. periodId = item.periodId,
  847. scope = "school",
  848. school = school,
  849. type = "class",
  850. year = item.year,
  851. expire = item.expire,
  852. members = smembers,
  853. scount = smembers.Count,
  854. pk = "GroupList",
  855. leader = item.leader,
  856. no = item.no,
  857. graduate = item.graduate,
  858. grades= new HashSet<int>() { item.year }
  859. };
  860. //graduate传入的状态>=0 表示指定状态查询,且传入的状态与数据库的状态一致。
  861. if (graduate >= 0)
  862. {
  863. if (group.graduate == graduate)
  864. {
  865. groupLists.Add(group);
  866. }
  867. }
  868. //全部。
  869. else
  870. {
  871. groupLists.Add(group);
  872. }
  873. //groupLists.Add(group);
  874. }
  875. //取差集,减少二次搜寻
  876. classes = classes.Except(groupLists.Select(y => y.id)).ToList();
  877. }
  878. }
  879. if (classes.IsNotEmpty())
  880. {
  881. List<RGroupList> privateList = new List<RGroupList>();
  882. sql = string.Join(",", classes.Select(x => $"'{x}'"));
  883. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<RGroupList>(queryText: $"select value(c) from c where c.id in ({sql})",
  884. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList") }))
  885. {
  886. privateList.Add(item);
  887. //if (string.IsNullOrWhiteSpace(school))
  888. //{
  889. // privateList.Add(item);
  890. //}
  891. //else
  892. //{
  893. // if (!string.IsNullOrWhiteSpace(item.school))
  894. // {
  895. // if (item.school.Equals(school))
  896. // {
  897. // privateList.Add(item);
  898. // }
  899. // }
  900. // else
  901. // {
  902. // privateList.Add(item);
  903. // }
  904. //}
  905. }
  906. if (privateList.IsNotEmpty())
  907. {
  908. groups.Add("Teacher", privateList);
  909. }
  910. }
  911. foreach (var item in groups)
  912. {
  913. var list = item.Value.GroupBy(x => x.type).Select(y => new { key = y.Key, list = y.ToList() });
  914. foreach (var group in list)
  915. {
  916. (List<RGroupList> rgroups, List<RMember> rmembers) = await GetGroupListMemberInfo(_coreAPIHttpService, client, group.key, group.list, item.Key, _dingDing, school,graduate);
  917. members.AddRange(rmembers);
  918. }
  919. }
  920. groupLists.AddRange(groups.SelectMany(x => x.Value).ToList());
  921. if (students.IsNotEmpty())
  922. {
  923. List<string> sqlList = students.Select(x => x.classId).ToList();
  924. string insql = string.Join(",", sqlList.Select(x => $"'{x}'"));
  925. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
  926. GetItemQueryIterator<RGroupList>(queryText: $"select c.id,c.code,c.name,c.no,c.periodId,c.scope,c.school,c.creatorId,c.type,c.year,c.tcount,c.scount,c.teacher.id as leader ,c.graduate from c where c.id in ({insql})",
  927. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Class-{school}") }))
  928. {
  929. ///行政班(学生搜寻classId动态返回)class
  930. List<RMember> smembers = students.Where(x => x.classId.Equals(item.id))
  931. .Select(y => new RMember
  932. {
  933. id = y.id,
  934. code = school,
  935. name = y.name,
  936. //nickname = y.name,
  937. type = 2,
  938. picture = y.picture,
  939. no = y.no,
  940. classId = y.classId,
  941. groupId = y.groupId,
  942. groupName = y.groupName,
  943. irs = y.irs,
  944. year= y.year,
  945. graduate = y.graduate,
  946. gender= y.gender,
  947. }).ToList();
  948. members.AddRange(smembers);
  949. RGroupList group = new RGroupList
  950. {
  951. id = item.id,
  952. code = $"GroupList-{school}",
  953. name = item.name,
  954. periodId = item.periodId,
  955. scope = "school",
  956. school = school,
  957. type = "class",
  958. expire= item.expire,
  959. year = item.year,
  960. members = smembers,
  961. scount = smembers.Count,
  962. no = item.no,
  963. leader = item.leader,
  964. pk = "GroupList",
  965. graduate = item.graduate,
  966. grades= new HashSet<int> { item.year}
  967. };
  968. //graduate传入的状态>=0 表示指定状态查询,且传入的状态与数据库的状态一致。
  969. if (graduate >= 0)
  970. {
  971. if (group.graduate == graduate)
  972. {
  973. groupLists.Add(group);
  974. }
  975. }
  976. //全部。
  977. else
  978. {
  979. groupLists.Add(group);
  980. }
  981. // groupLists.Add(group);
  982. }
  983. //去重。
  984. members = members.FindAll(x => x.type == 2).Where((x, i) => members.FindAll(x => x.type == 2).FindIndex(n => n.id.Equals(x.id) && n.code.Equals(x.code)) == i).ToList();
  985. }
  986. }
  987. if (groupids.IsNotEmpty())
  988. {
  989. List<RMember> rmembers = new List<RMember>();
  990. groupLists.ForEach(y => {
  991. (string id, List<string> grpids) = groupids.Find(x => x.Item1.Equals(y.id));
  992. var gpmember = y.members.FindAll(x => !string.IsNullOrEmpty(x.groupName) && grpids.Contains(x.groupName));
  993. if (grpids.Contains("default"))
  994. {
  995. var gpmemberdft = y.members.FindAll(x => string.IsNullOrWhiteSpace(x.groupName));
  996. if (gpmember.IsNotEmpty())
  997. {
  998. gpmember.AddRange(gpmemberdft);
  999. }
  1000. else
  1001. {
  1002. gpmember = gpmemberdft;
  1003. }
  1004. }
  1005. y.members = gpmember;
  1006. });
  1007. var gpgpmembers = groupLists.SelectMany(x => x.members).ToList();
  1008. List<RMember> tmdids = gpgpmembers.FindAll(x => x.type == 1).Where((x, i) => gpgpmembers.FindAll(x => x.type == 1).FindIndex(n => n.id.Equals(x.id)) == i).ToList();
  1009. List<RMember> students = gpgpmembers.FindAll(x => x.type == 2).Where((x, i) => gpgpmembers.FindAll(x => x.type == 2).FindIndex(n => n.id.Equals(x.id) && n.code.Equals(x.code)) == i).ToList();
  1010. if (tmdids.IsNotEmpty())
  1011. {
  1012. rmembers.AddRange(tmdids);
  1013. }
  1014. if (students.IsNotEmpty())
  1015. {
  1016. rmembers.AddRange(students);
  1017. }
  1018. return (rmembers, groupLists);
  1019. }
  1020. else
  1021. {
  1022. return (members, groupLists);
  1023. }
  1024. }
  1025. /// <summary>
  1026. /// 根据名单类型获取名单及成员信息。
  1027. /// </summary>
  1028. /// <param name="_coreAPIHttpService"></param>
  1029. /// <param name="client"></param>
  1030. /// <param name="type"></param>
  1031. /// <param name="scopes"></param>
  1032. /// <param name="school"></param>
  1033. /// <param name="_dingDing"></param>
  1034. /// <param name="graduate">毕业类型0在校,1毕业 , -1查全部。</param>
  1035. /// <returns></returns>
  1036. public static async Task<List<RGroupList>> GetGroupListMemberByType(CoreAPIHttpService _coreAPIHttpService, CosmosClient client, string type, List<string> scopes, string school, DingDing _dingDing, int graduate = -1)
  1037. {
  1038. StringBuilder sql = new StringBuilder($"SELECT distinct value(c) FROM c where c.type='{type}'");
  1039. Dictionary<string, List<RGroupList>> groups = new Dictionary<string, List<RGroupList>>();
  1040. if (scopes.Contains("school"))
  1041. {
  1042. if (!string.IsNullOrEmpty(school))
  1043. {
  1044. List<RGroupList> groupLists = new List<RGroupList>();
  1045. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<RGroupList>(queryText: sql.ToString(),
  1046. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{school}") }))
  1047. {
  1048. groupLists.Add(item);
  1049. }
  1050. groups.Add("School", groupLists);
  1051. }
  1052. }
  1053. else if (scopes.Contains("private"))
  1054. {
  1055. List<RGroupList> groupLists = new List<RGroupList>();
  1056. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<RGroupList>(queryText: sql.ToString(),
  1057. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList") }))
  1058. {
  1059. groupLists.Add(item);
  1060. //if (string.IsNullOrWhiteSpace(school))
  1061. //{
  1062. // groupLists.Add(item);
  1063. //}
  1064. //else
  1065. //{
  1066. // if (!string.IsNullOrWhiteSpace(item.school))
  1067. // {
  1068. // if (item.school.Equals(school))
  1069. // {
  1070. // groupLists.Add(item);
  1071. // }
  1072. // }
  1073. // else {
  1074. // groupLists.Add(item);
  1075. // }
  1076. //}
  1077. }
  1078. groups.Add("Teacher", groupLists);
  1079. }
  1080. foreach (var item in groups)
  1081. {
  1082. var list = item.Value.GroupBy(x => x.type).Select(y => new { key = y.Key, list = y.ToList() });
  1083. foreach (var group in list)
  1084. {
  1085. (List<RGroupList> rgroups, List<RMember> rmembers) = await GetGroupListMemberInfo(_coreAPIHttpService, client, group.key, group.list, item.Key, _dingDing, school,graduate);
  1086. }
  1087. }
  1088. var lists = groups.SelectMany(x => x.Value).ToList();
  1089. return lists;
  1090. }
  1091. /// <summary>
  1092. /// 根据名单类型,名单分组信息获取成员信息, rmembers是去重的信息,groups是名单及人员信息,同一个人可能在不同的名单内。
  1093. /// </summary>
  1094. /// <param name="_coreAPIHttpService"></param>
  1095. /// <param name="client"></param>
  1096. /// <param name="type"></param>
  1097. /// <param name="groups"></param>
  1098. /// <param name="groupTbname"></param>
  1099. /// <param name="_dingDing"></param>
  1100. /// <param name="school"></param>
  1101. /// <param name="graduate">毕业类型0在校,1毕业 , -1查全部。</param>
  1102. /// <returns></returns>
  1103. public static async Task<(List<RGroupList> groups, List<RMember> members)> GetGroupListMemberInfo(CoreAPIHttpService _coreAPIHttpService, CosmosClient client,
  1104. string type, List<RGroupList> groups, string groupTbname, DingDing _dingDing, string school, int graduate = -1)
  1105. {
  1106. try
  1107. {
  1108. HashSet<RGroupList> changes = new HashSet<RGroupList>();
  1109. var members = groups.SelectMany(y => y.members).ToList();
  1110. //去重
  1111. List<RMember> tmdids = members.FindAll(x => x.type == 1).Where((x, i) => members.FindAll(x => x.type == 1).FindIndex(n => n.id.Equals(x.id)) == i).ToList();
  1112. List<RMember> students = members.FindAll(x => x.type == 2).Where((x, i) => members.FindAll(x => x.type == 2).FindIndex(n => n.id.Equals(x.id) && n.code.Equals(x.code)) == i).ToList();
  1113. var stu = students.GroupBy(x => x.code).Select(y => new { key = y.Key, list = y.ToList() });
  1114. List<Student> studentsData = new List<Student>();
  1115. if (stu != null)
  1116. {
  1117. foreach (var item in stu)
  1118. {
  1119. var ids = item.list.Select(x => x.id).ToList();
  1120. if (ids.IsNotEmpty())
  1121. {
  1122. StringBuilder stuSql = new StringBuilder($"SELECT distinct c.name,c.id,c.code,c.picture,c.no,c.irs,c.classId ,c.graduate,c.year FROM c ");
  1123. string insql = string.Join(",", ids.Select(x => $"'{x}'"));
  1124. stuSql.Append($"where c.id in ({insql})");
  1125. await foreach (var student in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryIterator<Student>(queryText: stuSql.ToString(),
  1126. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{item.key}") }))
  1127. {
  1128. student.schoolId = item.key;
  1129. studentsData.Add(student);
  1130. }
  1131. }
  1132. }
  1133. var unexist_student = students.Select(x => (x.id, x.code)).Except(studentsData.Select(y => (y.id, y.schoolId)), new CompareIdCode()).ToList();
  1134. groups.ForEach(x =>
  1135. {
  1136. int item = x.members.RemoveAll(y => y.type == 2 && unexist_student.Exists(x => x.id.Equals(y.id) && x.Item2.Equals(y.code)));
  1137. if (item > 0)
  1138. {
  1139. changes.Add(x);
  1140. }
  1141. });
  1142. }
  1143. List<TmdUser> tmdsData = new List<TmdUser>();
  1144. if (tmdids.IsNotEmpty())
  1145. {
  1146. string memberTbname = "";
  1147. if ($"{type}".Equals("activity"))
  1148. {
  1149. var mbers = groups.SelectMany(x => x.members).Where(z => !string.IsNullOrEmpty(z.code));
  1150. var schoolTeachers = mbers.GroupBy(y => y.code).Select(m => new { key = m.Key, list = m.ToList() });
  1151. foreach (var schoolTeacher in schoolTeachers)
  1152. {
  1153. StringBuilder tmdidSql = new StringBuilder($"SELECT distinct c.name,c.id,c.picture FROM c ");
  1154. string insql = string.Join(",", schoolTeacher.list.Select(x => $"'{x.id}'"));
  1155. tmdidSql.Append($" where c.id in ({insql})");
  1156. await foreach (var tmd in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<TmdUser>(queryText: tmdidSql.ToString(),
  1157. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{schoolTeacher.key}") }))
  1158. {
  1159. tmdsData.Add(tmd);
  1160. }
  1161. }
  1162. var unexist_teachers = mbers.Select(x => (x.id, x.code)).Except(tmdsData.Select(y => (y.id, y.code)), new CompareIdCode()).ToList();
  1163. groups.ForEach(x =>
  1164. {
  1165. int item = x.members.RemoveAll(y => y.type == 2 && unexist_teachers.Exists(x => x.id.Equals(y.id) && x.Item2.Equals(y.code)));
  1166. if (item > 0)
  1167. {
  1168. changes.Add(x);
  1169. }
  1170. });
  1171. }
  1172. else
  1173. {
  1174. //处理研修名单,如果是学校老师的,则需要检查SchoolTeacher
  1175. //处理 学校教研组,学校管理人员,学校任课教师,学校研修名单。
  1176. if (!string.IsNullOrEmpty(school) && ($"{type}".Equals("yxtrain") || $"{type}".Equals("research") || $"{type}".Equals("manage") || $"{type}".Equals("subject")))
  1177. {
  1178. StringBuilder tmdidSql = new StringBuilder($"SELECT distinct c.name,c.id,c.picture FROM c ");
  1179. string insql = string.Join(",", tmdids.Select(x => $"'{x.id}'"));
  1180. tmdidSql.Append($" where c.id in ({insql})");
  1181. await foreach (var tmd in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<TmdUser>(queryText: tmdidSql.ToString(),
  1182. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school}") }))
  1183. {
  1184. tmdsData.Add(tmd);
  1185. }
  1186. }
  1187. else
  1188. {
  1189. {
  1190. StringBuilder tmdidSql = new StringBuilder($"SELECT distinct c.name,c.id,c.picture FROM c ");
  1191. string insql = string.Join(",", tmdids.Select(x => $"'{x.id}'"));
  1192. tmdidSql.Append($" where c.id in ({insql})");
  1193. memberTbname = "Teacher";
  1194. await foreach (var tmd in client.GetContainer(Constant.TEAMModelOS, memberTbname).GetItemQueryIterator<TmdUser>(queryText: tmdidSql.ToString(),
  1195. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
  1196. {
  1197. tmdsData.Add(tmd);
  1198. }
  1199. }
  1200. {
  1201. //取差集,减少二次搜寻
  1202. var tmdidexp = tmdids.Select(x => x.id).Except(tmdsData.Select(y => y.id)).ToList();
  1203. if (tmdidexp.IsNotEmpty())
  1204. {
  1205. StringBuilder tmdidSql = new StringBuilder($"SELECT distinct c.name,c.id,c.picture FROM c ");
  1206. string insql = string.Join(",", tmdidexp.Select(x => $"'{x}'"));
  1207. tmdidSql.Append($" where c.id in ({insql})");
  1208. memberTbname = "Student";
  1209. await foreach (var tmd in client.GetContainer(Constant.TEAMModelOS, memberTbname).GetItemQueryIterator<TmdUser>(queryText: tmdidSql.ToString(),
  1210. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
  1211. {
  1212. tmdsData.Add(tmd);
  1213. }
  1214. }
  1215. }
  1216. }
  1217. tmdsData = tmdsData.Where((x, i) => tmdsData.FindIndex(n => n.id.Equals(x.id)) == i).ToList();
  1218. var unexist_tmdid = tmdids.Select(x => x.id).Except(tmdsData.Select(y => y.id)).ToList();
  1219. groups.ForEach(x =>
  1220. {
  1221. int item = x.members.RemoveAll(y => unexist_tmdid.Contains(y.id) && y.type == 1);
  1222. if (item > 0)
  1223. {
  1224. changes.Add(x);
  1225. }
  1226. });
  1227. }
  1228. }
  1229. if (tmdids.IsNotEmpty() && _coreAPIHttpService.check) {
  1230. ///获取真实的名称 ,大于50则不处理
  1231. if (tmdids.Count < 60)
  1232. {
  1233. var content = new StringContent(tmdids.Select(x => x.id).ToHashSet().ToJsonString(), Encoding.UTF8, "application/json");
  1234. string json = null;
  1235. try
  1236. {
  1237. json = await _coreAPIHttpService.GetUserInfos(content);
  1238. if (!string.IsNullOrWhiteSpace(json))
  1239. {
  1240. List<TmdInfo> tmdInfos = json.ToObject<List<TmdInfo>>();
  1241. if (tmdInfos.IsNotEmpty())
  1242. {
  1243. tmdsData.ForEach(y =>
  1244. {
  1245. var tmd = tmdInfos.Find(x => x.id.Equals(y.id));
  1246. if (tmd != null)
  1247. {
  1248. y.name = tmd?.name;
  1249. y.picture = tmd?.picture;
  1250. }
  1251. else
  1252. {
  1253. groups.ForEach(x =>
  1254. {
  1255. int item = x.members.RemoveAll(z => z.id.Equals(y.id) && z.type == 1);
  1256. if (item > 0)
  1257. {
  1258. changes.Add(x);
  1259. }
  1260. });
  1261. }
  1262. });
  1263. }
  1264. }
  1265. }
  1266. catch (Exception ex)
  1267. {
  1268. await _dingDing.SendBotMsg($"{_coreAPIHttpService.options.location}用户转换失败:{_coreAPIHttpService.options.coreUrl}{json}\n {ex.Message}\n{ex.StackTrace}{tmdids.Select(x => x.id).ToJsonString()}", GroupNames.醍摩豆服務運維群組);
  1269. }
  1270. }
  1271. }
  1272. tmdids.ForEach(x =>
  1273. {
  1274. var user = tmdsData.Find(y => y.id.Equals(x.id));
  1275. x.name = user?.name;
  1276. // x.nickname = string.IsNullOrWhiteSpace(x.nickname) ? user?.name : x.nickname;
  1277. x.picture = user?.picture;
  1278. });
  1279. students.ForEach(x =>
  1280. {
  1281. var student = studentsData.Find(y => y.id.Equals(x.id) && y.schoolId.Equals(x.code));
  1282. if (student != null)
  1283. {
  1284. x.name = student?.name;
  1285. // x.nickname = string.IsNullOrWhiteSpace(x.nickname) ? student?.name:x.nickname;
  1286. x.picture = student?.picture;
  1287. x.classId = student?.classId;
  1288. x.graduate = student.graduate;
  1289. x.year = student.year;
  1290. x.gender= student.gender;
  1291. }
  1292. });
  1293. var mbs = tmdids;
  1294. mbs.AddRange(students);
  1295. if (changes.Count > 0 && !string.IsNullOrEmpty(groupTbname))
  1296. {
  1297. foreach (var change in changes)
  1298. {
  1299. change.tcount = change.members.Where(x => x.type == 1).Count();
  1300. change.scount = change.members.Where(x => x.type == 2).Count();
  1301. GroupList group = change.ToJsonString().ToObject<GroupList>();
  1302. await client.GetContainer(Constant.TEAMModelOS, groupTbname).ReplaceItemAsync(group, group.id, new PartitionKey(group.code));
  1303. }
  1304. }
  1305. groups.ForEach(x =>
  1306. {
  1307. x.members.ForEach(y =>
  1308. {
  1309. if (y.type == 1)
  1310. {
  1311. var tmd = tmdids.Find(t => t.id.Equals(y.id));
  1312. y.name = tmd?.name;
  1313. //y.nickname = string.IsNullOrWhiteSpace(y.nickname) ? tmd?.nickname : y.nickname;
  1314. y.picture = tmd?.picture;
  1315. }
  1316. if (y.type == 2)
  1317. {
  1318. var student = students.Find(t => t.id.Equals(y.id) && t.code.Equals(y.code));
  1319. if (student != null)
  1320. {
  1321. y.name = student?.name;
  1322. // y.nickname = string.IsNullOrWhiteSpace(y.nickname) ? student?.nickname : y.nickname;
  1323. y.picture = student?.picture;
  1324. y.classId = student?.classId;
  1325. y.graduate = student.graduate;
  1326. y.gender = student.gender;
  1327. y.year = student.year;
  1328. y.gender = student.gender;
  1329. x.grades.Add(student.year);
  1330. }
  1331. }
  1332. });
  1333. if (!x.type.Equals("class")) {
  1334. var yearc = x.members.Where(z => z.type == 2).GroupBy(g => g.year).Select(k => new { key = k.Key, count = k.Count() }).OrderByDescending(z => z.count);
  1335. if (yearc.Any())
  1336. {
  1337. //有一半的人是同一个班的,则以
  1338. if (yearc.First().count * 1.0 / x.members.Count > 0.51)
  1339. {
  1340. x.year = yearc.First().key;
  1341. }
  1342. }
  1343. }
  1344. });
  1345. HashSet<string> schoolCodes = groups.SelectMany(x => x.members).Where(y => !string.IsNullOrEmpty(y.code)).Select(z => z.code).ToHashSet();
  1346. if (schoolCodes != null && schoolCodes.Count > 0)
  1347. {
  1348. List<School> schools = new List<School>();
  1349. string insql = $"select c.name,c.id from c where c.id in ({string.Join(",", schoolCodes.Select(x => $"'{x}'"))})";
  1350. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<School>(queryText: insql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
  1351. {
  1352. schools.Add(item);
  1353. }
  1354. if (schools.IsNotEmpty())
  1355. {
  1356. groups.SelectMany(x => x.members).Where(y => !string.IsNullOrEmpty(y.code)).ToList().ForEach(z => {
  1357. var school = schools.Find(j => j.id.Equals(z.code));
  1358. z.schoolName = school?.name;
  1359. });
  1360. }
  1361. }
  1362. if (graduate >= 0)
  1363. {
  1364. groups= groups.FindAll(x => x.graduate == graduate);
  1365. if (groups != null) {
  1366. groups.ForEach(x =>
  1367. {
  1368. x.members.RemoveAll(y => y.graduate != graduate);
  1369. });
  1370. }
  1371. mbs.RemoveAll(z => z.graduate != graduate);
  1372. return (groups, mbs);
  1373. }
  1374. //直接返回
  1375. else {
  1376. return (groups, mbs);
  1377. }
  1378. }
  1379. catch (Exception ex)
  1380. {
  1381. await _dingDing.SendBotMsg($"{_coreAPIHttpService.options.location},GetGroupListMemberInfo()\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
  1382. }
  1383. return (null, null);
  1384. }
  1385. /// <summary>
  1386. /// 处理活动结束的
  1387. /// </summary>
  1388. /// <param name="_coreAPIHttpService"></param>
  1389. /// <param name="cosmosClient">数据库</param>
  1390. /// <param name="_dingDing">钉钉消息</param>
  1391. /// <param name="school">学校编码</param>
  1392. /// <param name="classes">行政班</param>
  1393. /// <param name="stuLists">学生</param>
  1394. /// <param name="tchLists">教师</param>
  1395. /// <param name="_groupLists">分组</param>
  1396. /// <param name="graduate">毕业类型0在校,1毕业 , -1查全部。</param>
  1397. /// <returns></returns>
  1398. public static async Task<List<FMember>> GetFinishMemberInfo(CoreAPIHttpService _coreAPIHttpService, CosmosClient cosmosClient, DingDing _dingDing, string school, List<string> classes, List<string> stuLists, List<string> tchLists, List<(string, List<string>)> _groupLists = null, int graduate = -1)
  1399. {
  1400. List<FMember> fMembers = new();
  1401. if (classes != null && classes.Count > 0)
  1402. {
  1403. (List<RMember> staffList, List<RGroupList> classInfos) = await GetMemberByListids(_coreAPIHttpService, cosmosClient, _dingDing, classes, school);
  1404. staffList.ForEach(x => fMembers.Add(new FMember() { id = x.id, code = school, type = 1, }));
  1405. }
  1406. if (stuLists != null && stuLists.Count > 0)
  1407. {
  1408. (List<RMember> staffList, List<RGroupList> classInfos) = await GetMemberByListids(_coreAPIHttpService, cosmosClient, _dingDing, stuLists, school);
  1409. staffList.ForEach(x => fMembers.Add(new FMember() { id = x.id, code = school, type = 2 }));
  1410. }
  1411. /* if (tchLists != null && tchLists.Count > 0)
  1412. {
  1413. (List<RMember> staffList, List<RGroupList> classInfos) = await GetMemberByListids(_coreAPIHttpService, cosmosClient, _dingDing, tchLists, school);
  1414. staffList.ForEach(x => fMembers.Add(new FMember() { id = x.id, code = school, type = 2 }));
  1415. }*/
  1416. if (tchLists != null && tchLists.Count > 0)
  1417. {
  1418. (List<RMember> staffList, List<RGroupList> groupLists1) = await GetMemberByListids(_coreAPIHttpService, cosmosClient, _dingDing, tchLists, school, _groupLists);
  1419. staffList.ForEach(x => fMembers.Add(new FMember() { id = x.id, code = school, type = 2 }));
  1420. }
  1421. return fMembers;
  1422. }
  1423. }
  1424. public class CompareIdCode : IEqualityComparer<(string id, string code)>
  1425. {
  1426. public bool Equals((string id, string code) x, (string id, string code) y)
  1427. {
  1428. return x.id.Equals(y.id) && x.code.Equals(y.code);
  1429. }
  1430. public int GetHashCode((string id, string code) obj)
  1431. {
  1432. if (obj.id != null && obj.code != null)
  1433. {
  1434. return 1;
  1435. }
  1436. else
  1437. {
  1438. return 0;
  1439. }
  1440. }
  1441. }
  1442. }