CourseController.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. using Microsoft.AspNetCore.Mvc;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using TEAMModelOS.Models;
  7. using TEAMModelOS.SDK;
  8. using TEAMModelOS.SDK.DI;
  9. using System.Text.Json;
  10. using TEAMModelOS.SDK.Models;
  11. using TEAMModelOS.SDK.Extension;
  12. using Azure.Cosmos;
  13. using Microsoft.AspNetCore.Http;
  14. using Microsoft.Extensions.Options;
  15. using System.IO;
  16. using System.Dynamic;
  17. using System.Net.Http;
  18. using System.Net;
  19. using Newtonsoft.Json;
  20. using System.Linq;
  21. using StackExchange.Redis;
  22. using static TEAMModelOS.SDK.Models.Teacher;
  23. using Microsoft.Extensions.Configuration;
  24. using TEAMModelOS.Filter;
  25. using Microsoft.AspNetCore.Authorization;
  26. using HTEXLib.COMM.Helpers;
  27. using TEAMModelOS.SDK.Models.Service;
  28. using System.ComponentModel.DataAnnotations;
  29. namespace TEAMModelAPI.Controllers
  30. {
  31. [ProducesResponseType(StatusCodes.Status200OK)]
  32. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  33. [ApiController]
  34. [Route("school")]
  35. public class CourseController : ControllerBase
  36. {
  37. public AzureCosmosFactory _azureCosmos;
  38. private readonly AzureStorageFactory _azureStorage;
  39. private readonly AzureRedisFactory _azureRedis;
  40. private readonly DingDing _dingDing;
  41. private readonly Option _option;
  42. private readonly IConfiguration _configuration;
  43. private readonly CoreAPIHttpService _coreAPIHttpService;
  44. private readonly AzureServiceBusFactory _serviceBus;
  45. //1 2 3 4 5 6 7
  46. private List<string> weekDays = new List<string> { "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN" };
  47. public CourseController(CoreAPIHttpService coreAPIHttpService, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration, AzureServiceBusFactory serviceBus)
  48. {
  49. _azureCosmos = azureCosmos;
  50. _azureStorage = azureStorage;
  51. _azureRedis = azureRedis;
  52. _dingDing = dingDing;
  53. _option = option?.Value;
  54. _configuration = configuration;
  55. _coreAPIHttpService = coreAPIHttpService;
  56. _serviceBus = serviceBus;
  57. }
  58. /// <summary>
  59. /// 获取指定学段作息
  60. /// </summary>
  61. /// <param name="request"></param>
  62. /// <returns></returns>
  63. [ProducesDefaultResponseType]
  64. [HttpPost("get-period-timetable")]
  65. [ApiToken(Auth = "1301", Name = "试卷和评测的条件信息", RW = "R", Limit = false)]
  66. public async Task<IActionResult> GetPaperExamCondition(JsonElement json)
  67. {
  68. json.TryGetProperty("periodId", out JsonElement _periodId);
  69. var (id, school) = HttpContext.GetApiTokenInfo();
  70. School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
  71. var period = data.period.Find(x => x.id.Equals($"{_periodId}"));
  72. if (period != null)
  73. {
  74. return Ok(new { period.subjects, period.timetable, period.grades, period.majors , weekDays });
  75. }
  76. else
  77. {
  78. return Ok(new { error = 1, msg = "学段不存在!" });
  79. }
  80. }
  81. [ProducesDefaultResponseType]
  82. [HttpPost("upsert-course-info")]
  83. [ApiToken(Auth = "1302", Name = "课程详细信息", RW = "W", Limit = false)]
  84. public async Task<IActionResult> UpsertCourseInfo(JsonElement json)
  85. {
  86. var (id, school) = HttpContext.GetApiTokenInfo();
  87. if (!json.TryGetProperty("course", out JsonElement _course)) { return Ok(new { error = 1, msg = "课程对象不存在" }); }
  88. var courseDto = _course.ToObject<CourseDto>();
  89. Course course = null;
  90. if (courseDto != null && courseDto.Valid().isVaild) {
  91. School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
  92. var period = data.period.Find(x => x.id.Equals($"{courseDto.periodId}"));
  93. if (period != null)
  94. {
  95. var subject = period.subjects.Find(x => x.id.Equals($"{courseDto.subjectId}"));
  96. if (subject != null)
  97. {
  98. if (string.IsNullOrWhiteSpace(courseDto?.id))
  99. {
  100. course = new Course
  101. {
  102. pk = "Course",
  103. id = Guid.NewGuid().ToString(),
  104. code = $"Course-{school}",
  105. name = courseDto.name,
  106. subject = new SubjectSimple { id = subject.id, name = subject.name },
  107. period = new PeriodSimple { id = period.id, name = period.name },
  108. school = school,
  109. desc = courseDto.desc,
  110. scope = "school",
  111. no = courseDto.no,
  112. };
  113. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(course, new PartitionKey(course.code));
  114. }
  115. else
  116. {
  117. Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{course.id}", new PartitionKey($"Course-{school}"));
  118. if (response.Status == 200)
  119. {
  120. JsonDocument jsonDocument = JsonDocument.Parse(response.Content);
  121. course = jsonDocument.RootElement.ToObject<Course>();
  122. course.pk = "Course";
  123. course.name = string.IsNullOrWhiteSpace(courseDto.name) ? course.name : courseDto.name;
  124. course.subject = new SubjectSimple { id = subject.id, name = subject.name };
  125. course.period = new PeriodSimple { id = period.id, name = period.name };
  126. course.school = school;
  127. course.desc = string.IsNullOrWhiteSpace(courseDto.desc) ? course.desc : courseDto.desc;
  128. course.scope = "school";
  129. course.no = string.IsNullOrWhiteSpace(courseDto.no) ? course.no : courseDto.no;
  130. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(course,course.id, new PartitionKey(course.code));
  131. }
  132. else {
  133. course = new Course
  134. {
  135. pk = "Course",
  136. id = Guid.NewGuid().ToString(),
  137. code = $"Course-{school}",
  138. name = courseDto.name,
  139. subject = new SubjectSimple { id = subject.id, name = subject.name },
  140. period = new PeriodSimple { id = period.id, name = period.name },
  141. school = school,
  142. desc = courseDto.desc,
  143. scope = "school",
  144. no = courseDto.no,
  145. };
  146. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(course, new PartitionKey(course.code));
  147. }
  148. }
  149. return Ok(new { period.subjects, period.timetable, course = course });
  150. }
  151. else {
  152. return Ok(new { error =4, msg = "科目不存在!" });
  153. }
  154. }
  155. else
  156. {
  157. return Ok(new { error = 2, msg = "学段不存在!" });
  158. }
  159. }
  160. else
  161. {
  162. return Ok(new { error = 3, msg = courseDto.Valid() });
  163. }
  164. }
  165. public class IptCourse {
  166. public string courseId { get; set; }
  167. public List<Schedule> schedules { get; set; }
  168. }
  169. [ProducesDefaultResponseType]
  170. [HttpPost("upsert-course-schedule")]
  171. [ApiToken(Auth = "1302", Name = "更新课程的排课信息", RW = "W", Limit = false)]
  172. public async Task<IActionResult> UpsertCourseSchedule(JsonElement json)
  173. {
  174. var (id, school) = HttpContext.GetApiTokenInfo();
  175. if (!json.TryGetProperty("courses", out JsonElement _courses)) { return Ok(new { error = 1, msg = "课程参数错误!" }); }
  176. IEnumerable<IptCourse> iptcourses= _courses.ToObject<List<IptCourse>>();
  177. var result = iptcourses.Valid();
  178. if (!result.isVaild) {
  179. return Ok(new { error = 2, msg =result});
  180. }
  181. HashSet<string> courseIds= iptcourses.Select(x => x.courseId).ToHashSet();
  182. if (courseIds.Count < 1) { return Ok(new { error = 1, msg = "课程参数错误!" }); }
  183. //string sql = $"select value(c) from c where c.id in({string.Join(",",courseIds.Select(x=>$"'{x}'"))})";
  184. string sql = $"select value(c) from c ";//直接获取全校的课程
  185. List<Course> courses = new List<Course>();
  186. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
  187. .GetItemQueryIterator<Course>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Course-{school}") })) {
  188. courses.Add(item);
  189. }
  190. //不存在的课程
  191. var notInCourseIds= courseIds.Except(courses.Select(x => x.id));
  192. iptcourses=iptcourses.Where(x => !notInCourseIds.Contains(x.courseId));
  193. //排查 课程学段,课程排课作息,课程排课的星期几是否准确
  194. List<ScheduleDto> import_schedules = new List<ScheduleDto>() ;
  195. //保存没有选用名单的排课。
  196. List<Schedule> schedules_noList= new List<Schedule>() ;
  197. List<ScheduleDto> import_weeksConfuse = new List<ScheduleDto>();
  198. iptcourses.ToList().ForEach(x => {
  199. x.schedules.ForEach(z => {
  200. if (!string.IsNullOrWhiteSpace(z.classId) || !string.IsNullOrWhiteSpace(z.stulist))
  201. {
  202. string classId = null;
  203. //行政班不为空,教学班为空,则名单取行政班
  204. classId = !string.IsNullOrWhiteSpace(z.classId) && string.IsNullOrWhiteSpace(z.stulist) ? z.classId : classId;
  205. //行政班为空,教学班不为空,则名单取教学班
  206. classId = string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) ? z.stulist : classId;
  207. //行政班,教学班都不为空,且相同,则任取一个,取的是行政班
  208. classId = !string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) && z.classId.Equals(z.stulist) ? z.classId : classId;
  209. //行政班,教学班都不为空,且不同,则取null
  210. classId = !string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) && !z.classId.Equals(z.stulist) ? null : classId;
  211. if (!string.IsNullOrWhiteSpace(classId))
  212. {
  213. z.time.ForEach(t =>
  214. {
  215. ScheduleDto scheduleDto = new ScheduleDto
  216. {
  217. courseId = x.courseId,
  218. roomId = z.room,
  219. classId = z.classId,
  220. stulist = z.stulist,
  221. teacherId = z.teacherId,
  222. timeId = t.id,
  223. week = t.week,
  224. keyTeacher = $"{z.teacherId}_{t.week}_{t.id}",
  225. keyGroupId = $"{classId}_{t.week}_{t.id}",
  226. keyRoomIds = string.IsNullOrWhiteSpace(z.room) ? null : $"{z.room}_{t.week}_{t.id}"
  227. };
  228. //星期几自检 1 2 3 4 5 6 7
  229. if (weekDays.Contains(t.week))
  230. {
  231. import_schedules.Add(scheduleDto);
  232. }
  233. else {
  234. import_weeksConfuse.Add(scheduleDto);
  235. }
  236. });
  237. }
  238. else { schedules_noList.Add(z); }
  239. }
  240. else {
  241. schedules_noList.Add(z);
  242. }
  243. });
  244. });
  245. //导入的排课自检。
  246. //教师自检
  247. var check_teacher = import_schedules.GroupBy(x => x.keyTeacher).Select(g => new { key = g.Key, list = g.ToList() });
  248. IEnumerable<ScheduleDto> import_teacherConfuse = new List<ScheduleDto>();
  249. import_teacherConfuse = check_teacher.Where(x => x.list.Count > 1).SelectMany(x => x.list);
  250. import_schedules.RemoveAll(x => import_teacherConfuse.Contains(x));
  251. //名单自检
  252. var check_groupId = import_schedules.GroupBy(x => x.keyGroupId).Select(g => new { key = g.Key, list = g.ToList() });
  253. IEnumerable<ScheduleDto> import_groupIdConfuse = new List<ScheduleDto>();
  254. import_groupIdConfuse = check_groupId.Where(x => x.list.Count > 1).SelectMany(x => x.list);
  255. import_schedules.RemoveAll(x => import_groupIdConfuse.Contains(x));
  256. //物理教室自检
  257. var check_roomIds = import_schedules.Where(r=>!string.IsNullOrWhiteSpace(r.keyRoomIds)).GroupBy(x => x.keyRoomIds).Select(g => new { key = g.Key, list = g.ToList() });
  258. IEnumerable<ScheduleDto> import_roomIdsConfuse = new List<ScheduleDto>();
  259. import_roomIdsConfuse = check_roomIds.Where(x => x.list.Count > 1).SelectMany(x => x.list);
  260. import_schedules.RemoveAll(x => import_roomIdsConfuse.Contains(x));
  261. //打散数据库已经有的排课信息
  262. List<ScheduleDto> database_schedules = new List<ScheduleDto>();
  263. courses.ForEach(x => {
  264. x.schedule.ForEach(z => {
  265. if (!string.IsNullOrWhiteSpace(z.teacherId) &&(!string.IsNullOrWhiteSpace(z.classId) || !string.IsNullOrWhiteSpace(z.stulist)))
  266. {
  267. string classId = null;
  268. //行政班不为空,教学班为空,则名单取行政班
  269. classId = !string.IsNullOrWhiteSpace(z.classId) && string.IsNullOrWhiteSpace(z.stulist) ? z.classId : classId;
  270. //行政班为空,教学班不为空,则名单取教学班
  271. classId = string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) ? z.stulist : classId;
  272. //行政班,教学班都不为空,且相同,则任取一个,取的是行政班
  273. classId = !string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) && z.classId.Equals(z.stulist) ? z.classId : classId;
  274. //行政班,教学班都不为空,且不同,则取null
  275. classId = !string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) && !z.classId.Equals(z.stulist) ? null : classId;
  276. if (!string.IsNullOrWhiteSpace(classId))
  277. {
  278. z.time.ForEach(t =>
  279. {
  280. ScheduleDto scheduleDto = new ScheduleDto
  281. {
  282. courseId = x.id,
  283. roomId = z.room,
  284. classId = z.classId,
  285. stulist = z.stulist,
  286. teacherId = z.teacherId,
  287. timeId = t.id,
  288. week = t.week,
  289. keyTeacher = $"{z.teacherId}_{t.week}_{t.id}",
  290. keyGroupId = $"{classId}_{t.week}_{t.id}",
  291. keyRoomIds = string.IsNullOrWhiteSpace(z.room) ? null : $"{z.room}_{t.week}_{t.id}"
  292. };
  293. database_schedules.Add(scheduleDto);
  294. });
  295. }
  296. }
  297. });
  298. });
  299. List<ScheduleDto> database_teacherConfuse = new List<ScheduleDto>();
  300. List<ScheduleDto> database_groupIdConfuse = new List<ScheduleDto>();
  301. List<ScheduleDto> database_roomIdsConfuse = new List<ScheduleDto>();
  302. import_schedules.ForEach(x => {
  303. //检查教师的排课是否冲突
  304. if (database_schedules.FindAll(s => s.keyTeacher.Equals(x.keyTeacher)).IsNotEmpty())
  305. {
  306. database_teacherConfuse.Add(x);
  307. }
  308. //检查名单的排课是否冲突
  309. if (database_schedules.FindAll(s => s.keyGroupId.Equals(x.keyGroupId)).IsNotEmpty())
  310. {
  311. database_groupIdConfuse.Add(x);
  312. }
  313. //检查教室的排课是否冲突
  314. if (database_schedules.FindAll(s => s.keyRoomIds.Equals(x.keyRoomIds)).IsNotEmpty())
  315. {
  316. database_roomIdsConfuse.Add(x);
  317. }
  318. });
  319. //移除 教师,名单,教室冲突的排课
  320. import_schedules.RemoveAll(x => database_teacherConfuse.Contains(x));
  321. import_schedules.RemoveAll(x => database_groupIdConfuse.Contains(x));
  322. import_schedules.RemoveAll(x => database_roomIdsConfuse.Contains(x));
  323. //最终导入之前,必须检查,课程是否存在(notInCourseIds),教师是否存在,名单是否存在,并重新排列行政班,教学班,
  324. //排课时间段id是否正确,星期几是否正确(import_weeksConfuse),教室是否正确
  325. School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
  326. //检查教师存在的
  327. HashSet<string> teachers = import_schedules.Select(x => x.teacherId).ToHashSet();
  328. if (teachers.Count > 0) {
  329. }
  330. //检查教师存在的
  331. HashSet<string> roomIds = import_schedules.Select(x => x.roomId).ToHashSet();
  332. if (roomIds.Count > 0)
  333. {
  334. }
  335. //检查名单存在的
  336. List<string> groupIds = new List<string>();
  337. var classIds = import_schedules.Where(x => !string.IsNullOrWhiteSpace(x.classId)).Select(x => x.classId).ToHashSet();
  338. if (classIds.Any()) {
  339. groupIds.AddRange(classIds);
  340. }
  341. var stulists = import_schedules.Where(x => !string.IsNullOrWhiteSpace(x.stulist)).Select(x => x.stulist).ToHashSet();
  342. if (stulists.Any())
  343. {
  344. groupIds.AddRange(stulists);
  345. }
  346. return Ok(new {
  347. import_check= new {
  348. import_groupIdConfuse,//名单冲突的排课
  349. import_roomIdsConfuse,//物理教室冲突的排课
  350. import_teacherConfuse,//教室冲突的排课
  351. import_weeksConfuse },//错误的星期几编码
  352. database_check= new { },
  353. });
  354. }
  355. [ProducesDefaultResponseType]
  356. [HttpPost("get-course-list")]
  357. [ApiToken(Auth = "1303", Name = "获取课程列表信息", RW = "R", Limit = false)]
  358. public async Task<IActionResult> GetCourseList(JsonElement json)
  359. {
  360. var client = _azureCosmos.GetCosmosClient();
  361. var (id, school) = HttpContext.GetApiTokenInfo();
  362. json.TryGetProperty("periodId", out JsonElement periodId);
  363. json.TryGetProperty("subjectId", out JsonElement subjectId);
  364. StringBuilder sql = new StringBuilder($"SELECT c.id,c.name,c.subject,c.period,c.scope,c.no,c.school FROM c where 1=1 ");
  365. if (!string.IsNullOrWhiteSpace($"{periodId}"))
  366. {
  367. sql.Append($" and c.period.id='{periodId}'");
  368. }
  369. if (!string.IsNullOrWhiteSpace($"{subjectId}"))
  370. {
  371. sql.Append($" and c.subject.id='{subjectId}'");
  372. }
  373. List<dynamic> courses = new List<dynamic>();
  374. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
  375. GetItemQueryIterator<dynamic>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{school}") }))
  376. {
  377. courses.Add(item);
  378. }
  379. return Ok(new { courses });
  380. }
  381. [ProducesDefaultResponseType]
  382. [HttpPost("get-course-info")]
  383. [ApiToken(Auth = "1304", Name = "课程详细信息", RW = "R", Limit = false)]
  384. public async Task<IActionResult> GetCourseInfo(JsonElement json)
  385. {
  386. var (id, school) = HttpContext.GetApiTokenInfo();
  387. json.TryGetProperty("courseId", out JsonElement courseId);
  388. Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School")
  389. .ReadItemStreamAsync($"{courseId}", new PartitionKey($"Course-{school}"));
  390. if (response.Status == 200)
  391. {
  392. JsonDocument document = JsonDocument.Parse(response.Content);
  393. Course course = document.RootElement.Deserialize<Course>();
  394. return Ok(new { course.name, course.id, course.subject, course.period, course.scope, course.school, course.no, course.desc, course.schedule });
  395. }
  396. else
  397. {
  398. return Ok(new { error = 1, msg = "课程不存在!" });
  399. }
  400. }
  401. }
  402. }