StatisticsService.cs 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. using Azure.Cosmos;
  2. using Azure.Messaging.ServiceBus;
  3. using DocumentFormat.OpenXml.Spreadsheet;
  4. using HTEXLib.COMM.Helpers;
  5. using Microsoft.AspNetCore.Http;
  6. using Microsoft.Extensions.Configuration;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using TEAMModelOS.SDK.DI;
  13. using TEAMModelOS.SDK.Extension;
  14. using TEAMModelOS.SDK.Models;
  15. using TEAMModelOS.SDK.Models.Service;
  16. namespace TEAMModelOS.SDK
  17. {
  18. public static class StatisticsService
  19. {
  20. /// <summary>
  21. /// 教师能力点操作
  22. /// </summary>
  23. public const string TeacherAbility = "TeacherAbility";
  24. /// <summary>
  25. /// 课堂实录
  26. /// </summary>
  27. public const string TeacherClass = "TeacherClass";
  28. /// <summary>
  29. /// 线下研修
  30. /// </summary>
  31. public const string OfflineRecord = "OfflineRecord";
  32. /// <summary>
  33. /// 教师投票活动
  34. /// </summary>
  35. public const string TeacherVote = "TeacherVote";
  36. /// <summary>
  37. /// 教师作业活动
  38. /// </summary>
  39. public const string TeacherHomework = "TeacherHomework";
  40. /// <summary>
  41. /// 教师问卷活动
  42. /// </summary>
  43. public const string TeacherSurvey = "TeacherSurvey";
  44. /// <summary>
  45. /// 教师评测活动
  46. /// </summary>
  47. public const string TeacherExamLite = "TeacherExamLite";
  48. public class TeacherTrainChangeMsg {
  49. public string areaId { get; set; }
  50. public List<TeacherTrainChangeMsgSchoolTeachers> schools { get; set; } = new List<TeacherTrainChangeMsgSchoolTeachers>();
  51. }
  52. public class TeacherTrainChangeMsgSchoolTeachers {
  53. public string school { get; set; }
  54. public List<string> teachers { get; set; } = new List<string>();
  55. }
  56. public static async Task DoChange(TeacherTrainChange change, AzureCosmosFactory _azureCosmos)
  57. {
  58. if (change.tmdids.IsNotEmpty() && change.update.Count() > 0 && !string.IsNullOrEmpty(change.school))
  59. {
  60. var client = _azureCosmos.GetCosmosClient();
  61. string insql = $"where c.id in ({string.Join(",", change.tmdids.Select(x => $"'{x}'"))})";
  62. string selsql = $"select value(c) from c {insql} ";
  63. List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
  64. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<TeacherTrain>(queryText: selsql,
  65. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{change.school}") }))
  66. {
  67. teacherTrains.Add(item);
  68. }
  69. List<Task<ItemResponse<TeacherTrain>>> task = new List<Task<ItemResponse<TeacherTrain>>>();
  70. teacherTrains.ForEach(x => {
  71. change.update.ToList().ForEach(u => {
  72. x.update.Add(u);
  73. });
  74. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<TeacherTrain>(x, x.id, new PartitionKey($"TeacherTrain-{change.school}")));
  75. });
  76. await task.TaskPage(5);
  77. var unchange = change.tmdids.Except(teacherTrains.Select(x => x.id));
  78. if (unchange != null)
  79. {
  80. task.Clear();
  81. unchange.ToList().ForEach(x => {
  82. TeacherTrain teacherTrain = new TeacherTrain
  83. {
  84. pk = "TeacherTrain",
  85. id = x,
  86. code = $"TeacherTrain-{change.school}",
  87. tmdid = x,
  88. school = change.school,
  89. update = new HashSet<string> { StatisticsService.TeacherAbility,
  90. StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
  91. };
  92. change.update.ToList().ForEach(u => {
  93. teacherTrain.update.Add(u);
  94. });
  95. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<TeacherTrain>(teacherTrain, new PartitionKey($"TeacherTrain-{change.school}")));
  96. });
  97. await task.TaskPage(5);
  98. }
  99. }
  100. }
  101. public static async Task SendServiceBus((string standard, List<string> tmdids, string school, List<string> update, int statistics) list, IConfiguration _configuration, AzureServiceBusFactory _serviceBus, CosmosClient client)
  102. {
  103. if (list.tmdids.IsNotEmpty() && list.update.IsNotEmpty())
  104. {
  105. string insql = $"where c.id in ({string.Join(",", list.tmdids.Select(x => $"'{x}'"))})";
  106. string selsql = $"select value(c) from c {insql} ";
  107. List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
  108. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<TeacherTrain>(queryText: selsql,
  109. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{list.school}") }))
  110. {
  111. teacherTrains.Add(item);
  112. }
  113. List<Task<ItemResponse<TeacherTrain>>> task = new List<Task<ItemResponse<TeacherTrain>>>();
  114. teacherTrains.ForEach(x => {
  115. list.update.ForEach(u => {
  116. x.update.Add(u);
  117. });
  118. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<TeacherTrain>(x, x.id, new PartitionKey($"TeacherTrain-{list.school}")));
  119. });
  120. await task.TaskPage(5);
  121. var unchange = list.tmdids.Except(teacherTrains.Select(x => x.id));
  122. if (unchange != null)
  123. {
  124. task.Clear();
  125. unchange.ToList().ForEach(x => {
  126. TeacherTrain teacherTrain = new TeacherTrain
  127. {
  128. pk = "TeacherTrain",
  129. id = x,
  130. code = $"TeacherTrain-{list.school}",
  131. tmdid = x,
  132. school = list.school,
  133. update = new HashSet<string> { StatisticsService.TeacherAbility,
  134. StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
  135. };
  136. list.update.ForEach(u => {
  137. teacherTrain.update.Add(u);
  138. });
  139. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<TeacherTrain>(teacherTrain, new PartitionKey($"TeacherTrain-{list.school}")));
  140. });
  141. await task.TaskPage(1);
  142. }
  143. }
  144. }
  145. public static async Task GetAreaAndAreaSetting(string schoolId, string _standard, CosmosClient client, HttpContext httpContext)
  146. {
  147. School school = null;
  148. AreaSetting setting = null;
  149. string standard = "";
  150. if (string.IsNullOrEmpty(_standard))
  151. {
  152. standard = _standard;
  153. }
  154. else if (!string.IsNullOrEmpty(schoolId))
  155. {
  156. //优先找校级
  157. setting = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<AreaSetting>(schoolId, new PartitionKey("AreaSetting"));
  158. //优先找校级
  159. school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(schoolId, new PartitionKey("Base"));
  160. }
  161. }
  162. //public static async Task<List<(List<TeacherTrain> trains, List<RGroupList> yxtrain)>> StatisticsArea(CoreAPIHttpService _coreAPIHttpService, AreaSetting setting, Area area, CosmosClient client, DingDing _dingDing, HashSet<string> updates)
  163. //{
  164. // List<(List<TeacherTrain> trains, List<RGroupList> yxtrain)> teacherTrains = new List<(List<TeacherTrain> trains, List<RGroupList> yxtrain)>();
  165. // List<School> schools = new List<School>();
  166. // await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School")
  167. // .GetItemQueryIterator<School>(queryText: $"select value(c) from c where c.areaId='{area.id}' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
  168. // {
  169. // schools.Add(item);
  170. // }
  171. // await foreach ((List<TeacherTrain> trains, List<RGroupList> yxtrain) tarain in GetStatisticsSchool(_coreAPIHttpService, schools, setting, area, client, _dingDing, updates))
  172. // {
  173. // teacherTrains.Add(tarain);
  174. // }
  175. // return teacherTrains;
  176. //}
  177. //private static async IAsyncEnumerable<(List<TeacherTrain> trains, List<RGroupList> yxtrain)> GetStatisticsSchool(CoreAPIHttpService _coreAPIHttpService,List<School> schools, AreaSetting setting, Area area, CosmosClient client, DingDing _dingDing, HashSet<string> updates)
  178. //{
  179. // foreach (var school in schools)
  180. // {
  181. // yield return await StatisticsSchool( _coreAPIHttpService,school.id, setting, area, client, _dingDing, updates);
  182. // }
  183. //}
  184. public static async Task<(List<TeacherTrain> trains, List<RGroupList> yxtrain, List<TeacherTrain> updateTeacherTrains)> StatisticsSchoolQuik(CoreAPIHttpService _coreAPIHttpService, string school, AreaSetting setting, Area area, CosmosClient client, DingDing _dingDing, HashSet<string> updates)
  185. {
  186. _coreAPIHttpService.check = false;
  187. List<RGroupList> yxtrain = await GroupListService.GetGroupListMemberByType(_coreAPIHttpService, client, "yxtrain", new List<string> { "school" }, $"{school}", _dingDing);
  188. List<TeacherTrain> trains = new List<TeacherTrain>();
  189. var members = yxtrain.SelectMany(x => x.members).ToList();
  190. if (members.Count <= 0)
  191. {
  192. return (trains, yxtrain, null) ;
  193. }
  194. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher")
  195. .GetItemQueryIterator<TeacherTrain>(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{school}") }))
  196. {
  197. trains.Add(item);
  198. }
  199. if (updates != null)
  200. {
  201. foreach (var up in updates)
  202. {
  203. trains.ForEach(x => x.update.Add(up));
  204. }
  205. }
  206. var update = trains.FindAll(x => x.update.Count() > 0);
  207. var noupdate = trains.FindAll(x => x.update.Count() <= 0);
  208. var unStatistics = members.Select(x => x.id).Except(trains.Select(x => x.id));
  209. List<TeacherTrain> updateTeacherTrains = new List<TeacherTrain>();
  210. List<TeacherTrain> returnTrains = new List<TeacherTrain>();
  211. if (update.IsNotEmpty())
  212. {
  213. updateTeacherTrains.AddRange(update);
  214. }
  215. if (unStatistics != null)
  216. {
  217. foreach (string x in unStatistics)
  218. {
  219. var member = members.Find(y => y.id.Equals(x));
  220. updateTeacherTrains.Add(new TeacherTrain
  221. {
  222. pk = "TeacherTrain",
  223. id = x,
  224. code = $"TeacherTrain-{school}",
  225. tmdid = x,
  226. nickname = member.nickname,
  227. name = member.name,
  228. picture = member.picture,
  229. school = school,
  230. groupName=member.groupName,
  231. update = new HashSet<string> { TeacherAbility, TeacherClass, OfflineRecord }
  232. });
  233. }
  234. }
  235. //List<Study> studies = new List<Study>();
  236. //await foreach (var item in client.GetContainer("TEAMModelOS", "Common")
  237. // .GetItemQueryIterator<Study>(queryText: $"select value(c) from c where c.owner<>'area' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Study-{school}") }))
  238. //{
  239. // studies.Add(item);
  240. //}
  241. returnTrains .AddRange(updateTeacherTrains) ;
  242. // await GetStatisticsTeacher(teacherTrains, setting, area, client, studies);
  243. //await foreach (var tarain in GetStatisticsTeacher(teacherTrains, setting, area, client))
  244. //{
  245. // returnTrains.Add(tarain);
  246. //}
  247. if (noupdate.IsNotEmpty())
  248. {
  249. returnTrains.AddRange(noupdate);
  250. }
  251. //移除不在研修名单的人员
  252. returnTrains.RemoveAll(x => !members.Select(y => y.id).Contains(x.id));
  253. returnTrains.ForEach(x => {
  254. var mbm = members.Find(y => y.id.Equals(x.id));
  255. if (mbm != null)
  256. {
  257. x.name = !string.IsNullOrWhiteSpace(x.name) ? x.name : mbm?.name;
  258. x.nickname = mbm?.nickname;
  259. x.picture = mbm?.picture;
  260. x.groupName = mbm?.groupName;
  261. }
  262. });
  263. return (returnTrains, yxtrain, updateTeacherTrains);
  264. }
  265. public static async Task<(List<TeacherTrain> trains, List<RGroupList> yxtrain)> StatisticsSchool(CoreAPIHttpService _coreAPIHttpService,string school, AreaSetting setting, Area area, CosmosClient client, DingDing _dingDing, HashSet<string> updates)
  266. {
  267. _coreAPIHttpService.check = false;
  268. List<RGroupList> yxtrain = await GroupListService.GetGroupListMemberByType(_coreAPIHttpService, client, "yxtrain", new List<string> { "school" }, $"{school}", _dingDing);
  269. List<TeacherTrain> trains = new List<TeacherTrain>();
  270. var members = yxtrain.SelectMany(x => x.members).ToList();
  271. if (members.Count <= 0)
  272. {
  273. return (trains, yxtrain);
  274. }
  275. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher")
  276. .GetItemQueryIterator<TeacherTrain>(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{school}") }))
  277. {
  278. trains.Add(item);
  279. }
  280. if (updates != null)
  281. {
  282. foreach (var up in updates)
  283. {
  284. trains.ForEach(x => x.update.Add(up));
  285. }
  286. }
  287. var update = trains.FindAll(x => x.update.Count() > 0);
  288. var noupdate = trains.FindAll(x => x.update.Count() <= 0);
  289. var unStatistics = members.Select(x => x.id).Except(trains.Select(x => x.id));
  290. List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
  291. List<TeacherTrain> returnTrains = new List<TeacherTrain>();
  292. if (update.IsNotEmpty())
  293. {
  294. teacherTrains.AddRange(update);
  295. }
  296. if (unStatistics != null)
  297. {
  298. foreach (string x in unStatistics)
  299. {
  300. var member = members.Find(y => y.id.Equals(x));
  301. teacherTrains.Add(new TeacherTrain
  302. {
  303. pk = "TeacherTrain",
  304. id = x,
  305. code = $"TeacherTrain-{school}",
  306. tmdid = x,
  307. nickname=member.nickname,
  308. name = member.name,
  309. picture = member.picture,
  310. school = school,
  311. groupName = member.groupName,
  312. update = new HashSet<string> { TeacherAbility, TeacherClass, OfflineRecord }
  313. });
  314. }
  315. }
  316. List<Study> studies = new List<Study>();
  317. await foreach (var item in client.GetContainer("TEAMModelOS", "Common")
  318. .GetItemQueryIterator<Study>(queryText: $"select value(c) from c where c.owner<>'area' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Study-{school}") }))
  319. {
  320. studies.Add(item);
  321. }
  322. returnTrains = await GetStatisticsTeacher(teacherTrains, setting, area, client, studies);
  323. //await foreach (var tarain in GetStatisticsTeacher(teacherTrains, setting, area, client))
  324. //{
  325. // returnTrains.Add(tarain);
  326. //}
  327. if (noupdate.IsNotEmpty())
  328. {
  329. returnTrains.AddRange(noupdate);
  330. }
  331. //移除不在研修名单的人员
  332. returnTrains.RemoveAll(x => !members.Select(y => y.id).Contains(x.id));
  333. returnTrains.ForEach(x => {
  334. var mbm = members.Find(y => y.id.Equals(x.id));
  335. if (mbm != null)
  336. {
  337. x.groupName = mbm?.groupName;
  338. x.name = !string.IsNullOrWhiteSpace(x.name) ? x.name : mbm?.name;
  339. x.nickname = mbm?.nickname;
  340. x.picture = mbm?.picture;
  341. }
  342. });
  343. return (returnTrains, yxtrain);
  344. }
  345. public static async Task<List<TeacherTrain>> GetStatisticsTeacher(List<TeacherTrain> trains, AreaSetting setting, Area area, CosmosClient client, List<Study> studies)
  346. {
  347. List<Task<TeacherTrain>> teachers = new List<Task<TeacherTrain>>();
  348. foreach (var train in trains)
  349. {
  350. teachers.Add(StatisticsTeacher(train, setting, area, client, studies)); //yield return await StatisticsTeacher( train, setting, area, client);
  351. }
  352. int pagesize = 20;
  353. if (teachers.Count <= pagesize)
  354. {
  355. await Task.WhenAll(teachers);
  356. }
  357. else
  358. {
  359. int pages = (teachers.Count + pagesize) / pagesize; //256是批量操作最大值,pages = (total + max -1) / max;
  360. for (int i = 0; i < pages; i++)
  361. {
  362. var lists = teachers.Skip((i) * pagesize).Take(pagesize).ToList();
  363. await Task.WhenAll(lists);
  364. }
  365. }
  366. return trains;
  367. }
  368. public static async Task<TeacherTrain> StatisticsTeacher(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, List<Study> studies)
  369. {
  370. string _school = train.school;
  371. string _tmdid = train.tmdid;
  372. // TeacherTrain teacher_train = null;
  373. List<Task<TeacherTrain>> teachers = new List<Task<TeacherTrain>>();
  374. if (train.update.Count > 0)
  375. {
  376. foreach (string property in train.update)
  377. {
  378. teachers.Add(DoProperty(train.update, property, setting, area, client, train, studies));
  379. }
  380. int pagesize = 20;
  381. if (teachers.Count <= pagesize)
  382. {
  383. await Task.WhenAll(teachers);
  384. }
  385. else
  386. {
  387. int pages = (teachers.Count + pagesize) / pagesize; //256是批量操作最大值,pages = (total + max -1) / max;
  388. for (int i = 0; i < pages; i++)
  389. {
  390. var lists = teachers.Skip((i) * pagesize).Take(pagesize).ToList();
  391. await Task.WhenAll(lists);
  392. }
  393. }
  394. }
  395. //每次都统计活动相关的数据。
  396. // train= await DoActivity(train, setting, area, client, _school, _tmdid);
  397. train.totalTime = train.onlineTime + train.classTime + train.currency.submitTime + train.offlineTime;
  398. if (train.totalTime >= setting.allTime)
  399. {
  400. //如果总学生超过50 且不是优秀则至少是合格。
  401. if (train.finalScore != 2)
  402. {
  403. train.finalScore = 1;
  404. }
  405. }
  406. // 50> 学时>0 是不合格
  407. else if (train.totalTime < setting.allTime && train.totalTime > 0)
  408. {
  409. train.finalScore = 0;
  410. }
  411. else
  412. {
  413. //学时<=0 则是为
  414. train.finalScore = -1;
  415. }
  416. await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<TeacherTrain>(train, new PartitionKey($"TeacherTrain-{_school}"));
  417. return train;
  418. }
  419. private static async Task<TeacherTrain> DoProperty(HashSet<string> updateProperty, string property, AreaSetting setting, Area area, CosmosClient client, TeacherTrain train, List<Study> studies)
  420. {
  421. string _school = train.school;
  422. string _tmdid = train.tmdid;
  423. switch (property)
  424. {
  425. case TeacherAbility:
  426. train = await DoTeacherAbility(train, setting, area, client, _school, _tmdid);
  427. train.update.Remove(TeacherAbility);
  428. break;
  429. //课堂实录更新
  430. case TeacherClass:
  431. train = await DoTeacherClass(train, setting, area, client, _school, _tmdid);
  432. train.update.Remove(TeacherClass);
  433. break;
  434. //线下研修
  435. case OfflineRecord:
  436. train = await DoOfflineRecord(train, setting, area, client, _school, _tmdid, studies);
  437. train.update.Remove(OfflineRecord);
  438. break;
  439. //投票
  440. case TeacherVote:
  441. train = await DoTeacherVote(train, setting, area, client, _school, _tmdid);
  442. train.update.Remove(TeacherVote);
  443. break;
  444. //问卷
  445. case TeacherSurvey:
  446. train = await DoTeacherSurvey(train, setting, area, client, _school, _tmdid);
  447. train.update.Remove(TeacherSurvey);
  448. break;
  449. //作业
  450. //case TeacherHomework:
  451. // train = await DoTeacherHomework(train, setting, area, client, _school, _tmdid);
  452. // train.updateProperty.Remove(TeacherHomework);
  453. // break;
  454. //评测
  455. case TeacherExamLite:
  456. train = await DoTeacherExamLite(train, setting, area, client, _school, _tmdid);
  457. train.update.Remove(TeacherExamLite);
  458. break;
  459. default:
  460. train.update.Remove(property);
  461. break;
  462. }
  463. return train;
  464. }
  465. public static async Task<TeacherTrain> DoTeacherVote(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid)
  466. {
  467. int voteJoin = 0;
  468. int voteDone = 0;
  469. int voteAreaJoin = 0;
  470. int voteAreaDone = 0;
  471. //投票活动
  472. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
  473. .GetItemQueryIterator<StuActivity>(queryText: $"select c.owner, c.taskStatus from c where c.type = 'Vote' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") }))
  474. {
  475. if (!string.IsNullOrEmpty(item.owner))
  476. {
  477. if (item.owner.Equals("school"))
  478. {
  479. voteJoin += 1;
  480. if (item.taskStatus > 0)
  481. {
  482. voteDone += 1;
  483. }
  484. }
  485. else if (item.owner.Equals("area"))
  486. {
  487. voteAreaJoin += 1;
  488. if (item.taskStatus > 0)
  489. {
  490. voteAreaDone += 1;
  491. }
  492. }
  493. }
  494. }
  495. train.voteJoin = voteJoin;
  496. train.voteDone = voteDone;
  497. train.voteAreaJoin = voteAreaJoin;
  498. train.voteAreaDone = voteAreaDone;
  499. return train;
  500. }
  501. public static async Task<TeacherTrain> DoTeacherSurvey(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid)
  502. {
  503. //问卷调查
  504. int surveyJoin = 0;
  505. int surveyDone = 0;
  506. int surveyAreaJoin = 0;
  507. int surveyAreaDone = 0;
  508. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher")
  509. .GetItemQueryIterator<StuActivity>(queryText: $"select c.owner, c.taskStatus from c where c.type = 'Survey' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") }))
  510. {
  511. if (!string.IsNullOrEmpty(item.owner))
  512. {
  513. if (item.owner.Equals("school"))
  514. {
  515. surveyJoin += 1;
  516. if (item.taskStatus > 0)
  517. {
  518. surveyDone += 1;
  519. }
  520. }
  521. else if (item.owner.Equals("area"))
  522. {
  523. surveyAreaJoin += 1;
  524. if (item.taskStatus > 0)
  525. {
  526. surveyAreaDone += 1;
  527. }
  528. }
  529. }
  530. }
  531. train.surveyJoin = surveyJoin;
  532. train.surveyDone = surveyDone;
  533. train.surveyAreaJoin = surveyAreaJoin;
  534. train.surveyAreaDone = surveyAreaDone;
  535. return train;
  536. }
  537. public static async Task<TeacherTrain> DoTeacherExamLite(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid)
  538. {
  539. //问卷调查
  540. int examJoin = 0;
  541. int examDone = 0;
  542. int examAreaJoin = 0;
  543. int examAreaDone = 0;
  544. //评量检测
  545. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
  546. .GetItemQueryIterator<StuActivity>(queryText: $"select c.owner, c.taskStatus from c where c.type = 'ExamLite' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") }))
  547. {
  548. if (!string.IsNullOrEmpty(item.owner))
  549. {
  550. if (item.owner.Equals("school"))
  551. {
  552. examJoin += 1;
  553. if (item.taskStatus > 0)
  554. {
  555. examDone += 1;
  556. }
  557. }
  558. else if (item.owner.Equals("area"))
  559. {
  560. examAreaJoin += 1;
  561. if (item.taskStatus > 0)
  562. {
  563. examAreaDone += 1;
  564. }
  565. }
  566. }
  567. }
  568. train.examJoin = examJoin;
  569. train.examDone = examDone;
  570. train.examAreaJoin = examAreaJoin;
  571. train.examAreaDone = examAreaDone;
  572. return train;
  573. }
  574. /// <summary>
  575. /// 课堂实录更新
  576. /// </summary>
  577. /// <param name="train"></param>
  578. /// <param name="setting"></param>
  579. /// <param name="area"></param>
  580. /// <param name="client"></param>
  581. /// <param name="_school"></param>
  582. /// <param name="_tmdid"></param>
  583. /// <returns></returns>
  584. public static async Task<TeacherTrain> DoOfflineRecord(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid, List<Study> studies)
  585. {
  586. //owner: school area
  587. //线下 学校研修活动
  588. List<StuActivity> activities = new List<StuActivity>();
  589. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
  590. .GetItemQueryIterator<StuActivity>(queryText: $"select value(c) from c where c.type = 'Study' and c.owner<>'area' and c.school='{_school}' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") }))
  591. {
  592. activities.Add(item);
  593. }
  594. string insql = "";
  595. if (studies.IsEmpty())
  596. {
  597. studies = new List<Study>();
  598. if (activities.IsNotEmpty())
  599. {
  600. insql = $" where c.id in ({string.Join(",", activities.Select(o => $"'{o.id}'"))})";
  601. await foreach (var item in client.GetContainer("TEAMModelOS", "Common")
  602. .GetItemQueryIterator<Study>(queryText: $"select value(c) from c {insql} and c.owner<>'area' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Study-{_school}") }))
  603. {
  604. studies.Add(item);
  605. }
  606. }
  607. }
  608. List<StudyRecord> studyRecords = new List<StudyRecord>();
  609. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
  610. .GetItemQueryIterator<StudyRecord>(queryText: $"select value(c) from c {insql} ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"StudyRecord-{_tmdid}") }))
  611. {
  612. studyRecords.Add(item);
  613. }
  614. List<HomeworkRecord> homeworkRecords = new List<HomeworkRecord>();
  615. List<Study> workids = studies.FindAll(x => !string.IsNullOrEmpty(x.workId));
  616. bool haswork = false;
  617. List<string> workidSubmits = new List<string>();
  618. if (workids.IsNotEmpty())
  619. {
  620. string rcdsql = $" where c.id in ({string.Join(",", workids.Select(o => $"'{o.workId}'"))})";
  621. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
  622. .GetItemQueryIterator<HomeworkRecord>(queryText: $"select value(c) from c {rcdsql} ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"HomeworkRecord-{_tmdid}") }))
  623. {
  624. var content = item.content.FindAll(x => x.prime);
  625. if (content.IsNotEmpty())
  626. {
  627. workidSubmits.Add(item.id);
  628. }
  629. homeworkRecords.Add(item);
  630. }
  631. //标记已经有需要提交作业的线下研修活动。则需要检查至少有一次的作业提交记录。否则不能获得学时。
  632. haswork = true;
  633. }
  634. //如果交了至少一份作业
  635. //一份作业都没有交
  636. //标记是否计算所有学时。
  637. bool getAll = false;
  638. if (haswork)
  639. {
  640. //如果有作业就需要检查是否至少交了一份作业。 如果交了一份,并且通过了,则可以计算全部。具体查看mark qweorrty
  641. getAll = false;
  642. }
  643. else
  644. {
  645. //如果没有作业,则计算全部学时。
  646. getAll = true;
  647. }
  648. activities.ForEach(item => {
  649. Study study = studies.Find(y => y.id.Equals(item.id) && !string.IsNullOrEmpty(y.workId));
  650. if (study != null)
  651. {
  652. StudyRecord studyRecord = studyRecords.Find(y => y.id.Equals(item.id));
  653. if (studyRecord != null && studyRecord.status > 0)
  654. {
  655. //mark qweorrty
  656. var submit = workidSubmits.Find(y => y.Equals(study.workId));
  657. if (submit != null)
  658. {
  659. getAll = true;
  660. }
  661. }
  662. }
  663. });
  664. List<OfflineRecord> offlines = new List<OfflineRecord>();
  665. activities.ForEach(item =>
  666. {
  667. Study study = studies.Find(y => y.id.Equals(item.id));
  668. if (study != null)
  669. {
  670. StudyRecord studyRecord = studyRecords.Find(y => y.id.Equals(item.id));
  671. OfflineRecord record = new OfflineRecord
  672. {
  673. id = item.id,
  674. name = item.name,
  675. done = item.taskStatus,
  676. owner = item.owner,
  677. sethour = study.hour
  678. };
  679. bool workOk = false;
  680. if (!string.IsNullOrEmpty(study.workId))
  681. {
  682. HomeworkRecord homeworkRecord = homeworkRecords.Find(y => y.id.Equals(study.workId));
  683. record.other = homeworkRecord?.content;
  684. Attachment attachment = homeworkRecord?.content.Find(x => x.prime);
  685. record.haswork = 1;
  686. if (null != attachment)
  687. {
  688. record.url = attachment.url;
  689. record.upload = 1;
  690. record.hash = attachment.hash;
  691. record.size = attachment.size;
  692. workOk = true;
  693. }
  694. }
  695. if (studyRecord != null)
  696. {
  697. if (getAll)
  698. {
  699. record.hour = studyRecord.status == 1 ? study.hour : 0;
  700. record.score = studyRecord.status;
  701. if (record.score >= 0)
  702. {
  703. record.done = 1;
  704. }
  705. else
  706. {
  707. record.score = -1;
  708. }
  709. }
  710. else
  711. {
  712. if (workOk && !string.IsNullOrEmpty(study.workId))
  713. {
  714. record.hour = studyRecord.status == 1 ? study.hour : 0;
  715. record.score = studyRecord.status;
  716. if (record.score >= 0)
  717. {
  718. record.done = 1;
  719. }
  720. else
  721. {
  722. record.score = -1;
  723. }
  724. }
  725. else if (!workOk && !string.IsNullOrEmpty(study.workId))
  726. {
  727. //没有交任何作业,即使通过,也不会获得学时。
  728. record.hour = 0;
  729. record.score = studyRecord.status;
  730. }
  731. else
  732. {
  733. record.hour = studyRecord.status == 1 ? study.hour : 0;
  734. record.score = studyRecord.status;
  735. if (record.score >= 0)
  736. {
  737. record.done = 1;
  738. }
  739. else
  740. {
  741. record.score = -1;
  742. }
  743. }
  744. }
  745. }
  746. offlines.Add(record);
  747. }
  748. });
  749. //标记已经有需要提交作业的线下研修活动。则需要检查至少有一次的作业提交记录。否则不能获得学时。
  750. int sum = offlines.Select(x => x.hour).Sum();
  751. //if (haswork)
  752. //{
  753. // var workd= homeworkRecords.Where(z=>z.content.IsNotEmpty()).SelectMany(x => x.content).Where(y => y.prime);
  754. // if (workd != null && workd.Count() > 0) {
  755. // sum = offlines.Select(x => x.hour).Sum();
  756. // }
  757. //}
  758. //else
  759. //{
  760. // sum = offlines.Select(x => x.hour).Sum();
  761. //}
  762. //有作业,且没有交任何作业。
  763. if (workidSubmits.IsEmpty() && haswork)
  764. {
  765. train.offlineTime = 0;
  766. }
  767. else
  768. {
  769. train.offlineTime = sum > setting.offlineTime ? setting.offlineTime : sum;
  770. }
  771. train.offlineRecords = offlines;
  772. return train;
  773. }
  774. /// <summary>
  775. /// 课堂实录更新
  776. /// </summary>
  777. /// <param name="train"></param>
  778. /// <param name="setting"></param>
  779. /// <param name="area"></param>
  780. /// <param name="client"></param>
  781. /// <param name="_school"></param>
  782. /// <param name="_tmdid"></param>
  783. /// <returns></returns>
  784. public static async Task<TeacherTrain> DoTeacherClass(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid)
  785. {
  786. string code = $"ClassVideo-{_school}";
  787. ClassVideo classVideo = null;
  788. try
  789. {
  790. classVideo = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<ClassVideo>($"{_tmdid}", new PartitionKey(code));
  791. }
  792. catch (Exception ex)
  793. {
  794. classVideo = null;
  795. }
  796. if (classVideo != null && classVideo.files.IsNotEmpty())
  797. {
  798. //2021.11.17 15:05,与J哥确认,取课堂实录第一个。前端也只show第一个视频。
  799. var files = classVideo.files[0];
  800. if (files.score > 0)
  801. {
  802. train.classTime = setting.classTime;
  803. }
  804. else
  805. {
  806. train.classTime = 0;
  807. }
  808. train.teacherClasses = new List<TeacherClass> { new Models.TeacherClass { url = files.url, score = files.score, hash = files.hash, name = files.name, size = files.size } };
  809. }
  810. else
  811. {
  812. train.classTime = 0;
  813. }
  814. return train;
  815. }
  816. public static async Task<TeacherTrain> DoTeacherAbility(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid)
  817. {
  818. //视频播放
  819. List<string> abilityIds = new List<string>();
  820. TeacherFile file = null;
  821. try
  822. {
  823. file = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<TeacherFile>(_tmdid, new PartitionKey($"TeacherFile-{_school}"));
  824. }
  825. catch (CosmosException)
  826. {
  827. file = new TeacherFile
  828. {
  829. id = _tmdid,
  830. code = $"TeacherFile-{_school}",
  831. pk = "TeacherFile",
  832. ttl = -1,
  833. };
  834. await client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<TeacherFile>(file, new PartitionKey($"TeacherFile-{_school}"));
  835. }
  836. List<AbilitySub> abilitySubs = new List<AbilitySub>();
  837. //认证材料
  838. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
  839. .GetItemQueryIterator<AbilitySub>(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"AbilitySub-{_school}-{_tmdid}") }))
  840. {
  841. abilitySubs.Add(item);
  842. }
  843. List<Ability> abilities = new List<Ability>();
  844. string insql = "";
  845. if (abilitySubs.IsNotEmpty())
  846. {
  847. insql = $" where c.id in ({string.Join(",", abilitySubs.Select(o => $"'{o.id}'"))})";
  848. }
  849. await foreach (var item in client.GetContainer("TEAMModelOS", "Normal")
  850. .GetItemQueryIterator<Ability>(queryText: $"select c.comid, c.id,c.name,c.currency,c.no,c.dimension,c.hour,c.stds,c.abilityCount from c {insql} ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Ability-{area.standard}") }))
  851. {
  852. abilities.Add(item);
  853. }
  854. List<Debate> debates = new List<Debate>();
  855. if (abilities.IsNotEmpty())
  856. {
  857. await foreach (var item in client.GetContainer("TEAMModelOS", "School")
  858. .GetItemQueryIterator<Debate>(queryText: $"select distinct value(c) from c join b in c.replies where b.tmdid='{_tmdid}'and c.source='uploadscore' and c.comid in ({string.Join(",", abilities.Select(o => $"'{o.comid}'"))})",
  859. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Debate-{_school}") }))
  860. {
  861. debates.Add(item);
  862. }
  863. }
  864. Currency currency = new Currency();
  865. // Currency currencyAll = new Currency();
  866. abilitySubs.ForEach(item => {
  867. int currencyInt = item.from == 1 ? 1 : 0;
  868. Ability ability = abilities.Find(x => x.id.Equals(item.id));
  869. if (ability != null)
  870. {
  871. if (ability != null)
  872. {
  873. currencyInt = item.from == 0 ? ability.currency : 1;
  874. }
  875. else
  876. {
  877. currencyInt = 0;
  878. }
  879. if (item.uploads.IsNotEmpty())
  880. {
  881. if (currencyInt == 1)
  882. {
  883. currency.uploadDone += item.uploads.Count;
  884. }
  885. // currencyAll.uploadDone += item.uploads.Count;
  886. }
  887. //通过能力点自测
  888. if (item.exerciseScore > 0)
  889. {
  890. if (currencyInt == 1)
  891. {
  892. // 与J哥 ,郭杰确认。只计算通过能力点自测就能获得的成长值。 并取消已学能力点 learnAbility
  893. currency.exerciseAbility += ability.abilityCount;
  894. //并且完全看完视频和文档。
  895. if (item.allDone)
  896. {
  897. currency.learnAbility += 1;
  898. }
  899. }
  900. //并且完全看完视频和文档。
  901. //if (item.allDone)
  902. //{
  903. // currencyAll.learnAbility += 1;
  904. //}
  905. //currencyAll.exerciseAbility += ability.abilityCount;
  906. }
  907. List<TeacherHprecord> hprecords = new List<TeacherHprecord>();
  908. List<Debate> debateOrthers = debates.FindAll(x => x.comid.Equals(ability.comid) && x.replies.IsNotEmpty());
  909. int debateOrther = -1;
  910. List<string> replyIds = new List<string>();
  911. if (debateOrthers.IsNotEmpty())
  912. {
  913. debateOrther = debateOrthers.Count;
  914. var replies = debateOrthers.SelectMany(x => x.replies).Where(z => z.tmdid.Equals(_tmdid));
  915. if (replies != null && replies.Count() > 0)
  916. {
  917. replyIds = replies.Select(x => x.id).ToList();
  918. }
  919. }
  920. TeacherAbility teacherAbility = new Models.TeacherAbility
  921. {
  922. replyIds = replyIds,
  923. debateOrther = debateOrther,
  924. id = ability.id,
  925. currency = currencyInt,
  926. no = ability.no,
  927. name = ability.name,
  928. dimension = ability.dimension,
  929. zpscore = item.self == 0 ? 1 : item.self,
  930. hprecord = hprecords,
  931. uploadHas = item.uploads.Count
  932. };
  933. if (file != null)
  934. {
  935. double view = 0;
  936. file.fileRecords.ForEach(record => {
  937. var abilityVideo = record.files.FindAll(x => x.abilityId.Equals(item.id));
  938. if (abilityVideo.IsNotEmpty())
  939. {
  940. view += record.view;
  941. }
  942. });
  943. //能力点学时限制
  944. int limit = ability.hour * setting.lessonMinutes;
  945. //如果超过 8* 45分钟学时,则直接赋值360(limit)分钟。
  946. view = view / 60;
  947. view = view > limit ? limit : view;
  948. teacherAbility.videoTime = (int)view;
  949. teacherAbility.limitTime = ability.hour;
  950. teacherAbility.onlineTime = setting.lessonMinutes != 0 ? (int)(view / setting.lessonMinutes) : 0;
  951. }
  952. if (item.otherScore.IsNotEmpty())
  953. {
  954. var schoolScore = item.otherScore.Where(x => x.roleType.Equals("school")).FirstOrDefault();
  955. if (schoolScore != null && schoolScore.score >= 0)
  956. {
  957. teacherAbility.xzscore = schoolScore.score;
  958. teacherAbility.xztime = schoolScore.time;
  959. teacherAbility.xztmdid = schoolScore.tmdid;
  960. teacherAbility.xztmdname = schoolScore.tmdname;
  961. }
  962. var hprecord = item.otherScore.FindAll(x => x.roleType.Equals("member")).Select(y => new TeacherHprecord { tmdid = y.tmdid, tmdname = y.tmdname, score = y.score });
  963. if (hprecord != null)
  964. {
  965. var no = hprecord.Where(x => x.score == 0) != null ? hprecord.Where(x => x.score == 0).Count() : 0;
  966. var hg = hprecord.Where(x => x.score == 1) != null ? hprecord.Where(x => x.score == 1).Count() : 0;
  967. var yx = hprecord.Where(x => x.score == 2) != null ? hprecord.Where(x => x.score == 2).Count() : 0;
  968. if (no == hg && hg == yx && no == 0)
  969. {
  970. //未评分 合格,优秀都是0 则未评分
  971. teacherAbility.hpscore = -1;
  972. }
  973. else if (no == hg && hg == yx && no != 0)
  974. {
  975. //未评分,合格,优秀不为0 且一样,按优秀算
  976. teacherAbility.hpscore = 2;
  977. }
  978. else
  979. {
  980. bool ok = false;
  981. List<int> arr = new List<int>() { yx, hg, no };
  982. int max = arr.Max();
  983. //有优秀按优秀算
  984. if (max == yx && !ok)
  985. {
  986. teacherAbility.hpscore = 2;
  987. ok = true;
  988. }
  989. //最高评分是合格,按合格算
  990. if (max == hg && !ok)
  991. {
  992. teacherAbility.hpscore = 1;
  993. ok = true;
  994. }
  995. //最高评分是未评分则按未评分算
  996. if (max == no && !ok)
  997. {
  998. teacherAbility.hpscore = 0;
  999. ok = true;
  1000. }
  1001. }
  1002. teacherAbility.hprecord.AddRange(hprecord);
  1003. }
  1004. }
  1005. if (currencyInt == 1)
  1006. {
  1007. currency.subCount += 1;
  1008. currency.uploadTotal += ability.stds.FindAll(x => x.task.IsNotEmpty()).Select(y => y.task).Count();
  1009. currency.teacherAilities.Add(teacherAbility);
  1010. }
  1011. // currencyAll.subCount += 1;
  1012. // currencyAll.uploadTotal += ability.stds.FindAll(x => x.task.IsNotEmpty()).Select(y => y.task).Count();
  1013. // currencyAll.teacherAilities.Add(teacherAbility);
  1014. }
  1015. });
  1016. train.currency = currency;
  1017. // train.currencyAll = currencyAll;
  1018. train.currency.videoTime = train.currency.teacherAilities.Select(x => x.videoTime).Sum();
  1019. // train.currencyAll.videoTime = train.currencyAll.teacherAilities.Select(x => x.videoTime).Sum();
  1020. //如果总分钟数超过20学时,则直接复制20学时。
  1021. var videoTime = setting.lessonMinutes != 0 ? (int)(train.currency.videoTime / setting.lessonMinutes) : 0;
  1022. train.onlineTime = videoTime > setting.onlineTime ? setting.onlineTime : videoTime;
  1023. var bhg = train.currency.teacherAilities.FindAll(x => x.xzscore > 0);
  1024. //由于有教师在省平台勾选太多能力点,暂时获得xzscore 数量大于三个的,也能获得学时
  1025. int limitAbility = 3;
  1026. if (setting.limitAbility != -1) {
  1027. limitAbility=setting.limitAbility;
  1028. }
  1029. if (bhg.IsNotEmpty() && (bhg.Count == train.currency.subCount|| bhg.Count>= limitAbility))
  1030. {
  1031. ///要全部合格才能获得学时。
  1032. train.currency.submitTime = setting.submitTime;
  1033. // train.currencyAll.submitTime = setting.submitTime;
  1034. }
  1035. return train;
  1036. }
  1037. }
  1038. }