CourseBaseController.cs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. using Azure.Cosmos;
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.AspNetCore.Mvc;
  4. using Microsoft.Extensions.Options;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Text.Json;
  10. using System.Threading.Tasks;
  11. using TEAMModelOS.Models;
  12. using TEAMModelOS.SDK.Models;
  13. using TEAMModelOS.SDK.DI;
  14. using TEAMModelOS.SDK.Extension;
  15. using Azure;
  16. using Microsoft.Extensions.Configuration;
  17. using TEAMModelOS.Filter;
  18. using HTEXLib.COMM.Helpers;
  19. using System.Globalization;
  20. using TEAMModelOS.SDK;
  21. using Microsoft.AspNetCore.Authorization;
  22. using StackExchange.Redis;
  23. using Azure.Storage.Blobs.Models;
  24. using Microsoft.Azure.Amqp.Sasl;
  25. using DocumentFormat.OpenXml.Drawing.Charts;
  26. namespace TEAMModelOS.Controllers.Both
  27. {
  28. [ProducesResponseType(StatusCodes.Status200OK)]
  29. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  30. [Route("course-base")]
  31. [ApiController]
  32. public class CourseBaseController : ControllerBase
  33. {
  34. private AzureCosmosFactory _azureCosmos;
  35. private readonly DingDing _dingDing;
  36. private readonly Option _option;
  37. private readonly AzureServiceBusFactory _serviceBus;
  38. private readonly AzureStorageFactory _azureStorage;
  39. private readonly AzureRedisFactory _azureRedis;
  40. private static List<string> weekDays = new List<string> { "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN" };
  41. public IConfiguration _configuration { get; set; }
  42. public CourseBaseController(AzureRedisFactory azureRedis,AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option, AzureServiceBusFactory serviceBus, AzureStorageFactory azureStorage, IConfiguration configuration)
  43. {
  44. _azureCosmos = azureCosmos;
  45. _dingDing = dingDing;
  46. _option = option?.Value;
  47. _serviceBus = serviceBus;
  48. _configuration = configuration;
  49. _azureStorage = azureStorage;
  50. _azureRedis = azureRedis;
  51. }
  52. /// <summary>
  53. /// 更新保存课程
  54. /// </summary>
  55. /// <param name="request"></param>
  56. /// <returns></returns>
  57. [ProducesDefaultResponseType]
  58. [AuthToken(Roles = "teacher,admin")]
  59. [HttpPost("manage")]
  60. [Authorize(Roles = "IES")]
  61. public async Task<IActionResult> upsert(JsonElement request)
  62. {
  63. try {
  64. (string id, _, _, string school) = HttpContext.GetAuthTokenInfo();
  65. if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
  66. if (!request.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  67. var client = _azureCosmos.GetCosmosClient();
  68. switch (true)
  69. {
  70. case bool when $"{grant_type}".Equals("list", StringComparison.OrdinalIgnoreCase):
  71. {
  72. if ( !request.TryGetProperty("scope", out JsonElement _scope) || !request.TryGetProperty("code", out JsonElement _code))
  73. {
  74. return BadRequest();
  75. }
  76. string tbname = $"{_scope}".Equals("school", StringComparison.OrdinalIgnoreCase)?Constant.School:Constant.Teacher;
  77. string code = $"CourseBase-{_code}";
  78. string baseSql = $"select value c from c ";
  79. List<CourseBase> courseBases = new List<CourseBase>();
  80. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname)
  81. .GetItemQueryIterator<CourseBase>(queryText: baseSql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey(code) }))
  82. {
  83. courseBases.Add(item);
  84. }
  85. return Ok(new { courseBases });
  86. }
  87. case bool when $"{grant_type}".Equals("delete", StringComparison.OrdinalIgnoreCase):
  88. {
  89. if (!request.TryGetProperty("id", out JsonElement _id) || !request.TryGetProperty("scope", out JsonElement _scope) || !request.TryGetProperty("code", out JsonElement _code))
  90. {
  91. return BadRequest();
  92. }
  93. string tbname = $"{_scope}".Equals("school", StringComparison.OrdinalIgnoreCase) ? Constant.School : Constant.Teacher;
  94. Azure.Response response= await client.GetContainer(Constant.TEAMModelOS, tbname).DeleteItemStreamAsync(_id.ToString(), new PartitionKey($"CourseBase-{_code}"));
  95. //需要联动删除排课
  96. string taskCode = $"CourseTask-{_code}-{_id}";
  97. string taskSql = $"select value c from c ";
  98. List<CourseTask> courseTasks = new List<CourseTask>();
  99. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname)
  100. .GetItemQueryIterator<CourseTask>(queryText: taskSql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey(taskCode) }))
  101. {
  102. courseTasks.Add(item);
  103. }
  104. if (courseTasks.Count > 0)
  105. {
  106. await client.GetContainer(Constant.TEAMModelOS, tbname).DeleteItemsStreamAsync(courseTasks.Select(x=>x.id).ToList(), taskCode);
  107. }
  108. return Ok(new {code= response .Status});
  109. }
  110. case bool when $"{grant_type}".Equals("upsert", StringComparison.OrdinalIgnoreCase) :
  111. {
  112. if (!request.TryGetProperty("course", out JsonElement _course))
  113. {
  114. return BadRequest();
  115. }
  116. CourseBase courseBase = _course.ToObject<CourseBase>();
  117. courseBase.pk = "CourseBase";
  118. if (string.IsNullOrWhiteSpace(courseBase.id))
  119. {
  120. courseBase.id = Guid.NewGuid().ToString();
  121. }
  122. string tbname = $"{courseBase.scope}".Equals("school", StringComparison.OrdinalIgnoreCase) ? Constant.School : Constant.Teacher;
  123. if (courseBase.scope.Equals("school", StringComparison.OrdinalIgnoreCase))
  124. {
  125. courseBase.school = school;
  126. courseBase.creatorId = id;
  127. courseBase.code = $"CourseBase-{school}";
  128. }
  129. else
  130. {
  131. courseBase.creatorId = id;
  132. courseBase.code = $"CourseBase-{id}";
  133. }
  134. await client.GetContainer(Constant.TEAMModelOS, tbname).UpsertItemAsync(courseBase, new PartitionKey(courseBase.code));
  135. return Ok(new { course = courseBase });
  136. }
  137. case bool when $"{grant_type}".Equals("read-task", StringComparison.OrdinalIgnoreCase):
  138. {
  139. if (!request.TryGetProperty("scope", out JsonElement _scope))
  140. {
  141. return BadRequest();
  142. }
  143. string tbname = $"{_scope}".Equals("school", StringComparison.OrdinalIgnoreCase) ? Constant.School : Constant.Teacher;
  144. if (_scope.ToString().Equals("school", StringComparison.OrdinalIgnoreCase))
  145. {
  146. if (!request.TryGetProperty("periodId", out JsonElement _periodId)) return BadRequest();
  147. if (!request.TryGetProperty("courseId", out JsonElement _courseId)) return BadRequest();
  148. int studyYear = -1;
  149. string semesterId = string.Empty;
  150. if (!request.TryGetProperty("year", out JsonElement _year) || !request.TryGetProperty("semesterId", out JsonElement _semesterId))
  151. {
  152. //如果没传,则以当前时间获取学年和学期信息
  153. School schoolBase = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(school, new PartitionKey("Base"));
  154. var period = schoolBase.period.Find(x => x.id.Equals($"{_periodId}"));
  155. (Semester currSemester, int studyYear, DateTimeOffset date, DateTimeOffset nextSemester) info = SchoolService.GetSemester(period);
  156. semesterId = info.currSemester.id;
  157. studyYear = info.studyYear;
  158. }
  159. else {
  160. studyYear = _year.GetInt32();
  161. semesterId=_semesterId.GetString();
  162. }
  163. string taskCode = $"CourseTask-{school}-{_courseId}";
  164. string taskId = $"{studyYear}-{semesterId}";
  165. Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname).ReadItemStreamAsync(taskId, new PartitionKey(taskCode));
  166. if (response.Status == 200) {
  167. CourseTask courseTask=JsonDocument.Parse(response.Content).RootElement.ToObject<CourseTask>();
  168. }
  169. return Ok(new { studyYear, semesterId, });
  170. }
  171. else
  172. {
  173. }
  174. break;
  175. }
  176. case bool when $"{grant_type}".Equals("insert-task", StringComparison.OrdinalIgnoreCase) :
  177. {
  178. if ( !request.TryGetProperty("scope", out JsonElement _scope))
  179. {
  180. return BadRequest();
  181. }
  182. string tbname = $"{_scope}".Equals("school", StringComparison.OrdinalIgnoreCase) ? Constant.School : Constant.Teacher;
  183. break;
  184. }
  185. //按照模板导入进行数据转换并且进行检查
  186. case bool when ($"{grant_type}".Equals("import-check") && $"{scope}".Equals("school", StringComparison.OrdinalIgnoreCase)):
  187. {
  188. //检查完成,生成一个检查通过的token+检查结果(pass,warn,error), 在正式导入的时候,只需要检查token是否存在则进行数据保存。 以确保每次被导入的数据都是检查通过的。
  189. //并标记相关检查状态对于的具体数值。
  190. //数据转换是必须的,可选是否开启数据检查,数据检查包括导入数据自检(逻辑,排他,教室-名单-教师-时间段,重复),导入数据与数据库数据库的比对检查。
  191. //课程 批量升学年 学期.
  192. if (!request.TryGetProperty("courseCheckImports", out JsonElement _courseCheckImports)) return BadRequest();
  193. if (!request.TryGetProperty("periodId", out JsonElement _periodId)) return BadRequest();
  194. request.TryGetProperty("majorId", out JsonElement _majorId) ;
  195. School schoolBase = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(school, new PartitionKey("Base"));
  196. var period = schoolBase.period.Find(x => x.id.Equals($"{_periodId}"));
  197. if (period == null) {
  198. return Ok(new { code = 1, msg = "学段不存在!" });
  199. }
  200. List<CourseCheckImport> courseCheckImports= _courseCheckImports.ToObject<List<CourseCheckImport>>();
  201. //数据检查
  202. //1.检查导入的课程名称是否有效
  203. StringBuilder sqlName = new StringBuilder(" select value c from c ");
  204. sqlName.Append($" where c.name in({string.Join(",", courseCheckImports.Select(z=>$"'{z.name}'"))}) and c.period.id='{_periodId}' ");
  205. if (!string.IsNullOrWhiteSpace($"{_majorId}"))
  206. {
  207. var major = period.majors.Find(z => z.id.Equals($"{_majorId}"));
  208. if (major==null) {
  209. return Ok(new { code = 2, msg = "专业不存在!" });
  210. }
  211. sqlName.Append($" and c.major.id='{_majorId}'");
  212. }
  213. List<CourseBase> courseBases = new List<CourseBase>() ;
  214. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
  215. .GetItemQueryIterator<CourseBase>(queryText: sqlName.ToString(), requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"CourseBase-{school}") }))
  216. {
  217. courseBases.Add(item);
  218. }
  219. HashSet<CourseCheckImport> courseInvalidImports = new HashSet<CourseCheckImport>();
  220. var nameInvalidImports = courseCheckImports.ExceptBy(courseBases.Select(x => x.name),z=>z.name);
  221. //保留课程名称存在的排课信息
  222. if (nameInvalidImports != null && nameInvalidImports.Any())
  223. {
  224. foreach (var nameInvalidImport in nameInvalidImports)
  225. {
  226. nameInvalidImport.invalidCode =1;
  227. courseInvalidImports.Add(nameInvalidImport);
  228. }
  229. courseCheckImports.RemoveAll(z=> nameInvalidImports.Contains(z));
  230. }
  231. //2.检查导入的醍摩豆教师ID是否有效
  232. StringBuilder sqlTmdid = new StringBuilder(" select c.id,c.name ,c.code ,c.picture from c ");
  233. sqlTmdid.Append($" where c.id in({string.Join(",", courseCheckImports.Select(z => $"'{z.tmdid}'"))}) ");
  234. List<IdNameCode> teachers = new List<IdNameCode>();
  235. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
  236. .GetItemQueryIterator<IdNameCode>(queryText: sqlTmdid.ToString(), requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
  237. {
  238. teachers.Add(item);
  239. }
  240. var tmdidInvalidImports = courseCheckImports.ExceptBy(teachers.Select(x => x.id), z => z.tmdid);
  241. //保留课程名称存在的及醍摩豆ID有效的排课信息
  242. if (tmdidInvalidImports != null && tmdidInvalidImports.Any())
  243. {
  244. foreach (var tmdidInvalidImport in tmdidInvalidImports)
  245. {
  246. tmdidInvalidImport.invalidCode = 2;
  247. courseInvalidImports.Add(tmdidInvalidImport);
  248. }
  249. courseCheckImports.RemoveAll(z => tmdidInvalidImports.Contains(z));
  250. }
  251. //3.检查导入的教学班名称是否有效
  252. IEnumerable<CourseCheckImport> teachInvalidImports = null;
  253. List<GroupList> groupLists = new List<GroupList>();
  254. var teachList = courseCheckImports.Where(x => x.type.Equals("teach"));
  255. if (teachList.Any() && teachList.Count()>0) {
  256. StringBuilder sqlTeach = new StringBuilder(" select value c from c ");
  257. sqlTeach.Append($" where c.name in({string.Join(",", teachList.Select(z => $"'{z.list}'"))}) ");
  258. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
  259. .GetItemQueryIterator<GroupList>(queryText: sqlTeach.ToString(), requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"GroupList-{school}") }))
  260. {
  261. groupLists.Add(item);
  262. }
  263. teachInvalidImports = courseCheckImports.ExceptBy(groupLists.Select(x => x.name), z => z.list);
  264. //保留课程名称存在的及醍摩豆ID有效的排课信息
  265. if (teachInvalidImports != null && teachInvalidImports.Any())
  266. {
  267. foreach (var teachInvalidImport in teachInvalidImports)
  268. {
  269. teachInvalidImport.invalidCode = 3;
  270. courseInvalidImports.Add(teachInvalidImport);
  271. }
  272. courseCheckImports.RemoveAll(z => teachInvalidImports.Contains(z));
  273. }
  274. }
  275. //4.检查导入的教室编号是否有效
  276. //获取填写了教室编号的数据
  277. var roomNos= courseCheckImports.Where(z => !string.IsNullOrWhiteSpace(z.roomNo));
  278. IEnumerable<CourseCheckImport> roomNoInvalidImports = null;
  279. List<Room> rooms = new List<Room>();
  280. if (roomNos.Any() && roomNos.Count() > 0)
  281. {
  282. StringBuilder sqlRoom = new StringBuilder(" select value c from c ");
  283. sqlRoom.Append($" where c.no in({string.Join(",", roomNos.Select(z => $"'{z.roomNo}'"))}) ");
  284. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
  285. .GetItemQueryIterator<Room>(queryText: sqlRoom.ToString(), requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Room-{school}") }))
  286. {
  287. rooms.Add(item);
  288. }
  289. roomNoInvalidImports = courseCheckImports.ExceptBy(rooms.Select(x => x.no), z => z.roomNo);
  290. //保留课程名称存在的及醍摩豆ID有效的排课信息
  291. if (roomNoInvalidImports != null && roomNoInvalidImports.Any())
  292. {
  293. foreach (var roomNoInvalidImport in roomNoInvalidImports)
  294. {
  295. roomNoInvalidImport.invalidCode = 4;
  296. courseInvalidImports.Add(roomNoInvalidImport);
  297. }
  298. courseCheckImports.RemoveAll(z => roomNoInvalidImports.Contains(z));
  299. }
  300. }
  301. //5.检查开学日期,行政班编号是否有效
  302. //List<CourseCheckImport> stimeInvalidImports = new List<CourseCheckImport>() ;
  303. //List<CourseCheckImport> etimeInvalidImports = new List<CourseCheckImport>();
  304. //List<CourseCheckImport> scheduleInvalidImports = new List<CourseCheckImport>();
  305. //List<CourseCheckImport> classIdNoInvalidImports = new List<CourseCheckImport>();
  306. Dictionary<string,List<Class>> duplicateClasses= new Dictionary<string, List<Class>>();
  307. var timeTables = period.timetable.Where(z => z.type.Equals("1")).ToList();
  308. HashSet< CourseTask > courseTasks = new HashSet<CourseTask>();
  309. int checkedCount = 0;
  310. foreach (var item in courseCheckImports)
  311. {
  312. DateTimeOffset sdateTime = default;
  313. DateTimeOffset edateTime = default;
  314. //5.1.检查开学日期格式是否正确
  315. if (!DateTimeOffset.TryParseExact(item.stime, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out sdateTime))
  316. {
  317. item.invalidCode = 5;
  318. courseInvalidImports.Add(item);
  319. continue;
  320. }
  321. //获取当前学年,当前学期,当前导入时间的日期,以及下学期开学时间
  322. (Semester currSemester, int studyYear, DateTimeOffset date, DateTimeOffset nextSemester) info = SchoolService.GetSemester(period, item.stime);
  323. if (info.currSemester != null)
  324. {
  325. //5.2检查课程结束日期格式是否正确
  326. if (!string.IsNullOrWhiteSpace(item.etime))
  327. {
  328. if (!DateTimeOffset.TryParseExact(item.etime, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out edateTime))
  329. {
  330. item.invalidCode = 6;
  331. courseInvalidImports.Add(item);
  332. continue;
  333. }
  334. }
  335. else
  336. {
  337. //未设置课程结束时间,开学前一天
  338. edateTime = info.nextSemester.AddDays(-1);
  339. }
  340. }
  341. else {
  342. //15.根据开学时间无法获取学期信息
  343. item.invalidCode = 15;
  344. courseInvalidImports.Add(item);
  345. continue;
  346. }
  347. ScheduleTime scheduleTime = null;
  348. //5.3检查排课字段格式,数据是否符合要求
  349. if (!string.IsNullOrWhiteSpace(item.schedule)) {
  350. string[] datas= item.schedule.Split('-');
  351. if (datas.Length >= 3) {
  352. int timeIndex = -1;
  353. int weekIndex = -1;
  354. string mode =string.Empty;
  355. if (int.TryParse(datas[0], out timeIndex) && timeIndex > 0
  356. && int.TryParse(datas[1], out weekIndex) && weekIndex > 0
  357. && (datas[2].Equals("A", StringComparison.OrdinalIgnoreCase) || datas[2].Equals("D", StringComparison.OrdinalIgnoreCase) || datas[2].Equals("C", StringComparison.OrdinalIgnoreCase)))
  358. {
  359. mode = datas[2];
  360. HashSet<int> weekIndexs = new HashSet<int>();
  361. if (mode.Equals("C"))
  362. {
  363. if (datas.Length == 4)
  364. {
  365. var customWeeks = datas[3].Split(',');
  366. bool hasInvalidData = false;
  367. HashSet<int> weeks = new HashSet<int>();
  368. foreach (var customWeek in customWeeks)
  369. {
  370. if (int.TryParse(customWeek, out int customWeekIndex) && customWeekIndex > 0)
  371. {
  372. weeks.Add(customWeekIndex);
  373. }
  374. else {
  375. hasInvalidData = true;
  376. break;
  377. }
  378. }
  379. if (hasInvalidData)
  380. {
  381. //C 自定义模式下,配置的上课周是大于等于1的整数
  382. item.invalidCode = 11;
  383. courseInvalidImports.Add(item);
  384. continue;
  385. }
  386. else {
  387. weekIndexs = weeks;
  388. }
  389. }
  390. else {
  391. //C 自定义模式下,需要配置对应的上课周
  392. item.invalidCode = 10;
  393. courseInvalidImports.Add(item);
  394. continue;
  395. }
  396. }
  397. scheduleTime = new ScheduleTime();
  398. try {
  399. var timeTable = timeTables[timeIndex-1];
  400. scheduleTime.id= timeTable.id;
  401. }
  402. catch (Exception ex)
  403. {
  404. //数组越界,表示导入的不存在,没有对应的上课时间段
  405. item.invalidCode = 8;
  406. courseInvalidImports.Add(item);
  407. continue;
  408. }
  409. try
  410. {
  411. var week = weekDays[weekIndex - 1];
  412. scheduleTime.week = week;
  413. }
  414. catch (Exception ex)
  415. {
  416. //数组越界,表示导入的不存在
  417. //上课时间不在星期一至星期日
  418. item.invalidCode = 9;
  419. courseInvalidImports.Add(item);
  420. continue;
  421. }
  422. scheduleTime.mode= mode;
  423. scheduleTime.index = weekIndexs;
  424. }
  425. else {
  426. //不满足最基本的1-1-A格式,可能是不是数字,或者不是A,D,C模式,
  427. //排课时间格式不满足[1-n]-[1|2|3|4|5|6|7]-[A|D|C]
  428. item.invalidCode = 7;
  429. courseInvalidImports.Add(item);
  430. continue;
  431. }
  432. }
  433. else
  434. {
  435. //不满足最基本的1-1-A格式
  436. //排课时间格式不满足[1-n]-[1|2|3|4|5|6|7]-[A|D|C]
  437. item.invalidCode = 7;
  438. courseInvalidImports.Add(item);
  439. continue;
  440. }
  441. }
  442. string groupId = string.Empty;
  443. //5.4 检查导入的行政班编号是否有效
  444. if (item.type.Equals("class"))
  445. {
  446. var yearNo = item.list.Split("-");
  447. if (yearNo.Length == 2)
  448. {
  449. StringBuilder sqlYearNo = new StringBuilder(" select value c from c ");
  450. sqlYearNo.Append($" where c.year ={yearNo[0]} and c.no ='{yearNo[1]}' and c.periodId='{period.id}' ");
  451. List<Class> classes = new List<Class>();
  452. await foreach (var classInfo in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
  453. .GetItemQueryIterator<Class>(queryText: sqlYearNo.ToString(), requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Class-{school}") }))
  454. {
  455. classes.Add(classInfo);
  456. }
  457. if (classes.Count > 1)
  458. {
  459. ///班级入学年-编号重复的班级
  460. duplicateClasses.Add(item.list, classes);
  461. //导入的班级入学年-编号在系统中重复,请检查行政班设置。
  462. item.invalidCode = 13;
  463. courseInvalidImports.Add(item);
  464. continue;
  465. }
  466. else if (classes.Count <= 0)
  467. {
  468. //班级入学年-编号不存在
  469. item.invalidCode = 12;
  470. courseInvalidImports.Add(item);
  471. continue;
  472. }
  473. else
  474. {
  475. Class @class = classes[0];
  476. groupId = @class.id;
  477. }
  478. }
  479. else
  480. {
  481. courseInvalidImports.Add(item);
  482. //导入的班级入学年-编号格式错误
  483. item.invalidCode = 14;
  484. continue;
  485. }
  486. }
  487. else {
  488. var groupList= groupLists.Find(z => z.name.Equals(item.list));
  489. groupId=groupList?.id;
  490. }
  491. Room room = rooms.Find(z =>!string.IsNullOrWhiteSpace(item.roomNo) && z.no.Equals(item.roomNo));
  492. string roomId= room?.id;
  493. string teacherId = teachers.Find(z => z.id.Equals(item.tmdid))?.id;
  494. CourseBase courseBase = courseBases.Find(z => z.name.Equals(item.name));
  495. string taskId = $"{info.studyYear}-{info.currSemester.id}";
  496. string taskCode = $"CourseTask-{school}-{courseBase.id}";
  497. CourseTask courseTask = courseTasks.FirstOrDefault(z => z.id.Equals(taskId) && z.code.Equals(taskCode));
  498. if (courseTask == null) {
  499. Azure.Response courseTaskResponse = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync(taskId, new PartitionKey(taskCode));
  500. if (courseTaskResponse.Status == 200) {
  501. courseTask = JsonDocument.Parse(courseTaskResponse.Content).RootElement.ToObject<CourseTask>();
  502. }
  503. }
  504. if (courseTask == null)
  505. {
  506. courseTask = new CourseTask()
  507. {
  508. id = taskId,
  509. code = taskCode,
  510. expire = edateTime.ToUnixTimeMilliseconds(),
  511. pk = "CourseTask",
  512. ttl = -1,
  513. courseId = courseBase.id,
  514. year = info.studyYear,
  515. semesterId = info.currSemester.id,
  516. schedules = new List<ScheduleTask>
  517. {
  518. new ScheduleTask()
  519. {
  520. roomId=roomId,
  521. groupId=groupId,
  522. type=item.type,
  523. teacherId=teacherId,
  524. times= new List<ScheduleTime> { scheduleTime }
  525. }
  526. }
  527. };
  528. courseTasks.Add(courseTask);
  529. }
  530. else {
  531. var scheduleTask= courseTask.schedules.Find(z => z.type.Equals(item.type) && z.groupId.Equals(groupId) && z.teacherId.Equals(teacherId));
  532. if (scheduleTask == null)
  533. {
  534. courseTask.schedules.Add(new ScheduleTask()
  535. {
  536. roomId = roomId,
  537. groupId = groupId,
  538. type = item.type,
  539. teacherId = teacherId,
  540. times = new List<ScheduleTime> { scheduleTime }
  541. });
  542. }
  543. else {
  544. scheduleTask.roomId = roomId;
  545. if (scheduleTime != null) {
  546. var shtime = scheduleTask.times.Find(z => z.id.Equals(scheduleTime.id) && z.week.Equals(scheduleTime.week) && z.mode.Equals(scheduleTime.mode));
  547. if (shtime == null)
  548. {
  549. scheduleTask.times.Add(scheduleTime);
  550. }
  551. else {
  552. if (scheduleTime.index.Any())
  553. {
  554. foreach (var ind in scheduleTime.index) {
  555. shtime.index.Add(ind);
  556. }
  557. }
  558. }
  559. }
  560. }
  561. }
  562. checkedCount++;
  563. }
  564. //生成检查结果token,有效期5分钟
  565. string checkToken=$"CourseTask:CheckToken:{scope}:{school}:{Guid.NewGuid()}" ;
  566. await _azureRedis.GetRedisClient(8).StringSetAsync(checkToken, courseTasks.ToJsonString(),expiry:new TimeSpan(0,5,0));
  567. return Ok(new { courseCheckedImports = courseTasks , checkedCount, invalidCount= courseInvalidImports.Count, courseInvalidImports, checkToken });
  568. }
  569. case bool when $"{grant_type}".Equals("import-task", StringComparison.OrdinalIgnoreCase) && $"{scope}".Equals("school", StringComparison.OrdinalIgnoreCase):
  570. {
  571. request.TryGetProperty("checkToken", out JsonElement _checkToken);
  572. if (!string.IsNullOrWhiteSpace($"{_checkToken}") && $"{_checkToken}".StartsWith($"CourseTask:CheckToken:{scope}:{school}:"))
  573. {
  574. RedisValue value = await _azureRedis.GetRedisClient(8).StringGetAsync($"{_checkToken}");
  575. List<CourseTask> courseTasks = value.ToString().ToObject<List<CourseTask>>();
  576. if (courseTasks.IsNotEmpty())
  577. {
  578. foreach (var task in courseTasks)
  579. {
  580. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).UpsertItemAsync(task, new PartitionKey(task.code));
  581. }
  582. return Ok(new { code=200 });
  583. }
  584. }
  585. return BadRequest();
  586. }
  587. }
  588. } catch (Exception ex) {
  589. await _dingDing.SendBotMsg($"{_option.Location},课程处理异常,{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  590. }
  591. return Ok();
  592. }
  593. }
  594. }