StatisticsService.cs 46 KB

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