StatisticsService.cs 50 KB

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