ThirdService.cs 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. using Azure.Cosmos;
  2. using Azure.Storage.Blobs.Models;
  3. using DocumentFormat.OpenXml.Drawing.Charts;
  4. using DocumentFormat.OpenXml.Office2010.Excel;
  5. using HTEXLib.COMM.Helpers;
  6. using Microsoft.Extensions.Configuration;
  7. using Microsoft.OData.Edm;
  8. using Newtonsoft.Json;
  9. using OpenXmlPowerTools;
  10. using OpenXmlPowerTools.HtmlToWml.CSS;
  11. using System;
  12. using System.Collections.Generic;
  13. using System.IO;
  14. using System.Linq;
  15. using System.Net.Http;
  16. using System.Text;
  17. using System.Text.Json;
  18. using System.Threading.Tasks;
  19. using TEAMModelOS.Models;
  20. using TEAMModelOS.SDK.DI;
  21. using TEAMModelOS.SDK.Extension;
  22. using TEAMModelOS.SDK.Models.Cosmos;
  23. using TEAMModelOS.SDK.Models.Cosmos.Student;
  24. using static TEAMModelOS.SDK.Models.Teacher;
  25. namespace TEAMModelOS.SDK.Models
  26. {
  27. public static class ThirdService
  28. {
  29. //自动加入学校,加入培训名单,并根据学科进行分组
  30. public static async Task<ScTeacher> GetScTeacher(ScBindData scBind, Teacher teacher, AzureStorageFactory _azureStorage, AzureCosmosFactory _azureCosmos, AzureServiceBusFactory _serviceBus, IConfiguration _configuration, DingDing _dingDing)
  31. {
  32. var table = _azureStorage.GetCloudTableClient().GetTableReference("ScYxpt");
  33. List<ScSchool> schools = await table.FindListByDict<ScSchool>(new Dictionary<string, object> { { "PartitionKey", "ScSchool" }, { "RowKey", scBind.sid } });
  34. List<ScTeacher> scTeachers = await table.FindListByDict<ScTeacher>(new Dictionary<string, object> { { "PartitionKey", "ScTeacher" }, { "TID", scBind.userid }, { "RowKey", $"{scBind.pxid}" } });
  35. if (schools.IsNotEmpty())
  36. {
  37. ScSchool scSchool = schools[0];
  38. if (!string.IsNullOrEmpty(scSchool.schoolCode))
  39. {
  40. try
  41. {
  42. School school = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(scSchool.schoolCode, new PartitionKey("Base"));
  43. if (school != null)
  44. {
  45. if (scTeachers.IsNotEmpty())
  46. {
  47. if (string.IsNullOrEmpty(scTeachers[0].tmdid))
  48. {
  49. scTeachers[0].tmdid = teacher.id;
  50. scTeachers[0].schoolCode = scSchool.schoolCode;
  51. scTeachers[0].areaId = school.areaId;
  52. await table.SaveOrUpdate<ScTeacher>(scTeachers[0]);
  53. }
  54. }
  55. var sc = teacher.schools.Find(x => x.schoolId.Equals(scSchool.schoolCode));
  56. if (sc != null)
  57. {
  58. if (string.IsNullOrEmpty(sc.status) || !sc.status.Equals("join"))
  59. {
  60. sc.status = "join";
  61. try
  62. {
  63. SchoolTeacher schoolTeacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SchoolTeacher>(teacher.id, new PartitionKey($"Teacher-{school.id}"));
  64. if (schoolTeacher != null)
  65. {
  66. if (!schoolTeacher.roles.IsEmpty())
  67. {
  68. if (!schoolTeacher.roles.Contains("teacher"))
  69. {
  70. schoolTeacher.roles.Add("teacher");
  71. }
  72. }
  73. else
  74. {
  75. schoolTeacher.roles = new List<string> { "teacher" };
  76. }
  77. schoolTeacher.status = "join";
  78. schoolTeacher.pk = "Teacher";
  79. schoolTeacher.name = teacher.name;
  80. schoolTeacher.picture = teacher.picture;
  81. schoolTeacher.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  82. schoolTeacher.ttl = -1;
  83. schoolTeacher.permissions = schoolTeacher.permissions.IsNotEmpty() ? schoolTeacher.permissions : new List<string>();
  84. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync(schoolTeacher, new PartitionKey(schoolTeacher.code));
  85. }
  86. }
  87. catch (CosmosException)
  88. {
  89. SchoolTeacher schoolTeacher = new SchoolTeacher
  90. {
  91. id = teacher.id,
  92. code = $"Teacher-{school.id}",
  93. roles = new List<string> { "teacher" },
  94. permissions = new List<string>(),
  95. pk = "Teacher",
  96. name = teacher.name,
  97. picture = teacher.picture,
  98. status = "join",
  99. createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
  100. ttl = -1
  101. };
  102. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync(schoolTeacher, new PartitionKey(schoolTeacher.code));
  103. }
  104. }
  105. }
  106. else
  107. {
  108. teacher.schools.Add(new Teacher.TeacherSchool { schoolId = school.id, name = school.name, areaId = school.areaId, picture = school.picture, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), status = "join" });
  109. SchoolTeacher schoolTeacher = new SchoolTeacher
  110. {
  111. id = teacher.id,
  112. code = $"Teacher-{school.id}",
  113. roles = new List<string> { "teacher" },
  114. permissions = new List<string>(),
  115. pk = "Teacher",
  116. name = teacher.name,
  117. picture = teacher.picture,
  118. status = "join",
  119. createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
  120. };
  121. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync(schoolTeacher, new PartitionKey(schoolTeacher.code));
  122. }
  123. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync(teacher, teacher.id, new PartitionKey("Base"));
  124. //处理培训名单
  125. StringBuilder queryText = new StringBuilder($"SELECT distinct value(c) FROM c where c.type='yxtrain'");
  126. List<GroupList> yxtrain = new List<GroupList>();
  127. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupList>(queryText: queryText.ToString(),
  128. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{scSchool.schoolCode}") }))
  129. {
  130. yxtrain.Add(item);
  131. }
  132. if (yxtrain.IsNotEmpty())
  133. {
  134. string nickname = teacher.name;
  135. string groupName = null;
  136. string groupId = Guid.NewGuid().ToString();
  137. if (scTeachers.IsNotEmpty())
  138. {
  139. if (scBind.pid.Equals("1249"))
  140. {
  141. groupName = $"第三批教师培训组";
  142. }
  143. nickname = scTeachers[0].TeacherName;
  144. if (!string.IsNullOrEmpty(groupName))
  145. {
  146. var mebers = yxtrain.SelectMany(x => x.members).Where(y => !string.IsNullOrEmpty(y.groupName) && y.groupName.Equals(groupName));
  147. if (mebers != null && mebers.Count() > 0)
  148. {
  149. groupId = mebers.First().groupId;
  150. }
  151. }
  152. else { groupId = null; }
  153. }
  154. else { groupId = null; }
  155. var meber = yxtrain.SelectMany(x => x.members).Where(y => y.id.Equals(teacher.id));
  156. //不在研修名单
  157. if (meber == null || !meber.Any())
  158. {
  159. yxtrain[0].members.Add(new Member { id = teacher.id, type = 1, groupId = groupId, groupName = groupName, nickname = nickname });
  160. await GroupListService.UpsertList(yxtrain[0], _azureCosmos, _configuration, _serviceBus, "web");
  161. }
  162. else
  163. {
  164. if (string.IsNullOrEmpty(meber.First().groupId) || string.IsNullOrEmpty(meber.First().groupName))
  165. {
  166. meber.ToList().ForEach(x => { x.groupId = groupId; x.groupName = groupName; x.nickname = string.IsNullOrWhiteSpace(x.nickname) ? nickname : x.nickname; });
  167. await GroupListService.UpsertList(yxtrain[0], _azureCosmos, _configuration, _serviceBus, "web");
  168. }
  169. }
  170. }
  171. else
  172. {
  173. string nickname = teacher.name;
  174. string groupName = null;
  175. if (scTeachers.IsNotEmpty())
  176. {
  177. groupName = scTeachers[0].TeacherXK;
  178. nickname = scTeachers[0].TeacherName;
  179. }
  180. string groupId = null;
  181. if (!string.IsNullOrEmpty(groupName))
  182. {
  183. groupId = Guid.NewGuid().ToString();
  184. }
  185. GroupList groupList = new()
  186. {
  187. id = Guid.NewGuid().ToString(),
  188. code = $"GroupList-{scSchool.schoolCode}",
  189. creatorId = teacher.id,
  190. type = "yxtrain",
  191. year = DateTimeOffset.UtcNow.Year,
  192. expire = 0,
  193. members = new List<Member> { new Member { id = teacher.id, type = 1, groupId = groupId, groupName = groupName, nickname = nickname } },
  194. scope = "school",
  195. school = scSchool.schoolCode,
  196. name = "研修名单",
  197. pk = "GroupList",
  198. ttl = -1
  199. };
  200. await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus, "web");
  201. }
  202. }
  203. }
  204. catch (Exception ex)
  205. {
  206. await _dingDing.SendBotMsg($"OS\n自动加入学校,加入研修名单出现异常:,{ex.Message}\n{ex.StackTrace}GetScTeacher", GroupNames.醍摩豆服務運維群組);
  207. }
  208. }
  209. }
  210. return null;
  211. }
  212. public static async Task<(string accessConfig, Area area, AreaSetting setting)> GetAccessConfig(CosmosClient client, string standard)
  213. {
  214. Area area = null;
  215. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").
  216. GetItemQueryIterator<Area>($"select value(c) from c where c.standard='{standard}'", requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base-Area") }))
  217. {
  218. area = item;
  219. break;
  220. }
  221. AreaSetting setting = null;
  222. if (area != null)
  223. {
  224. try
  225. {
  226. setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>(area.id, new PartitionKey("AreaSetting"));
  227. }
  228. catch (CosmosException)
  229. {
  230. setting = null;
  231. }
  232. }
  233. if (setting == null || string.IsNullOrEmpty(setting.accessConfig))
  234. {
  235. return (null, null, null);
  236. }
  237. else
  238. {
  239. return (setting.accessConfig, area, setting);
  240. }
  241. }
  242. public static async Task<List<Ability>> GetDiagnosisList(CosmosClient client, string standard, DingDing _dingDing, AreaSetting setting, HttpClient _httpClient, Teacher teacher, TEAMModelOS.Models.Option _option, AzureStorageFactory _azureStorage)
  243. {
  244. List<string> abilityNos = new();
  245. var table = _azureStorage.GetCloudTableClient().GetTableReference("ScYxpt");
  246. setting.accessConfig.ToObject<JsonElement>().TryGetProperty("config", out JsonElement _config);
  247. if ($"{_config}".Equals("scsyxpt"))
  248. {
  249. var binds = teacher.binds.FindAll(x => x.type.Equals("scsyxpt"));
  250. var datas = binds.SelectMany(x => x.data).Where(y => y.Contains("scsyxpt"));
  251. HashSet<string> pxids = new();
  252. if (datas != null)
  253. {
  254. datas.ToList().ForEach(x =>
  255. {
  256. var data = x.ToObject<ScBindData>();
  257. if (!string.IsNullOrEmpty(data?.pxid))
  258. {
  259. pxids.Add(data.pxid);
  260. }
  261. });
  262. }
  263. foreach (var pxid in pxids)
  264. {
  265. List<ScTeacher> teachers = await table.FindListByDict<ScTeacher>(new Dictionary<string, object> { { "PartitionKey", "ScTeacher" }, { "PXID", pxid } });
  266. Dictionary<string, object> dict = new();
  267. if (teachers.IsNotEmpty())
  268. {
  269. dict = new Dictionary<string, object>() { { "accessConfig", setting.accessConfig }, { "pxid", pxid }, { "areaId", setting.id }, { "schoolCode", teachers[0].schoolCode } };
  270. }
  271. else
  272. {
  273. dict = new Dictionary<string, object>() { { "accessConfig", setting.accessConfig }, { "pxid", pxid }, { "areaId", setting.id } };
  274. }
  275. (int status, string json) = await ScsStudyApisService.GetDiagnosisListByProject_V2(_httpClient, _dingDing, _azureStorage, setting.id, setting.accessConfig, pxid, teachers[0].schoolCode);
  276. //(int status, string json) = await httpTrigger.RequestHttpTrigger(dict, _option.Location, "GetDiagnosisListByProject_V2");
  277. if (status == 200)
  278. {
  279. List<string> nos = json.ToObject<List<string>>();
  280. if (nos.IsNotEmpty())
  281. {
  282. abilityNos.AddRange(nos);
  283. }
  284. }
  285. }
  286. }
  287. //获取能力点
  288. List<Ability> abilities = null;
  289. if (abilityNos.IsNotEmpty())
  290. {
  291. abilities = new List<Ability>();
  292. StringBuilder sql = new StringBuilder($"select value(c) from c where c.no in ({string.Join(",", abilityNos.Select(x => $"'{x}'"))})");
  293. await foreach (var item in client.GetContainer("TEAMModelOS", "Normal")
  294. .GetItemQueryIterator<Ability>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Ability-{standard}") }))
  295. {
  296. abilities.Add(item);
  297. }
  298. }
  299. return abilities;
  300. }
  301. //5.3.1.22学员校本教研PDF(每人可以返回多条)批量回写-UploadSBTARPDFListV2
  302. public async static Task<(int t53122OK, List<CodeValue> msgs, List<OfflineRecord> allRightOfflineRecords)> check53122(TeacherTrain teacherTrain, List<CodeValue> msgs, string school,
  303. string schoolPrefix, string sas, AzureStorageFactory _azureStorage)
  304. {
  305. int t53122OK = 1;
  306. if (teacherTrain.offlineRecords.Count <= 0)
  307. {
  308. t53122OK = 0;
  309. msgs.Add(new CodeValue("offlineRecord-count", $"文件个数为0"));
  310. }
  311. List<OfflineRecord> allRightOfflineRecords = new List<OfflineRecord>();
  312. var hasUrl = teacherTrain.offlineRecords.Where(x => !string.IsNullOrWhiteSpace(x.url) && x.size > 0);
  313. if (!hasUrl.Any())
  314. {
  315. t53122OK = 0;
  316. msgs.Add(new CodeValue("offlineRecord-url", $"需要上传的校本研修作业至少有一个。"));
  317. }
  318. if (teacherTrain.offlineReport == null)
  319. {
  320. t53122OK = 0;
  321. msgs.Add(new CodeValue("offlineReport", $"校本研修汇总报告未生成。"));
  322. }
  323. List<string> unexistUrl = new List<string>();
  324. foreach (var url in hasUrl)
  325. {
  326. string blobItem = url.url.Replace($"{schoolPrefix}/", "");
  327. bool Exist = await _azureStorage.GetBlobContainerClient(school).GetBlobClient(blobItem).ExistsAsync();
  328. if (!Exist)
  329. {
  330. unexistUrl.Add($"{url.url}?{sas}");
  331. }
  332. else
  333. {
  334. allRightOfflineRecords.Add(url);
  335. }
  336. }
  337. if (unexistUrl.Any() && hasUrl.Count() > 0 && hasUrl.Count() == unexistUrl.Count)
  338. {
  339. t53122OK = 0;
  340. msgs.Add(new CodeValue("offlineRecord-url-unexist", $"校本研修文件不存在,{string.Join(" , ", unexistUrl)}"));
  341. }
  342. //不需要检查每一个校本研修的文件记录。
  343. //teacherTrain.offlineRecords.ForEach(x => {
  344. // if (string.IsNullOrEmpty(x.url)) {
  345. // msgs.Add(new CodeValue("offlineRecord-url", $"链接为空"));
  346. // }
  347. // if (x.size<=0)
  348. // {
  349. // msgs.Add(new CodeValue("offlineRecord-size", $"文件大小"));
  350. // }
  351. //});
  352. return (t53122OK, msgs, allRightOfflineRecords);
  353. }
  354. //5.3.1.17学员课堂实录批量回写-UploadKTSLList
  355. public async static Task<(int t53117OK, List<CodeValue> msgs)> check53117(TeacherTrain teacherTrain, List<CodeValue> msgs, string school,
  356. string schoolPrefix, string sas, AzureStorageFactory _azureStorage)
  357. {
  358. //校验 基本情况是否满足
  359. int t53117OK = 1;
  360. if (teacherTrain.classTime <= 0)
  361. {
  362. msgs.Add(new CodeValue("classTime", $"未获得学时:{teacherTrain.classTime}"));
  363. t53117OK = 0;
  364. }
  365. if (teacherTrain.teacherClasses.Count() <= 0)
  366. {
  367. msgs.Add(new CodeValue("teacherClasses", $"未上传课堂实录:{teacherTrain.teacherClasses.Count()}个视频"));
  368. t53117OK = 0;
  369. }
  370. teacherTrain.teacherClasses.ForEach(x =>
  371. {
  372. if (string.IsNullOrWhiteSpace(x.url))
  373. {
  374. t53117OK = 0;
  375. msgs.Add(new CodeValue("teacherClasses", $"课堂实录链接无效"));
  376. }
  377. });
  378. List<string> unexistUrl = new List<string>();
  379. foreach (var url in teacherTrain.teacherClasses)
  380. {
  381. string blobItem = url.url.Replace($"{schoolPrefix}/", "");
  382. bool Exist = await _azureStorage.GetBlobContainerClient(school).GetBlobClient(blobItem).ExistsAsync();
  383. if (!Exist)
  384. {
  385. unexistUrl.Add($"{url.url}?{sas}");
  386. }
  387. }
  388. if (unexistUrl.Any())
  389. {
  390. t53117OK = 0;
  391. msgs.Add(new CodeValue("teacherClasses-url-unexist", $"课堂实录文件不存在,{string.Join(" , ", unexistUrl)}"));
  392. }
  393. return (t53117OK, msgs);
  394. }
  395. //5.3.1.12学员培训基本情况批量回写-UpdateTeacherListSituation
  396. public static (int t53112OK, List<CodeValue> msgs) check53112(TeacherTrain teacherTrain, List<CodeValue> msgs)
  397. {
  398. //校验 基本情况是否满足
  399. int t53112OK = 1;
  400. if (teacherTrain.finalScore <= 0)
  401. {
  402. //总体认定结果0、未认定 1、合格 2、优秀 3、不合格 4、其他
  403. msgs.Add(new CodeValue("finalScore", $"最终评定结果参数:{teacherTrain.finalScore}"));
  404. t53112OK = 0;
  405. }
  406. //if (string.IsNullOrEmpty(teacherTrain.summary) || teacherTrain.summary.Length > 300)
  407. //{
  408. // string msg = string.IsNullOrEmpty(teacherTrain.summary) ? "未填写" : teacherTrain.summary.Length > 300 ? "字数超过300." : "";
  409. // msgs.Add(new CodeValue("summary", $"教师培训总结:{msg}"));
  410. // t53112OK = 0;
  411. //}
  412. if (!string.IsNullOrEmpty(teacherTrain.summary) && teacherTrain.summary.Length > 300)
  413. {
  414. //string msg = string.IsNullOrEmpty(teacherTrain.summary) ? "未填写" : teacherTrain.summary.Length > 300 ? "字数超过300." : "";
  415. msgs.Add(new CodeValue("summary", $"教师培训总结:字数超过300."));
  416. t53112OK = 0;
  417. }
  418. if (teacherTrain.totalTime <= 0)
  419. {
  420. msgs.Add(new CodeValue("totalTime", $"未获得学时:{teacherTrain.totalTime}"));
  421. t53112OK = 0;
  422. }
  423. return (t53112OK, msgs);
  424. }
  425. //5.3.1.13学员能力点测评结果批量回写-UpdateTeacherListDiagnosis
  426. public async static Task<(int t53113OK, List<CodeValue> msgs, List<AbilitySub> abilitySubs, List<AbilitySub> allRightAbility)> check53113(AzureCosmosFactory _azureCosmos, TeacherTrain teacherTrain, ScTeacherDiagnosis diagnosis,
  427. List<CodeValue> msgs, string school,
  428. string schoolPrefix, string sas, AzureStorageFactory _azureStorage)
  429. {
  430. //校验 基本情况是否满足
  431. int t53113OK = 1;
  432. List<AbilitySub> allRightAbility = new List<AbilitySub>();
  433. List<AbilitySub> abilitySubs = new List<AbilitySub>();
  434. if (teacherTrain.currency.videoTime <= 0)
  435. {
  436. msgs.Add(new CodeValue("videoTime", $"视频学习时长:{teacherTrain.currency.videoTime}"));
  437. t53113OK = 0;
  438. }
  439. if (teacherTrain.currency.submitTime <= 0)
  440. {
  441. msgs.Add(new CodeValue("submitTime", $"认证材料学习:{teacherTrain.currency.submitTime}"));
  442. t53113OK = 0;
  443. }
  444. if (teacherTrain.currency.teacherAilities.Count <= 0)
  445. {
  446. msgs.Add(new CodeValue("teacherAilities", $"已学习能力点:0"));
  447. t53113OK = 0;
  448. }
  449. try
  450. {
  451. if (diagnosis != null)
  452. {
  453. if (!string.IsNullOrWhiteSpace(diagnosis.abilityNos))
  454. {
  455. List<string> nos = diagnosis.abilityNos.ToObject<List<string>>();
  456. if (nos.Count > 0 && teacherTrain.currency.teacherAilities.Count > 0)
  457. {
  458. var notin = nos.Except(teacherTrain.currency.teacherAilities.Select(x => x.no).Where(z => !string.IsNullOrWhiteSpace(z)));
  459. if (notin.Any())
  460. {
  461. msgs.Add(new CodeValue("diagnosisNos", $"省平台勾选的能力点编号为学习完成:省平台:{string.Join(",", nos.OrderBy(x => x))}" + $" ,已学习:{string.Join(",", teacherTrain.currency.teacherAilities.Select(x => x.no).OrderBy(x => x))} "));
  462. t53113OK = 0;
  463. }
  464. else
  465. {
  466. string insql = "";
  467. if (teacherTrain.currency.teacherAilities.IsNotEmpty())
  468. {
  469. var abilites = teacherTrain.currency.teacherAilities.Where(c => !string.IsNullOrWhiteSpace(c.no) && nos.Contains(c.no));
  470. insql = $" where c.id in ({string.Join(",", abilites.Select(o => $"'{o.id}'"))})";
  471. }
  472. //认证材料
  473. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher")
  474. .GetItemQueryIterator<AbilitySub>(queryText: $"select value(c) from c {insql}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"AbilitySub-{teacherTrain.school}-{teacherTrain.id}") }))
  475. {
  476. abilitySubs.Add(item);
  477. }
  478. if (abilitySubs.Count() <= 3)
  479. {
  480. abilitySubs.ForEach(ab =>
  481. {
  482. var x = teacherTrain.currency.teacherAilities.Find(x => x.id.Equals(ab.id));
  483. if (x == null || !ab.uploads.Any())
  484. {
  485. t53113OK = 0;
  486. msgs.Add(new CodeValue("uploads", $"未上传认证材料:{x.no},{x.name}"));
  487. }
  488. if (x.zpscore <= 0)
  489. {
  490. t53113OK = 0;
  491. msgs.Add(new CodeValue("zpscore", $"认证材料,没有完成自评:{x.no},{x.name},{x.zpscore}"));
  492. }
  493. if (x.hpscore <= 0)
  494. {
  495. x.hpscore = 1;
  496. }
  497. if (x.xzscore <= 0)
  498. {
  499. x.xzscore = 1;
  500. }
  501. });
  502. foreach (AbilitySub abilitySub in abilitySubs)
  503. {
  504. //当前能力点上传的文件是否完全有效
  505. bool isAllRight = true;
  506. List<string> urlUn = new List<string>();
  507. foreach (var subUpload in abilitySub.uploads)
  508. {
  509. foreach (var url in subUpload.urls)
  510. {
  511. string blobItem = url.url.Replace($"{schoolPrefix}/", "");
  512. bool Exist = await _azureStorage.GetBlobContainerClient(school).GetBlobClient(blobItem).ExistsAsync();
  513. if (!Exist)
  514. {
  515. isAllRight = false;
  516. urlUn.Add($"{url.url}?{sas}");
  517. }
  518. }
  519. }
  520. if (isAllRight)
  521. {
  522. allRightAbility.Add(abilitySub);
  523. }
  524. else
  525. {
  526. t53113OK = 0;
  527. var x = teacherTrain.currency.teacherAilities.Find(x => x.id.Equals(abilitySub.id));
  528. msgs.Add(new CodeValue("uploads-url", $"{x.no},{x.name}上传的认证材料文件失效:{string.Join(" , ", urlUn)}"));
  529. }
  530. }
  531. }
  532. else
  533. {
  534. //一个都没上传
  535. if (!abilitySubs.SelectMany(upsl => upsl.uploads).Any())
  536. {
  537. t53113OK = 0;
  538. msgs.Add(new CodeValue("uploads-all", $"没有上传认证材料。"));
  539. }
  540. else
  541. {
  542. //检查上传了认证材料的能力点,超过三个的。
  543. var uploaded = abilitySubs.FindAll(x => x.uploads.Count > 0);
  544. //不足三个的则需要记录
  545. if (uploaded.Count < 3)
  546. {
  547. t53113OK = 0;
  548. ///少于三个的,需要判断另外的不满足情况的
  549. abilitySubs.RemoveAll(x => x.uploads.Count > 0);
  550. abilitySubs.ForEach(ab =>
  551. {
  552. var x = teacherTrain.currency.teacherAilities.Find(x => x.id.Equals(ab.id));
  553. if (x == null || !ab.uploads.Any())
  554. {
  555. t53113OK = 0;
  556. msgs.Add(new CodeValue("uploads", $"未上传认证材料:{x.no},{x.name}"));
  557. }
  558. if (x.zpscore <= 0)
  559. {
  560. t53113OK = 0;
  561. msgs.Add(new CodeValue("zpscore", $"认证材料,没有完成自评:{x.no},{x.name},{x.zpscore}"));
  562. }
  563. if (x.hpscore <= 0)
  564. {
  565. t53113OK = 0;
  566. //如果只有三个,且互评为未评状态,则直接为合格。
  567. x.hpscore = 1;
  568. msgs.Add(new CodeValue("hpscore", $"认证材料,没有完成互评:{x.no},{x.name},{x.hpscore}"));
  569. }
  570. if (x.xzscore <= 0)
  571. {
  572. t53113OK = 0;
  573. msgs.Add(new CodeValue("xzscore", $"认证材料,没有完成小组评:{x.no},{x.name},{x.xzscore}"));
  574. }
  575. });
  576. }
  577. ///如果上传的文件,失效导致不满足3个能力点
  578. List<CodeValue> un_msg = new List<CodeValue>();
  579. //检查已经上传的文件是否正确。
  580. foreach (AbilitySub abilitySub in uploaded)
  581. {
  582. //当前能力点上传的文件是否完全有效
  583. bool isAllRight = true;
  584. List<string> urlUn = new List<string>();
  585. foreach (var subUpload in abilitySub.uploads)
  586. {
  587. foreach (var url in subUpload.urls)
  588. {
  589. string blobItem = url.url.Replace($"{schoolPrefix}/", "");
  590. bool Exist = await _azureStorage.GetBlobContainerClient(school).GetBlobClient(blobItem).ExistsAsync();
  591. if (!Exist)
  592. {
  593. isAllRight = false;
  594. urlUn.Add($"{url.url}?{sas}");
  595. }
  596. }
  597. }
  598. if (isAllRight)
  599. {
  600. allRightAbility.Add(abilitySub);
  601. }
  602. else
  603. {
  604. var x = teacherTrain.currency.teacherAilities.Find(x => x.id.Equals(abilitySub.id));
  605. un_msg.Add(new CodeValue("uploads-url", $"{x.no},{x.name}上传的认证材料文件失效:{string.Join(" , ", urlUn)}"));
  606. }
  607. }
  608. if (allRightAbility.Count < 3)
  609. {
  610. t53113OK = 0;
  611. msgs.AddRange(un_msg);
  612. }
  613. }
  614. }
  615. }
  616. }
  617. else
  618. {
  619. msgs.Add(new CodeValue("teacherAilities", $"未同步省平台挑选的能力点"));
  620. t53113OK = 0;
  621. }
  622. }
  623. else
  624. {
  625. msgs.Add(new CodeValue("teacherAilities", $"未同步省平台挑选的能力点"));
  626. t53113OK = 0;
  627. }
  628. }
  629. else
  630. {
  631. msgs.Add(new CodeValue("teacherAilities", $"未同步省平台挑选的能力点"));
  632. t53113OK = 0;
  633. }
  634. }
  635. catch (Exception ex)
  636. {
  637. throw new Exception($"{ex.StackTrace},{ex.Message}");
  638. }
  639. if (allRightAbility.Count < 3)
  640. {
  641. t53113OK = 0;
  642. msgs.Add(new CodeValue("uploads-count", $"完整上传且有效的认证材料的 能力点数量小于3,当前数量:{allRightAbility.Count}"));
  643. }
  644. return (t53113OK, msgs, abilitySubs, allRightAbility);
  645. }
  646. //推送作答数据
  647. public static async Task<(string id, int code)> pushAnswers(CosmosClient client, AzureStorageFactory _azureStorage, IHttpClientFactory _httpClient, string activityId, string code)
  648. {
  649. if (string.IsNullOrEmpty(activityId))
  650. {
  651. try
  652. {
  653. ExamInfo info = null;
  654. var response = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemStreamAsync(activityId.ToString(), new PartitionKey($"Exam-{code}"));
  655. if (response.Status == 200)
  656. {
  657. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  658. info = json.ToObject<ExamInfo>();
  659. }
  660. List<ExamClassResult> classResults = new();
  661. if (info.scope.Equals("school", StringComparison.OrdinalIgnoreCase))
  662. {
  663. var queryResult = $"select value(c) where c.examId ='{activityId}' and c.pk = 'ExamClassResult' ";
  664. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamClassResult>(queryText: queryResult,
  665. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{info.school}") }))
  666. {
  667. classResults.Add(item);
  668. }
  669. }
  670. else
  671. {
  672. var queryResult = $"select value(c) where c.examId ='{activityId}' and c.pk = 'ExamClassResult' ";
  673. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamClassResult>(queryText: queryResult,
  674. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{code}") }))
  675. {
  676. classResults.Add(item);
  677. }
  678. }
  679. //如果单个活动包含多个科目
  680. var (grade, per) = await GetGradeAsync(client, info);
  681. var (currSemester, studyYear, currSemesterDate, date, nextSemester) = SchoolService.GetSemester(per, info.startTime);
  682. int no = 0;
  683. foreach (var subject in info.subjects)
  684. {
  685. //获取试题详细信息
  686. BlobDownloadResult index_json;
  687. if (info.scope.Equals("school"))
  688. {
  689. index_json = await _azureStorage.GetBlobContainerClient($"{info.school}").GetBlobClient($"{info.papers[no].blob}/index.json").DownloadContentAsync();
  690. }
  691. else
  692. {
  693. index_json = await _azureStorage.GetBlobContainerClient($"{info.creatorId}").GetBlobClient($"{info.papers[no].blob}/index.json").DownloadContentAsync();
  694. }
  695. JsonElement RecordingJson = JsonDocument.Parse(new MemoryStream(Encoding.UTF8.GetBytes(index_json.Content.ToString()))).RootElement;
  696. RecordingJson.TryGetProperty("slides", out JsonElement slides);
  697. var sdes = slides.ToObject<List<Slides>>();
  698. List<string> urls = new();
  699. foreach (var ne in sdes)
  700. {
  701. if (!ne.type.Equals("compose"))
  702. {
  703. urls.Add(ne.url);
  704. }
  705. }
  706. // 获取整体的题目ID集合
  707. List<string> ids = new();
  708. List<(string id, string type, double score, int difficulty, string choices, string answer)> itemInfos = new();
  709. int index = 1;
  710. foreach (string url in urls)
  711. {
  712. string id = url.Replace(".json", "");
  713. BlobDownloadResult index_item_json;
  714. if (info.scope.Equals("school"))
  715. {
  716. index_item_json = await _azureStorage.GetBlobContainerClient($"{info.school}").GetBlobClient($"{info.papers[no].blob}/{url}").DownloadContentAsync();
  717. }
  718. else
  719. {
  720. index_item_json = await _azureStorage.GetBlobContainerClient($"{info.creatorId}").GetBlobClient($"{info.papers[no].blob}/{url}").DownloadContentAsync();
  721. }
  722. JsonElement itemJson = JsonDocument.Parse(new MemoryStream(Encoding.UTF8.GetBytes(index_item_json.Content.ToString()))).RootElement;
  723. itemJson.TryGetProperty("exercise", out JsonElement exercise);
  724. var item_json = exercise.ToObject<Exercise>();
  725. string type = item_json.type;
  726. int level = item_json.level;
  727. double score = item_json.score;
  728. var ans = item_json.answer;
  729. if (itemJson.TryGetProperty("item", out JsonElement item))
  730. {
  731. var itemInfo_json = item.ToObject<List<itemInfo>>();
  732. StringBuilder sb = new();
  733. StringBuilder an = new();
  734. itemInfo_json.FirstOrDefault().option.Select(c => c.code).ToList().ForEach(z =>
  735. {
  736. sb.Append(z);
  737. });
  738. ans.ForEach(z =>
  739. {
  740. an.Append(z);
  741. });
  742. itemInfos.Add((index.ToString(), type, score, level, sb.ToString(), an.ToString()));
  743. }
  744. index++;
  745. }
  746. //学生作答信息
  747. List<(string stuId, List<(string questionNo, double score, string answer)> ansDt)> stuAns = new();
  748. foreach (ExamClassResult classResult in classResults)
  749. {
  750. if (classResult.subjectId.Equals(subject.id)) {
  751. int stuCount = 0;
  752. foreach (var stu in classResult.studentIds)
  753. {
  754. int itemCount = 0;
  755. List<(string questionNo, double score, string answer)> ansDt = new();
  756. foreach (var itemNo in classResult.studentAnswers[stuCount])
  757. {
  758. ansDt.Add(((itemCount + 1).ToString(), classResult.studentScores[stuCount][itemCount], itemNo));
  759. itemCount++;
  760. }
  761. stuAns.Add((stu, ansDt));
  762. stuCount++;
  763. }
  764. }
  765. }
  766. var jsonString = new
  767. {
  768. examDate = info.startTime,
  769. //todo 不同学段年级数量不一致
  770. grade,
  771. subName = subject.name,
  772. totalScore = info.papers[no].point.Sum(),
  773. termCode = currSemester.start == 1 ? 1 : 2,
  774. data = new
  775. {
  776. items = itemInfos.Select(c => new
  777. {
  778. questionNo = c.id,
  779. c.type,
  780. c.score,
  781. c.difficulty,
  782. c.choices,
  783. c.answer
  784. }),
  785. stuDate = stuAns.Select(c => new
  786. {
  787. stuNo = c.stuId,
  788. scoreData = c.ansDt.Select(z => new
  789. {
  790. z.questionNo,
  791. z.score,
  792. z.answer
  793. })
  794. })
  795. }
  796. };
  797. var key = Md5Hash.GetMd5String("TMD" + info.school);
  798. string connect = $"http://www.moofen.net/esi/tmd/exam/{info.school}/{key}";
  799. var htc = _httpClient.CreateClient();
  800. string paramJson = JsonConvert.SerializeObject(jsonString);
  801. var content = new StringContent(paramJson, Encoding.UTF8, "application/json");
  802. var ansResponse = await htc.PostAsync(connect, content);
  803. if ((int)ansResponse.StatusCode == 200)
  804. {
  805. return (activityId, 200);
  806. }
  807. no++;
  808. }
  809. }
  810. catch (CosmosException)
  811. {
  812. return (activityId, 500);
  813. }
  814. }
  815. return (activityId, 404);
  816. }
  817. public static async Task<(string gId, Period per)> GetGradeAsync(CosmosClient client, ExamInfo info)
  818. {
  819. if (info.grades.Count > 0)
  820. {
  821. var schresponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(info.school, new PartitionKey("Base"));
  822. string grade = "";
  823. School sc = new();
  824. if (schresponse.Status == 200)
  825. {
  826. using var schjson = await JsonDocument.ParseAsync(schresponse.ContentStream);
  827. sc = schjson.ToObject<School>();
  828. }
  829. var period = sc.period.Where(x => x.id.Equals(info.period.id)).FirstOrDefault();
  830. var pType = sc.period.FirstOrDefault(c => c.id.Equals(info.period.id)).periodType;
  831. int pcount = (int)(sc.period.Where(c => c.periodType.Equals("primary")).FirstOrDefault()?.grades.Count);
  832. int jcount = (int)(sc.period.Where(c => c.periodType.Equals("junior")).FirstOrDefault()?.grades.Count);
  833. if (pType.Equals("primary"))
  834. {
  835. grade = (int.Parse(info.grades.FirstOrDefault().id) + 1).ToString();
  836. }
  837. else if (pType.Equals("junior"))
  838. {
  839. grade = (int.Parse(info.grades.FirstOrDefault().id) + 1 + pcount).ToString();
  840. }
  841. else
  842. {
  843. grade = (int.Parse(info.grades.FirstOrDefault().id) + 1 + pcount + jcount).ToString();
  844. }
  845. return (grade, period);
  846. }
  847. else
  848. {
  849. return ("", new Period());
  850. }
  851. }
  852. /* private class item
  853. {
  854. public string questionNo { get; set; }
  855. public string type { get; set; }
  856. public double score { get; set; }
  857. public int difficulty { get; set; }
  858. public string choices { get; set; }
  859. public string answer { get; set; }
  860. }*/
  861. private class itemInfo
  862. {
  863. public List<opt> option { get; set; } = new();
  864. }
  865. private class opt
  866. {
  867. public string code { get; set; }
  868. public double value { get; set; }
  869. }
  870. }
  871. }