CrazyIter_Bin 3 年之前
父节点
当前提交
597d8e5a6b

+ 0 - 2
TEAMModelBI/Controllers/BITest/TestController.cs

@@ -30,10 +30,8 @@ using TEAMModelOS.SDK.Models.Cosmos.Common;
 using TEAMModelOS.SDK.Models.Service;
 using TEAMModelOS.SDK.Models.Table;
 
-using static TEAMModelBI.DI.BIAzureStorage.BIAzureStorageBlobExtensions;
 
 //.Net 6新的特性
-using System.Threading;
 using System.Reflection;
 using System.Numerics;
 using System.Security.Cryptography;

+ 635 - 0
TEAMModelBI/Controllers/OpenApi/Business/CourseController.cs

@@ -0,0 +1,635 @@
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.DI;
+using System.Text.Json;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Extension;
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using System.IO;
+using System.Dynamic;
+using System.Net.Http;
+using System.Net;
+using Newtonsoft.Json;
+using System.Linq;
+using StackExchange.Redis;
+using static TEAMModelOS.SDK.Models.Teacher;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.Filter;
+using Microsoft.AspNetCore.Authorization;
+using HTEXLib.COMM.Helpers;
+using TEAMModelOS.SDK.Models.Service;
+using System.ComponentModel.DataAnnotations;
+
+namespace TEAMModelAPI.Controllers
+{
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    [ApiController]
+    [Route("{scope}")]
+    public class CourseController : ControllerBase
+    {
+        public AzureCosmosFactory _azureCosmos;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly AzureRedisFactory _azureRedis;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly IConfiguration _configuration;
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly AzureServiceBusFactory _serviceBus;
+        //1 2 3 4 5 6 7
+        private List<string> weekDays = new List<string> { "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN" };
+        public CourseController(CoreAPIHttpService coreAPIHttpService, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration, AzureServiceBusFactory serviceBus)
+        {
+            _azureCosmos = azureCosmos;
+            _azureStorage = azureStorage;
+            _azureRedis = azureRedis;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _configuration = configuration;
+            _coreAPIHttpService = coreAPIHttpService;
+            _serviceBus = serviceBus;
+        }
+        [ProducesDefaultResponseType]
+        [HttpPost("get-course-list")]
+        [ApiToken(Auth = "1301", Name = "获取课程列表信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetCourseList(JsonElement json)
+        {
+            var client = _azureCosmos.GetCosmosClient();
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            json.TryGetProperty("periodId", out JsonElement periodId);
+            json.TryGetProperty("subjectId", out JsonElement subjectId);
+            StringBuilder sql = new StringBuilder($"SELECT c.id,c.name,c.subject,c.period,c.scope,c.no,c.school FROM c where 1=1 ");
+            if (!string.IsNullOrWhiteSpace($"{periodId}"))
+            {
+                sql.Append($" and c.period.id='{periodId}'");
+            }
+            if (!string.IsNullOrWhiteSpace($"{subjectId}"))
+            {
+                sql.Append($" and c.subject.id='{subjectId}'");
+            }
+            List<dynamic> courses = new List<dynamic>();
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
+                    GetItemQueryIterator<dynamic>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{school}") }))
+            {
+                courses.Add(item);
+            }
+            return Ok(new { courses });
+        }
+
+        [ProducesDefaultResponseType]
+        [HttpPost("get-course-info")]
+        [ApiToken(Auth = "1302", Name = "课程详细信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetCourseInfo(JsonElement json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            json.TryGetProperty("courseId", out JsonElement courseId);
+            Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School")
+               .ReadItemStreamAsync($"{courseId}", new PartitionKey($"Course-{school}"));
+            if (response.Status == 200)
+            {
+                JsonDocument document = JsonDocument.Parse(response.Content);
+                Course course = document.RootElement.Deserialize<Course>();
+                return Ok(new { course.name, course.id, course.subject, course.period, course.scope, course.school, course.no, course.desc, course.schedule });
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "课程不存在!" });
+            }
+        }
+
+        /// <summary>
+        ///  获取指定学段作息
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-period-timetable")]
+        [ApiToken(Auth = "1303", Name = "试卷和评测的条件信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetPaperExamCondition(JsonElement json)
+        {
+            json.TryGetProperty("periodId", out JsonElement _periodId);
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            var period = data.period.Find(x => x.id.Equals($"{_periodId}"));
+            if (period != null)
+            {
+              
+                return Ok(new { period.subjects, period.timetable, period.grades, period.majors , weekDays });
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "学段不存在!" });
+            }
+        }
+
+
+        [ProducesDefaultResponseType]
+        [HttpPost("upsert-course-infos")]
+        [ApiToken(Auth = "1304", Name = "课程详细信息", RW = "W", Limit = false)]
+        public async Task<IActionResult> UpsertCourseInfo(CourseDtoImpt json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            List<CourseDto> courseDtos = json.courses;
+            List<Dictionary<string, string>> errorData = new List<Dictionary<string, string>>();
+            List<Course> courses = new List<Course>() ;
+             
+            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            foreach (var courseDto in courseDtos) {
+                var period = data.period.Find(x => x.id.Equals($"{courseDto.periodId}"));
+                if (period != null)
+                {
+                    //同名学科
+                    var subject = period.subjects.Find(x => x.id.Equals($"{courseDto.subjectId}"));
+                    if (subject == null) {
+                        subject = period.subjects.Find(x => x.name.Equals($"{courseDto.subjectName}"));
+                    }
+                    if (subject == null) {
+                        subject = new Subject { id = courseDto.subjectId, name = subject.name, type = 1 };
+                        period.subjects.Add(subject);
+                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(data, data.id, new PartitionKey("Base"));
+                    }
+                    Course course = null;
+                    if (string.IsNullOrWhiteSpace(courseDto?.id))
+                    {
+                        course = new Course
+                        {
+                            pk = "Course",
+                            id = Guid.NewGuid().ToString(),
+                            code = $"Course-{school}",
+                            name = courseDto.name,
+                            subject = new SubjectSimple { id = subject.id, name = subject.name },
+                            period = new PeriodSimple { id = period.id, name = period.name },
+                            school = school,
+                            desc = courseDto.desc,
+                            scope = "school",
+                            no = courseDto.no,
+                        };
+                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(course, new PartitionKey(course.code));
+                    }
+                    else
+                    {
+                        Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{course.id}", new PartitionKey($"Course-{school}"));
+                        if (response.Status == 200)
+                        {
+                            JsonDocument jsonDocument = JsonDocument.Parse(response.Content);
+                            course = jsonDocument.RootElement.ToObject<Course>();
+                            course.pk = "Course";
+                            course.name = string.IsNullOrWhiteSpace(courseDto.name) ? course.name : courseDto.name;
+                            course.subject = new SubjectSimple { id = subject.id, name = subject.name };
+                            course.period = new PeriodSimple { id = period.id, name = period.name };
+                            course.school = school;
+                            course.desc = string.IsNullOrWhiteSpace(courseDto.desc) ? course.desc : courseDto.desc;
+                            course.scope = "school";
+                            course.no = string.IsNullOrWhiteSpace(courseDto.no) ? course.no : courseDto.no;
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(course, course.id, new PartitionKey(course.code));
+                        }
+                        else
+                        {
+                            course = new Course
+                            {
+                                pk = "Course",
+                                id = Guid.NewGuid().ToString(),
+                                code = $"Course-{school}",
+                                name = courseDto.name,
+                                subject = new SubjectSimple { id = subject.id, name = subject.name },
+                                period = new PeriodSimple { id = period.id, name = period.name },
+                                school = school,
+                                desc = courseDto.desc,
+                                scope = "school",
+                                no = courseDto.no,
+                            };
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(course, new PartitionKey(course.code));
+                        }
+                    }
+                    if (course != null) { courses.Add(course); }
+                }
+                else
+                {
+                    errorData.Add(new Dictionary<string, string> { { "course", courseDto.name }, { "periodId", courseDto.periodId } });
+                    //return Ok(new { error = 2, msg = "学段不存在!" });
+                }
+            }
+            
+            return Ok(new { courses = courses ,errorData});
+        }
+        //[Required(ErrorMessage = "{0} 课程的科目id必须填写"), RegularExpression(@"[0-9a-zA-Z]{8}(-[0-9a-zA-Z]{4}){3}-[0-9a-zA-Z]{12}",ErrorMessage ="科目的uuid格式错误!")]
+
+        public class ImportCourseDto {
+            public List<ImportCourse> courses { get; set; } = new List<ImportCourse>();
+        }
+
+
+        public class ImportCourse {
+            [Required(ErrorMessage = "课程id  必须设置"), RegularExpression(@"[0-9a-zA-Z]{8}(-[0-9a-zA-Z]{4}){3}-[0-9a-zA-Z]{12}", ErrorMessage = "科目的uuid格式错误!")]
+            public string courseId { get; set; }
+            [Required(ErrorMessage = "课程名称  必须设置")]
+            public string courseName { get; set; }
+            [Required(ErrorMessage = "课程科目id  必须设置"), RegularExpression(@"[0-9a-zA-Z]{8}(-[0-9a-zA-Z]{4}){3}-[0-9a-zA-Z]{12}", ErrorMessage = "科目的uuid格式错误!")]
+            public string subjectId { get; set; }
+            [Required(ErrorMessage = "课程科目名称 必须设置")]
+            public string subjectName { get; set; }
+            [Required(ErrorMessage = "课程学段id  必须设置"), RegularExpression(@"[0-9a-zA-Z]{8}(-[0-9a-zA-Z]{4}){3}-[0-9a-zA-Z]{12}", ErrorMessage = "学段的uuid格式错误!")]
+            public string periodId { get; set; }
+            public List<Schedule> schedules { get; set; }
+        
+        }
+
+        
+        [ProducesDefaultResponseType]
+        [HttpPost("upsert-course-schedule")]
+        [ApiToken(Auth = "1305", Name = "更新课程的排课信息", RW = "W", Limit = false)]
+        public async Task<IActionResult> UpsertCourseSchedule(ImportCourseDto json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            List<ImportCourse> importCourses = json.courses;
+            HashSet<string> courseIds= importCourses .Select(x => x.courseId).ToHashSet();
+            if (courseIds.Count < 1) { return Ok(new { error = 1, msg = "课程参数错误!" }); }
+
+            //string sql = $"select value(c) from c  where c.id in({string.Join(",",courseIds.Select(x=>$"'{x}'"))})";
+            string sql = $"select value(c) from c ";//直接获取全校的课程
+            List<Course> courses = new List<Course>();
+            await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
+                .GetItemQueryIterator<Course>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Course-{school}") })) {
+                courses.Add(item);
+            }
+            List<Subject> addSubjects = new List<Subject>();
+            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            //不存在的课程,可以被直接创建
+            var unexistCourseIds = courseIds.Except(courses.Select(x => x.id));
+            foreach (var item in unexistCourseIds) {
+                ImportCourse importCourse= importCourses.Find(x => x.courseId.Equals(item));
+                if (importCourse != null) {
+                    Period period= data.period.Find(x => x.id.Equals(importCourse.periodId));
+                    if (period != null) {
+                        //同名学科
+                        var subject = period.subjects.Find(x => x.id.Equals($"{importCourse.subjectId}"));
+                        if (subject == null)
+                        {
+                            subject = period.subjects.Find(x => x.name.Equals($"{importCourse.subjectName}"));
+                        }
+                        if (subject == null) {
+                            subject = new Subject { id = importCourse.subjectId, name = importCourse.subjectName, type = 1 };
+                            period.subjects.Add(subject);
+                            addSubjects.Add(subject);
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(data, data.id, new PartitionKey("Base"));
+                        }
+                        Course course = new Course
+                        {
+                            id = importCourse.courseId,
+                            code = $"Course-{school}",
+                            pk = "Course",
+                            name = importCourse.courseName,
+                            period = new PeriodSimple { id = period.id, name = period.name },
+                            subject = new SubjectSimple { id = subject.id, name = subject.name },
+                            school = school,
+                            scope = "school",
+                            year = DateTimeOffset.Now.Year,
+                            schedule = new List<Schedule>(),
+                        };
+                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(course, new PartitionKey(course.code));
+                        courses.Add(course);
+                    }
+                }
+            }
+            //importCourses =importCourses .Where(x => !unexistCourseIds .Contains(x.courseId));
+
+            //排查 课程学段,课程排课作息,课程排课的星期几是否准确
+            List<ScheduleTimeDto> import_schedules_hastime = new List<ScheduleTimeDto>() ;
+            List<ScheduleNoTimeDto> import_schedules_nottime = new List<ScheduleNoTimeDto>();
+            //保存没有选用名单的排课。
+            List<Schedule> schedules_noList= new List<Schedule>() ;
+            List<ScheduleTimeDto> weeksError = new List<ScheduleTimeDto>();
+
+
+            importCourses .ToList().ForEach(x => {
+                x.schedules.ForEach(z => {
+
+                    if (!string.IsNullOrWhiteSpace(z.classId) || !string.IsNullOrWhiteSpace(z.stulist))
+                    {
+                        string classId = null;
+                        //行政班不为空,教学班为空,则名单取行政班
+                        classId = !string.IsNullOrWhiteSpace(z.classId) && string.IsNullOrWhiteSpace(z.stulist) ? z.classId : classId;
+                        //行政班为空,教学班不为空,则名单取教学班
+                        classId = string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) ? z.stulist : classId;
+                        //行政班,教学班都不为空,且相同,则任取一个,取的是行政班
+                        classId = !string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) && z.classId.Equals(z.stulist) ? z.classId : classId;
+                        //行政班,教学班都不为空,且不同,则取null
+                        classId = !string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) && !z.classId.Equals(z.stulist) ? null : classId;
+                        if (!string.IsNullOrWhiteSpace(classId))
+                        {
+                            if (z.time.IsNotEmpty())
+                            {
+                                z.time.ForEach(t =>
+                                {
+                                    ScheduleTimeDto scheduleDto = new ScheduleTimeDto
+                                    {
+                                        courseId = x.courseId,
+                                        roomId = z.room,
+                                        classId = z.classId,
+                                        stulist = z.stulist,
+                                        teacherId = z.teacherId,
+                                        timeId = t.id,
+                                        week = t.week,
+                                        keyTeacher = $"{z.teacherId}_{t.week}_{t.id}",
+                                        keyGroupId = $"{classId}_{t.week}_{t.id}",
+                                        keyRoomIds = string.IsNullOrWhiteSpace(z.room) ? null : $"{z.room}_{t.week}_{t.id}"
+                                    };
+                                    //星期几自检 1 2 3 4 5 6 7
+                                    if (weekDays.Contains(t.week))
+                                    {
+                                        import_schedules_hastime.Add(scheduleDto);
+                                    }
+                                    else
+                                    {
+                                        weeksError.Add(scheduleDto);
+                                    }
+
+                                });
+                            }
+                            else {
+                                //允许导入没有排课时间表的课程。
+                                import_schedules_nottime.Add(new ScheduleNoTimeDto
+                                {
+                                    courseId = x.courseId,
+                                    roomId = z.room,
+                                    classId = z.classId,
+                                    stulist = z.stulist,
+                                    teacherId = z.teacherId,
+                                });
+                            }
+                        }
+                        else { schedules_noList.Add(z); }
+                    }
+                    else {
+                        schedules_noList.Add(z);
+                    }
+                });
+            });
+            //导入的排课自检。
+            //教师自检
+            var check_teacher = import_schedules_hastime.GroupBy(x => x.keyTeacher).Select(g => new { key = g.Key, list = g.ToList() });
+            IEnumerable<ScheduleTimeDto> teacherWarning = new List<ScheduleTimeDto>();
+            teacherWarning = check_teacher.Where(x => x.list.Count > 1).SelectMany(x => x.list);
+            //import_schedules.RemoveAll(x => import_teacherConfuse.Contains(x));
+            //名单自检
+            var check_groupId = import_schedules_hastime.GroupBy(x => x.keyGroupId).Select(g => new { key = g.Key, list = g.ToList() });
+            IEnumerable<ScheduleTimeDto> groupIdWarning = new List<ScheduleTimeDto>();
+            groupIdWarning = check_groupId.Where(x => x.list.Count > 1).SelectMany(x => x.list);
+            //import_schedules.RemoveAll(x => import_groupIdConfuse.Contains(x));
+            //物理教室自检
+            var check_roomIds = import_schedules_hastime.Where(r=>!string.IsNullOrWhiteSpace(r.keyRoomIds)).GroupBy(x => x.keyRoomIds).Select(g => new { key = g.Key, list = g.ToList() });
+            IEnumerable<ScheduleTimeDto> roomIdsWarning = new List<ScheduleTimeDto>();
+            roomIdsWarning = check_roomIds.Where(x => x.list.Count > 1).SelectMany(x => x.list);
+            //import_schedules.RemoveAll(x => import_roomIdsConfuse.Contains(x));
+
+          
+            //打散数据库已经有的排课信息
+            List<ScheduleTimeDto> database_schedules = new List<ScheduleTimeDto>();
+            courses.ForEach(x => {
+                x.schedule.ForEach(z => {
+                    if (!string.IsNullOrWhiteSpace(z.teacherId) &&(!string.IsNullOrWhiteSpace(z.classId) || !string.IsNullOrWhiteSpace(z.stulist)))
+                    {
+                        string classId = null;
+                        //行政班不为空,教学班为空,则名单取行政班
+                        classId = !string.IsNullOrWhiteSpace(z.classId) && string.IsNullOrWhiteSpace(z.stulist) ? z.classId : classId;
+                        //行政班为空,教学班不为空,则名单取教学班
+                        classId = string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) ? z.stulist : classId;
+                        //行政班,教学班都不为空,且相同,则任取一个,取的是行政班
+                        classId = !string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) && z.classId.Equals(z.stulist) ? z.classId : classId;
+                        //行政班,教学班都不为空,且不同,则取null
+                        classId = !string.IsNullOrWhiteSpace(z.classId) && !string.IsNullOrWhiteSpace(z.stulist) && !z.classId.Equals(z.stulist) ? null : classId;
+                        if (!string.IsNullOrWhiteSpace(classId))
+                        {
+                            z.time.ForEach(t =>
+                            {
+                                ScheduleTimeDto scheduleDto = new ScheduleTimeDto
+                                {
+                                    courseId = x.id,
+                                    roomId = z.room,
+                                    classId = z.classId,
+                                    stulist = z.stulist,
+                                    teacherId = z.teacherId,
+                                    timeId = t.id,
+                                    week = t.week,
+                                    keyTeacher = $"{z.teacherId}_{t.week}_{t.id}",
+                                    keyGroupId = $"{classId}_{t.week}_{t.id}",
+                                    keyRoomIds = string.IsNullOrWhiteSpace(z.room) ? null : $"{z.room}_{t.week}_{t.id}"
+                                };
+                                database_schedules.Add(scheduleDto);
+                            });
+                        }
+                    }
+                });
+            });
+            List<ScheduleTimeDto> teacherError = new List<ScheduleTimeDto>();
+            List<ScheduleTimeDto> groupIdError = new List<ScheduleTimeDto>();
+            List<ScheduleTimeDto> roomIdsError = new List<ScheduleTimeDto>();
+            //数据库排查
+            import_schedules_hastime.ForEach(x => {
+                //检查教师的排课是否冲突,不同的课程不能出现 教师冲突的情况, 相同课程可能是需要更新的。
+                if (database_schedules.FindAll(s => s.keyTeacher.Equals(x.keyTeacher)  && !x.courseId.Equals(s.courseId)).IsNotEmpty()) 
+                {
+                    teacherError.Add(x);
+                } 
+                //检查名单的排课是否冲突
+                if (database_schedules.FindAll(s => s.keyGroupId.Equals(x.keyGroupId) && !x.courseId.Equals(s.courseId)).IsNotEmpty())
+                {
+                    groupIdError.Add(x);
+                }
+                //检查教室的排课是否冲突
+                if (database_schedules.FindAll(s => s.keyRoomIds.Equals(x.keyRoomIds) && !x.courseId.Equals(s.courseId)).IsNotEmpty())
+                {
+                    roomIdsError.Add(x);
+                }
+            });
+            //移除 教师,名单,教室冲突的排课
+            import_schedules_hastime.RemoveAll(x => teacherError.Contains(x));
+            import_schedules_hastime.RemoveAll(x => groupIdError.Contains(x));
+            import_schedules_hastime.RemoveAll(x => roomIdsError.Contains(x));
+            //最终导入之前,必须检查,课程是否存在(notInCourseIds),教师是否存在,名单是否存在,并重新排列行政班,教学班,
+            //排课时间段id是否正确,星期几是否正确(import_weeksConfuse),教室是否正确
+           
+            //检查教师存在的
+            HashSet<string> teachers = import_schedules_hastime.Select(x => x.teacherId).ToHashSet();
+            teachers.Union(import_schedules_nottime.Select(x => x.teacherId));
+            IEnumerable<string> unexistTeacherIds= null;
+            if (teachers.Count > 0) {
+                List<string> teacherIds = new List<string>();
+                string sqlTeacher = $"select value(c.id) from c where c.id in ({string.Join(",",teachers.Select(x=>$"'{x}'"))})";
+                await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
+                    .GetItemQueryIterator<string>(queryText: sqlTeacher, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Teacher-{school}") })) 
+                {
+                    teacherIds.Add(item);
+                }
+                unexistTeacherIds= teachers.Except(teacherIds);
+                //移除不存在的教师
+                import_schedules_hastime.RemoveAll(x => unexistTeacherIds.Contains(x.teacherId));
+                import_schedules_nottime.RemoveAll(x => unexistTeacherIds.Contains(x.teacherId));
+            }
+            //检查教室存在的
+            HashSet<string> roomIds = import_schedules_hastime.Select(x => x.roomId).ToHashSet();
+            roomIds.Union(import_schedules_nottime.Select(x => x.roomId));
+            IEnumerable<string> unexistRoomIds = null;
+            if (roomIds.Count > 0)
+            {
+                List<string> rooms = new List<string>();
+                string sqlRoom = $"select value(c.id) from c where c.id in ({string.Join(",", roomIds.Select(x => $"'{x}'"))})";
+                await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
+                    .GetItemQueryIterator<string>(queryText: sqlRoom, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Room-{school}") }))
+                {
+                    rooms.Add(item);
+                }
+                unexistRoomIds= roomIds.Except(rooms);
+                //移除不存在的教室
+                import_schedules_hastime.RemoveAll(x => unexistRoomIds.Contains(x.roomId));
+                import_schedules_nottime.RemoveAll(x => unexistRoomIds.Contains(x.roomId));
+            }
+            //检查名单存在的
+            List<string> groupIds = new List<string>();
+            var classIdsHasTime = import_schedules_hastime.Where(x => !string.IsNullOrWhiteSpace(x.classId)).Select(x => x.classId).ToHashSet();
+            if (classIdsHasTime.Any()) {
+                groupIds.AddRange(classIdsHasTime);
+            }
+            var stulistsHasTime = import_schedules_hastime.Where(x => !string.IsNullOrWhiteSpace(x.stulist)).Select(x => x.stulist).ToHashSet();
+            if (stulistsHasTime.Any())
+            {
+                groupIds.AddRange(stulistsHasTime);
+            }
+            var classIdsNotTime = import_schedules_nottime.Where(x => !string.IsNullOrWhiteSpace(x.classId)).Select(x => x.classId).ToHashSet();
+            if (classIdsNotTime.Any())
+            {
+                groupIds.AddRange(classIdsNotTime);
+            }
+            var stulistsNotTime = import_schedules_nottime.Where(x => !string.IsNullOrWhiteSpace(x.stulist)).Select(x => x.stulist).ToHashSet();
+            if (stulistsNotTime.Any())
+            {
+                groupIds.AddRange(stulistsNotTime);
+            }
+
+            List<GroupListDto> groupListDtos= await GroupListService.GetGroupListListids(_azureCosmos.GetCosmosClient(), _dingDing, groupIds, school);
+            IEnumerable<string> unexistGroupIds = groupIds.Except(groupListDtos.Select(x=>x.id));
+            //移除不存在的名单id
+            import_schedules_hastime.RemoveAll(x => unexistGroupIds.Contains(x.classId));
+            import_schedules_hastime.RemoveAll(x => unexistGroupIds.Contains(x.stulist));
+            import_schedules_nottime.RemoveAll(x => unexistGroupIds.Contains(x.classId));
+            import_schedules_nottime.RemoveAll(x => unexistGroupIds.Contains(x.stulist));
+
+            HashSet<Course> update_course = new HashSet<Course>();
+            HashSet<string> unexistTimeIds = new HashSet<string>();
+            //处理包含时间排课的课程
+            import_schedules_hastime.ForEach(schedule => {
+                Course course = courses.Find(x => x.id.Equals(schedule.courseId));
+                if (string.IsNullOrWhiteSpace(course?.period?.id))
+                {
+                    Period period = data.period.Find(p => p.id.Equals(course.period.id));
+                    TimeTable timeTable = period?.timetable.Find(x => x.id.Equals(schedule.timeId));
+                    if (timeTable != null)
+                    {
+                        string groupId= string.IsNullOrWhiteSpace(schedule.classId)?schedule.stulist:schedule.classId;
+                        GroupListDto groupList= groupListDtos.Find(g => g.id.Equals(groupId));
+                        string classId = null;
+                        string stulist = null;
+                        if (groupList.type.Equals("class")) {
+                            classId = groupList.id;
+
+
+                        }
+                        else {
+                            stulist = groupList.id;
+                        }
+                        var course_schedule =course.schedule.Find(x => x.teacherId.Equals(schedule.teacherId));
+                        if (course_schedule != null)
+                        {
+                            course_schedule.classId = classId;
+                            course_schedule.stulist = stulist ;
+                            course_schedule.room = schedule.roomId;
+                            var time=  course_schedule.time.Find(t => t.id.Equals(schedule.timeId) && t.week.Equals(schedule.week));
+                            if (time != null)
+                            {
+                                time.id=schedule.timeId;
+                                time.week=schedule.week;
+                            }
+                            else {
+                                course_schedule.time.Add(new TimeInfo { id = schedule.timeId, week = schedule.week });
+                            }
+                        }
+                        else {
+                            course.schedule.Add(new Schedule { teacherId = schedule.teacherId,classId = classId, stulist = stulist, room = schedule.roomId, time = new List<TimeInfo> { new TimeInfo { id=schedule.timeId,week=schedule.week} } });
+                        }
+                        update_course.Add(course);
+                    }
+                    else {
+                        //课程,所在学段对应的作息时间不正确
+                        unexistTimeIds.Add(schedule.timeId);
+                    }
+                }
+            });
+            //处理没有时间排课的课程
+            import_schedules_nottime.ForEach(schedule => {
+                Course course = courses.Find(x => x.id.Equals(schedule.courseId));
+                if (string.IsNullOrWhiteSpace(course?.period?.id))
+                {
+                    Period period = data.period.Find(p => p.id.Equals(course.period.id));
+                    string groupId = string.IsNullOrWhiteSpace(schedule.classId) ? schedule.stulist : schedule.classId;
+                    GroupListDto groupList = groupListDtos.Find(g => g.id.Equals(groupId));
+                    string classId = null;
+                    string stulist = null;
+                    if (groupList.type.Equals("class"))
+                    {
+                        classId = groupList.id;
+                    }
+                    else
+                    {
+                        stulist = groupList.id;
+                    }
+                    var course_schedule = course.schedule.Find(x => x.teacherId.Equals(schedule.teacherId));
+                    if (course_schedule != null)
+                    {
+                        course_schedule.classId = classId;
+                        course_schedule.stulist = stulist;
+                        course_schedule.room = schedule.roomId;
+                    }
+                    else
+                    {
+                        course.schedule.Add(new Schedule { teacherId=schedule.teacherId, classId = classId, stulist = stulist, room = schedule.roomId});
+                    }
+                    update_course.Add(course);
+                }
+            });
+
+            foreach (var item in update_course) {
+                await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(item, item.id, new PartitionKey(item.code));
+            }
+            return Ok(new {
+                import= new //导入数据自检信息
+                {
+                    teacherWarning,//自检-教师冲突的排课
+                    groupIdWarning,//自检-名单冲突的排课
+                    roomIdsWarning,//自检-物理教室冲突的排课
+                    weeksError //自检-错误的星期几编码
+                },
+                database= new //数据库比对信息
+                {
+                    teacherError,//数据比对-教师冲突的排课
+                    groupIdError,//数据比对-名单冲突的排课
+                    roomIdsError,//数据比对-物理教室冲突的排课
+                    unexistCourseIds ,//不存在的课程
+                    unexistTeacherIds,//不存在的教师
+                    unexistGroupIds,//不存在的名单
+                    unexistRoomIds,//不存在的教室
+                    unexistTimeIds  //不存在的作息
+                },
+                updateCourse= update_course,
+                addSubjects= addSubjects
+            });
+        }
+        
+    }
+}

+ 565 - 0
TEAMModelBI/Controllers/OpenApi/Business/ExamController.cs

@@ -0,0 +1,565 @@
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.DI;
+using System.Text.Json;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Extension;
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using System.IO;
+using System.Dynamic;
+using System.Net.Http;
+using System.Net;
+using Newtonsoft.Json;
+using System.Linq;
+using StackExchange.Redis;
+using static TEAMModelOS.SDK.Models.Teacher;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.Filter;
+using Microsoft.AspNetCore.Authorization;
+using HTEXLib.COMM.Helpers;
+using HTEXLib.Translator;
+using TEAMModelOS.Models.Dto;
+
+namespace TEAMModelAPI.Controllers
+{
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    [ApiController]
+    [Route("{scope}")]
+    public class ExamController : ControllerBase
+    {
+        public AzureCosmosFactory _azureCosmos;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly AzureRedisFactory _azureRedis;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly IConfiguration _configuration;
+        public DOXC2HTMLTranslator _DOXC2HTMLTranslator { get; set; }
+        //public PPTX2HTEXTranslator _PPTX2HTEXTranslator { get; set; }
+        public HTML2ITEMV3Translator _HTML2ITEMV3Translator { get; set; }
+        public ExamController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration)
+        {
+            _azureCosmos = azureCosmos;
+            _azureStorage = azureStorage;
+            _azureRedis = azureRedis;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _configuration = configuration;
+        }
+        /// <summary>
+        ///  获取试卷和评测的条件信息
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-paper-exam-condition")]
+        [ApiToken(Auth = "1101", Name = "试卷和评测的条件信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetPaperExamCondition(JsonElement json)
+        {
+            json.TryGetProperty("periodId", out JsonElement _periodId);
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            var exmaType = new { type = new List<string> { "regular", "simulation", "normal" } };//regula ,正规考,  simulation 模拟靠考,normal 普通考
+            var exmaMode = new { type = new List<string> { "0", "1", "2" } };//0 线上评测,  1 课中评测 ,2 阅卷评测
+            var period = data.period.Find(x => x.id.Equals($"{_periodId}"));
+            if (period != null)
+            {
+                return Ok(new { period.subjects, period.analysis, period.grades, exmaType, exmaMode });
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "学段不存在!" });
+            }
+        }
+        [ProducesDefaultResponseType]
+        [HttpPost("import-exam")]
+        [ApiToken(Auth = "1102", Name = "汇入评测基础数据", Limit = false)]
+        public async Task<IActionResult> importExam(JsonElement request)
+        {
+            //获取评测的ID
+            if (!request.TryGetProperty("exam", out JsonElement exam)) return BadRequest();
+            if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                ExamInfo info = exam.ToObject<ExamInfo>();
+                info.progress = "going";
+                await client.GetContainer(Constant.TEAMModelOS, "Common").UpsertItemAsync(info, new PartitionKey($"Exam-{code}"));
+                return Ok(new { info });
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},analysis/import-exam()\n{e.Message}\n{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
+        [ProducesDefaultResponseType]
+        [HttpPost("upsert-record")]
+        [ApiToken(Auth = "1103", Name = "批量汇入作答数据", Limit = false)]
+        public async Task<IActionResult> upsertRecord(JsonElement request)
+        {
+
+            if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
+            if (!request.TryGetProperty("students", out JsonElement students)) return BadRequest();
+            if (!request.TryGetProperty("subjectId", out JsonElement subjectId)) return BadRequest();
+            //根据不同评测的类型返回对应的编码
+            if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                //List<string> ids = students.ToObject<List<string>>();
+                List<students> stus = students.ToObject<List<students>>();
+                ExamInfo info = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(id.GetString(), new PartitionKey($"Exam-{code}"));
+                string classCode = info.scope.Equals("school") ? info.school : info.creatorId;
+                List<ExamClassResult> examClassResults = new();
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamClassResult>(
+                           queryText: $"select value(c) from c where c.examId = '{id}' and c.subjectId = '{subjectId}'",
+                           requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{classCode}") }))
+                {
+                    examClassResults.Add(item);
+                }
+                int n = 0;
+                foreach (ExamSubject subject in info.subjects)
+                {
+                    if (!subject.id.Equals(subjectId.GetString()))
+                    {
+                        n++;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+                //获取试卷信息
+                PaperSimple standerAnswers = new PaperSimple();
+                List<List<string>> standard = new List<List<string>>();
+                List<double> points = new List<double>();
+                standerAnswers = info.papers[n];
+                standard = standerAnswers.answers;
+                points = standerAnswers.point;
+                int rule = standerAnswers.multipleRule;
+                List<string> value = new List<string>();
+                await foreach (var s in stuTask(stus, examClassResults, standard, points, rule, info, subjectId.GetString(), client))
+                {
+                    if (s.code == 1)
+                    {
+                        value.Add(s.value);
+                    }
+                }
+                if (value.Count > 0)
+                {
+                    return Ok(new { code = 1, msg = "学生ID异常", value = value });
+                }
+                else
+                {
+                    return Ok(new { code = 0 });
+                }
+
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},activity/upsert-record()\n{e.Message}\n{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+
+        }
+        private async IAsyncEnumerable<(int code, string value)> stuTask(List<students> stus, List<ExamClassResult> examClassResults, List<List<string>> standard,
+            List<double> points, int rule, ExamInfo info, string subjectId, CosmosClient client)
+        {
+            foreach (var s in stus)
+            {
+                string value = "";
+                int code = 0;
+                List<List<string>> ans = s.answer;
+                bool isExist = examClassResults.Exists(e => e.studentIds.Contains(s.id));
+                if (!isExist)
+                {
+                    value = s.id;
+                    code = 1;
+                }
+                else
+                {
+                    foreach (ExamClassResult result in examClassResults)
+                    {
+                        if (!result.studentIds.Contains(s.id))
+                        {
+                            continue;
+                        }
+                        else
+                        {
+                            int newIndex = result.studentIds.IndexOf(s.id);
+                            StringBuilder builder = new StringBuilder();
+                            builder.Append(result.examId).Append('/');
+                            builder.Append(result.subjectId).Append('/');
+                            builder.Append(s.id).Append('/');
+                            builder.Append("ans.json");
+                            result.studentAnswers[newIndex].Clear();
+                            result.studentAnswers[newIndex].Add(builder.ToString());
+                            result.status[newIndex] = 0;
+                            for (int i = 0; i < ans.Count; i++)
+                            {
+                                if (ans[i] == null)
+                                {
+                                    continue;
+                                    //ans[i] = new List<string>();
+                                }
+                                var ac = ans[i].Count;
+                                var sc = standard[i].Count;
+                                //记录次数
+                                int n = 0;
+                                //算分处理
+                                if (sc > 0)
+                                {
+                                    result.ans[newIndex][i] = ans[i];
+                                    if (ac == sc && sc == 1)
+                                    {
+                                        foreach (string right in ans[i])
+                                        {
+                                            if (standard[i].Contains(right))
+                                            {
+                                                result.studentScores[newIndex][i] = points[i];
+                                            }
+                                            else
+                                            {
+                                                result.studentScores[newIndex][i] = 0;
+                                            }
+                                        }
+
+                                    }
+                                    else
+                                    {
+                                        if (rule > 0)
+                                        {
+                                            int falseCount = 0;
+                                            if (ac > 0)
+                                            {
+                                                foreach (string obj in ans[i])
+                                                {
+                                                    if (!standard[i].Contains(obj))
+                                                    {
+                                                        falseCount++;
+                                                    }
+                                                }
+                                                switch (rule)
+                                                {
+                                                    case 1:
+                                                        if (ac == sc)
+                                                        {
+                                                            if (falseCount == 0)
+                                                            {
+                                                                result.studentScores[newIndex][i] = points[i];
+                                                            }
+                                                            else
+                                                            {
+                                                                result.studentScores[newIndex][i] = 0;
+                                                            }
+                                                        }
+                                                        else
+                                                        {
+                                                            result.studentScores[newIndex][i] = 0;
+                                                        }
+                                                        break;
+                                                    case 2:
+                                                        if (falseCount > 0)
+                                                        {
+                                                            result.studentScores[newIndex][i] = 0;
+                                                        }
+                                                        else
+                                                        {
+                                                            if (ac == sc)
+                                                            {
+                                                                result.studentScores[newIndex][i] = points[i];
+                                                            }
+                                                            else
+                                                            {
+                                                                result.studentScores[newIndex][i] = points[i] / 2;
+                                                            }
+
+                                                        }
+                                                        break;
+                                                    case 3:
+                                                        if (falseCount > 0)
+                                                        {
+                                                            result.studentScores[newIndex][i] = 0;
+                                                        }
+                                                        else
+                                                        {
+                                                            if (ac == sc)
+                                                            {
+                                                                result.studentScores[newIndex][i] = points[i];
+                                                            }
+                                                            else
+                                                            {
+                                                                result.studentScores[newIndex][i] = System.Math.Round((double)ac / sc * points[i], 1);
+                                                            }
+
+                                                        }
+                                                        break;
+                                                    case 4:
+                                                        if (ac == sc)
+                                                        {
+                                                            result.studentScores[newIndex][i] = points[i];
+                                                        }
+                                                        else
+                                                        {
+                                                            double persent = (double)(sc - 2 * falseCount) / sc;
+                                                            if (persent <= 0)
+                                                            {
+                                                                result.studentScores[newIndex][i] = 0;
+                                                            }
+                                                            else
+                                                            {
+                                                                result.studentScores[newIndex][i] = System.Math.Round(persent * points[i], 1);
+                                                            }
+                                                        }
+                                                        break;
+                                                }
+                                            }
+                                            else
+                                            {
+                                                result.studentScores[newIndex][i] = 0;
+                                            }
+
+                                        }
+                                    }
+                                }
+                            }
+                            bool flag = true;
+                            foreach (List<double> scores in result.studentScores)
+                            {
+                                foreach (double score in scores)
+                                {
+                                    if (score == -1)
+                                    {
+                                        flag = false;
+                                        break;
+                                    }
+                                }
+                            }
+                            if (flag)
+                            {
+                                result.progress = true;
+                                info.subjects.ForEach(s =>
+                                {
+                                    if (s.id.Equals(subjectId.ToString()))
+                                    {
+                                        s.classCount += 1;
+                                    }
+                                });
+                                await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(info, info.id.ToString(), new PartitionKey($"{info.code}"));
+                            }
+                            result.sum[newIndex] = result.studentScores[newIndex].Sum();
+                            await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(result, result.id, new PartitionKey($"{result.code}"));
+                            break;
+                        }
+                    }
+                }
+                yield return (code, value);
+            }
+        }
+        [ProducesDefaultResponseType]
+        [HttpPost("parse-word")]
+        [ApiToken(Auth = "1104", Name = "录入试卷数据", Limit = false)]
+        public async Task<IActionResult> ParseWord([FromForm] FileDto fileDto)
+        {
+            if (!FileType.GetExtention(fileDto.file.FileName).ToLower().Equals("docx"))
+            {
+                return BadRequest(new Dictionary<string, object> { { "msg", "type is not docx!" }, { "code", 404 } });
+            }
+
+            try
+            {
+               
+                var client = _azureCosmos.GetCosmosClient();
+                var response = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemStreamAsync(fileDto.examId, new PartitionKey($"Exam-{fileDto.code}"));
+                ExamInfo examInfo;
+                if (response.Status == 200)
+                {
+                    using var json = await JsonDocument.ParseAsync(response.ContentStream);
+                    examInfo = json.ToObject<ExamInfo>();
+
+                }
+                else
+                {
+                    return Ok(new { error = 404, msg = "请先导入评测信息" });
+                }
+                foreach (PaperSimple paper in examInfo.papers)
+                {
+                    if (paper.id.Contains(fileDto.subjectId))
+                    {
+                        return Ok(new { error = 500, msg = "该试卷信息已存在" });
+                    }
+                }
+                PaperSimple simple = new();
+                var doc = _DOXC2HTMLTranslator.Translate(fileDto.file.OpenReadStream());
+                (List<HTEXLib.DOCX.Models.ItemInfo> tests, List<string> error) = _HTML2ITEMV3Translator.Translate(doc);
+                List<Task<string>> tasks = new List<Task<string>>();
+                PaperDto paperDto = new()
+                {
+                    id = Guid.NewGuid().ToString(),
+                    name = fileDto.name,
+                    code = fileDto.code,
+                    scope = "school",
+                    multipleRule = fileDto.multipleRule,
+                    gradeIds = fileDto.gradeIds,
+                    subjectId = fileDto.subjectId,
+                    periodId = fileDto.periodId
+                };
+                foreach (HTEXLib.DOCX.Models.ItemInfo item in tests)
+                {
+                    Slides slides = new();
+                    ItemDto dto = new();
+                    Scoring scoring = new();
+                    dto.id = Guid.NewGuid().ToString();
+                    dto.exercise.answer = item.answer;
+                    dto.exercise.explain = item.explain;
+                    dto.exercise.type = item.type;
+                    dto.exercise.opts = item.option.Count;
+                    dto.exercise.knowledge = item.knowledge;
+                    dto.exercise.field = item.field;
+                    dto.exercise.level = item.level;
+                    dto.exercise.subjectId = fileDto.subjectId;
+                    dto.exercise.periodId = fileDto.periodId;
+                    dto.exercise.gradeIds = fileDto.gradeIds;
+                    slides.url = dto.id + ".json";
+                    slides.type = dto.exercise.type;
+                    scoring.ans = dto.exercise.answer;
+                    scoring.score = dto.exercise.score;
+                    scoring.knowledge = dto.exercise.knowledge;
+                    scoring.field = dto.exercise.field;
+                    slides.scoring = scoring;
+                    //添加试卷信息
+                    paperDto.slides.Add(slides);
+                    if (!slides.type.Equals("compose"))
+                    {
+                        simple.point.Add(dto.exercise.score);
+                        simple.answers.Add(dto.exercise.answer);
+                        simple.knowledge.Add(dto.exercise.knowledge);
+                        simple.type.Add(dto.exercise.type);
+                        simple.field.Add((int)dto.exercise.field);
+                    }
+                    if (item.children.Count > 0)
+                    {
+                        foreach (HTEXLib.DOCX.Models.ItemInfo its in item.children)
+                        {
+                            Slides cslides = new();
+                            Scoring cscoring = new();
+                            ItemDto dtoChildren = new ItemDto();
+                            dtoChildren.id = Guid.NewGuid().ToString();
+                            dtoChildren.pid = dto.id;
+                            dtoChildren.exercise.answer = its.answer;
+                            dtoChildren.exercise.explain = its.explain;
+                            dtoChildren.exercise.type = its.type;
+                            dtoChildren.exercise.opts = its.option.Count;
+                            dtoChildren.exercise.knowledge = its.knowledge;
+                            dtoChildren.exercise.field = its.field;
+                            dtoChildren.exercise.level = its.level;
+                            dtoChildren.exercise.scope = "school";
+                            dtoChildren.exercise.score = its.score;
+                            dtoChildren.exercise.subjectId = fileDto.subjectId;
+                            dtoChildren.exercise.periodId = fileDto.periodId;
+                            dtoChildren.exercise.gradeIds = fileDto.gradeIds;
+                            dtoChildren.exercise.children.Add(dtoChildren.id);
+                            info info1 = new();
+                            info1.uid = dtoChildren.id;
+                            info1.question = its.question;
+                            info1.option = its.option;
+                            dtoChildren.item.Add(info1);
+                            dto.exercise.children.Add(dtoChildren.id);
+                            //处理子题的slides
+                            cslides.url = dtoChildren.id + ".json";
+                            cslides.type = dtoChildren.exercise.type;
+                            cscoring.ans = dtoChildren.exercise.answer;
+                            cscoring.score = dtoChildren.exercise.score;
+                            cscoring.knowledge = dtoChildren.exercise.knowledge;
+                            cscoring.field = dtoChildren.exercise.field;
+                            cslides.scoring = scoring;
+                            paperDto.slides.Add(cslides);
+                            //添加试卷信息
+                            simple.point.Add(dtoChildren.exercise.score);
+                            simple.answers.Add(dto.exercise.answer);
+                            simple.knowledge.Add(dto.exercise.knowledge);
+                            simple.type.Add(dto.exercise.type);
+                            simple.field.Add((int)dto.exercise.field);
+
+                            StringBuilder stringBuilder = new StringBuilder();
+                            stringBuilder.Append(fileDto.examId).Append("/");
+                            stringBuilder.Append("paper").Append("/");
+                            stringBuilder.Append(fileDto.subjectId).Append("/");
+                            stringBuilder.Append(dtoChildren.id + ".json");
+
+                            tasks.Add(_azureStorage.GetBlobContainerClient(fileDto.code).UploadFileByContainer( dtoChildren.ToJsonString(), "exam", stringBuilder.ToString(), false));
+                        }
+                    }
+                    info @info = new();
+                    @info.uid = dto.id;
+                    @info.question = item.question;
+                    @info.option = item.option;
+                    dto.item.Add(@info);
+                    dto.exercise.scope = "school";
+                    dto.exercise.score = item.score;
+                    StringBuilder builder = new StringBuilder();
+                    builder.Append(fileDto.examId).Append('/');
+                    builder.Append("paper").Append('/');
+                    builder.Append(fileDto.subjectId).Append('/');
+                    builder.Append(dto.id + ".json");
+                    tasks.Add(_azureStorage.GetBlobContainerClient(fileDto.code).UploadFileByContainer(dto.ToJsonString(), "exam", builder.ToString(), false));
+
+
+                }
+                StringBuilder paperBuilder = new StringBuilder();
+                paperBuilder.Append(fileDto.examId).Append('/');
+                paperBuilder.Append("paper").Append('/');
+                paperBuilder.Append(fileDto.subjectId).Append('/');
+                paperBuilder.Append("index.json");
+                tasks.Add(_azureStorage.GetBlobContainerClient(fileDto.code).UploadFileByContainer(paperDto.ToJsonString(), "exam", paperBuilder.ToString(), false));
+
+                //开始给ExamInfo paper赋值
+                simple.id = fileDto.subjectId;
+                simple.code = "Paper-" + fileDto.code;
+                simple.name = fileDto.name;
+                simple.blob = paperBuilder.ToString().Replace("index.json", "");
+                simple.scope = "school";
+                simple.multipleRule = fileDto.multipleRule;
+
+                examInfo.papers.Add(simple);
+                await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(examInfo, examInfo.id, new PartitionKey($"{examInfo.code}"));
+                await Task.WhenAll(tasks);
+
+                return Ok(new { code = 200 });
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},analysis/word()\n{e.Message}\n{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+
+        }
+
+        private class students
+        {
+            public string id { get; set; }
+            public List<List<string>> answer { get; set; }
+        }
+        public class FileDto
+        {
+            public string periodId { get; set; }
+            public string code { get; set; }
+            public string name { get; set; }
+            public int multipleRule { get; set; }
+            public string examId { get; set; }
+            public string subjectId { get; set; }
+            public List<string> gradeIds { get; set; }
+            public IFormFile file { get; set; }
+        }
+
+
+    }
+}

+ 506 - 0
TEAMModelBI/Controllers/OpenApi/Business/GroupListController.cs

@@ -0,0 +1,506 @@
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.DI;
+using System.Text.Json;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Extension;
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using System.IO;
+using System.Dynamic;
+using System.Net.Http;
+using System.Net;
+using Newtonsoft.Json;
+using System.Linq;
+using StackExchange.Redis;
+using static TEAMModelOS.SDK.Models.Teacher;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.Filter;
+using Microsoft.AspNetCore.Authorization;
+using HTEXLib.COMM.Helpers;
+using TEAMModelOS.SDK.Models.Service;
+namespace TEAMModelAPI.Controllers
+{
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    [ApiController]
+    [Route("{scope}")]
+    public class GroupListController : ControllerBase
+    {
+        public AzureCosmosFactory _azureCosmos;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly AzureRedisFactory _azureRedis;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly IConfiguration _configuration;
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly AzureServiceBusFactory _serviceBus;
+        public GroupListController(CoreAPIHttpService coreAPIHttpService, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration, AzureServiceBusFactory serviceBus)
+        {
+            _azureCosmos = azureCosmos;
+            _azureStorage = azureStorage;
+            _azureRedis = azureRedis;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _configuration = configuration;
+            _coreAPIHttpService = coreAPIHttpService;
+            _serviceBus = serviceBus;
+        }
+
+        /*
+            "periodId":"学段(选填)"
+         */
+        /// <summary>
+        ///  获取学校的行政班,教学班,教研组,研修名单
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-group-list")]
+        [ApiToken(Auth = "1201", Name = "学校名单列表", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetGroupList(JsonElement json)
+        {
+            var client = _azureCosmos.GetCosmosClient();
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            json.TryGetProperty("periodId", out JsonElement periodId);
+            List<GroupListGrp> groupLists = new List<GroupListGrp>();
+            //包含,学校的行政班,教学班
+            json.TryGetProperty("type", out JsonElement _type);
+            List<string> types = null;
+            if (_type.ValueKind.Equals(JsonValueKind.Array))
+            {
+                types = _type.ToObject<List<string>>();
+            }
+            else if (_type.ValueKind.Equals(JsonValueKind.String))
+            {
+                types = new List<string> { $"{types}" };
+            }
+            if (types.IsEmpty() || types.Contains("class"))
+            {
+                StringBuilder classsql = new StringBuilder($"SELECT c.id,c.name,c.periodId ,c.year  FROM c ");
+                if (!string.IsNullOrEmpty($"{periodId}"))
+                {
+                    classsql.Append($" where  c.periodId='{periodId}' ");
+                }
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ClassInfo>(queryText: classsql.ToString(),
+                    requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Class-{school}") }))
+                {
+                    HashSet<string> groupNames = new HashSet<string>();
+                    string gpsql = $"SELECT distinct c.groupId,c.groupName FROM c where  c.classId='{item.id}'and c.groupName <>null";
+                    await foreach (var gp in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryIterator<Student>(queryText: gpsql,
+                        requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Base-{school}") }))
+                    {
+                        groupNames.Add(gp.groupName);
+                    }
+                    ///行政班(学生搜寻classId动态返回)class
+                    GroupListGrp group = new GroupListGrp
+                    {
+                        id = item.id,
+                        code = $"GroupList-{school}",
+                        name = item.name,
+                        periodId = item.periodId,
+                        scope = "school",
+                        school = $"{school}",
+                        type = "class",
+                        year = item.year,
+                        groupName = groupNames
+                    };
+                    groupLists.Add(group);
+                }
+            }
+            if (types.IsEmpty() || types.Contains("teach"))
+            {
+                //教学班
+                StringBuilder teachsql = new StringBuilder($" SELECT distinct value(c) FROM c  where c.type='teach'");
+                if (!string.IsNullOrEmpty($"{periodId}"))
+                {
+                    teachsql.Append($" and c.periodId='{periodId}'");
+                }
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
+                    GetItemQueryIterator<GroupList>(queryText: teachsql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList-{school}") }))
+                {
+                    HashSet<string> groupName = item.members.Where(x => !string.IsNullOrEmpty(x.groupName)).Select(y => y.groupName).ToHashSet();
+                    groupLists.Add(new GroupListGrp(item, groupName));
+                }
+            }
+            if (types.IsEmpty() || types.Contains("research"))
+            {
+                //教研组
+                StringBuilder researchsql = new StringBuilder($"SELECT distinct value(c) FROM c   where c.type='research'");
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
+                    GetItemQueryIterator<GroupList>(queryText: researchsql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList-{school}") }))
+                {
+                    HashSet<string> groupName = item.members.Where(x => !string.IsNullOrEmpty(x.groupName)).Select(y => y.groupName).ToHashSet();
+                    groupLists.Add(new GroupListGrp(item, groupName));
+                }
+            }
+
+            if (types.IsEmpty() || types.Contains("yxtrain"))
+            {
+                //研修名单
+                StringBuilder yxtrainsql = new StringBuilder($"SELECT distinct value(c) FROM c    where c.type='yxtrain'");
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
+                    GetItemQueryIterator<GroupList>(queryText: yxtrainsql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList-{school}") }))
+                {
+                    HashSet<string> groupName = item.members.Where(x => !string.IsNullOrEmpty(x.groupName)).Select(y => y.groupName).ToHashSet();
+                    groupLists.Add(new GroupListGrp(item, groupName));
+                }
+            }
+            return Ok(new
+            {
+                groupLists = groupLists.Select(x => new { x.id, x.type, x.name, x.periodId, x.school, x.scope, x.year })
+            });
+        }
+        [ProducesDefaultResponseType]
+        [HttpPost("get-group-members")]
+        [ApiToken(Auth = "1202", Name = "获取名单详细信息和成员信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetGroupMembers(JsonElement json)
+        {
+            var client = _azureCosmos.GetCosmosClient();
+            if (!json.TryGetProperty("ids", out JsonElement ids)) return BadRequest();
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            List<string> listids = ids.ToObject<List<string>>();
+            (List<RMember> members, List<RGroupList> groups) = await GroupListService.GetStutmdidListids(_coreAPIHttpService, client, _dingDing, listids, $"{school}");
+            return Ok(new { groups = groups.Select(x => new { x.name, x.no, x.periodId, x.school, x.type, x.year, x.tcount, x.scount, x.leader, x.members, x.id }), members });
+        }
+        /// <summary>
+        /// 导入行政班学生
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("import-class-members")]
+        [ApiToken(Auth = "1203", Name = "导入行政班学生", RW = "W", Limit = false)]
+        public async Task<IActionResult> ImportClassMembers(JsonElement json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            if (!json.TryGetProperty("periodId", out JsonElement _periodId)) { return Ok(new { error = 2, msg = "学段信息错误!" }); }
+            if (!json.TryGetProperty("students", out JsonElement _students)) { return Ok(new { error = 1, msg = "学生列表格式错误!" }); } 
+            if (_students.ValueKind.Equals(JsonValueKind.Array))
+            {
+                School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+                Period period = data.period.Find(x => x.id.Equals($"{_periodId}"));
+                if (period != null)
+                {
+                    List<Student> webStudents = _students.ToObject<List<Student>>();
+                    webStudents.ForEach(x => x.periodId = $"{_periodId}");
+                    List<Student> preStudents = await StudentService.GeStudentData(_azureCosmos, school, webStudents?.Select(x=>x.id));
+                    var retUpsert = await StudentService.upsertStudents(_azureCosmos, _dingDing, _option, school, json.GetProperty("students").EnumerateArray());
+                    await StudentService.CheckStudent(_serviceBus, _configuration, _azureCosmos, school, webStudents, preStudents);
+                    return this.Ok(new { code = $"{school}", students = retUpsert.studs, retUpsert.classDuplNos, retUpsert.errorIds });
+                }
+                else 
+                {
+                    return Ok(new { error = 2, msg = "学段信息错误!" }); 
+                }
+            }
+            else {
+                return Ok(new { error = 1, msg = "学生列表格式错误" });
+            }
+        }
+        /// <summary>
+        ///更新學生資料,批量密碼重置,基本資訊更新(姓名、教室ID、性別、學年及座號)
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("update-class-members")]
+        [ApiToken(Auth = "1204", Name = "更新行政班学生", RW = "W", Limit = false)]
+        public async Task<IActionResult> UpdateClassMembers(JsonElement json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            if (!json.TryGetProperty("periodId", out JsonElement _periodId)) { return Ok(new { error = 2, msg = "学段信息错误!" }); }
+            if (!json.TryGetProperty("students", out JsonElement _students)) { return Ok(new { error = 1, msg = "学生列表格式错误!" }); }
+            if (_students.ValueKind.Equals(JsonValueKind.Array))
+            {
+                School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+                Period period = data.period.Find(x => x.id.Equals($"{_periodId}"));
+                if (period != null)
+                {
+                    //更新學生資料,批量密碼重置,基本資訊更新(姓名、教室ID、性別、學年及座號)
+                    List<Student> webStudents = json.GetProperty("students").ToObject<List<Student>>();
+                    webStudents.ForEach(x => x.periodId = $"{_periodId}");
+                    List<Student> preStudents = await StudentService.GeStudentData(_azureCosmos, school, webStudents?.Select(x => x.id));
+                    var retUpdate = await StudentService.updateStudents(_azureCosmos, _dingDing, _option, school, json.GetProperty("students").EnumerateArray());
+                    await StudentService.CheckStudent(_serviceBus, _configuration, _azureCosmos, school, webStudents, preStudents);
+                    return this.Ok(new { code = school, students = retUpdate.studs, retUpdate.classDuplNos, retUpdate.nonexistentIds, retUpdate.errorNos, retUpdate.errorClassId });
+                }
+                else
+                {
+                    return Ok(new { error = 2, msg = "学段信息错误!" });
+                }
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "学生列表格式错误" });
+            }
+        }
+        /// <summary>
+        ////將學生基本資料內的classId、no、groupId及groupName寫入null
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("remove-class-members")]
+        [ApiToken(Auth = "1205", Name = "移除行政班学生", RW = "W", Limit = false)]
+        public async Task<IActionResult> RemoveClassMembers(JsonElement json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            if (!json.TryGetProperty("periodId", out JsonElement _periodId)) { return Ok(new { error = 2, msg = "学段信息错误!" }); }
+            if (!json.TryGetProperty("students", out JsonElement _students)) { return Ok(new { error = 1, msg = "学生列表格式错误!" }); }
+            if (_students.ValueKind.Equals(JsonValueKind.Array))
+            {
+                School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+                Period period = data.period.Find(x => x.id.Equals($"{_periodId}"));
+                if (period != null)
+                {
+                    //將學生基本資料內的classId、no、groupId及groupName寫入null
+                    List<string> stus = json.GetProperty("students").ToObject<List<string>>();
+                    List<Student> webStudents = new List<Student>();
+                    foreach (string idstu in stus)
+                    {
+                        webStudents.Add(new Student { id = idstu, code = $"Base-{school}" });
+                    }
+                    List<Student>  preStudents = await StudentService.GeStudentData(_azureCosmos, school, webStudents?.Select(x => x.id));
+                    (List<string> studs, List<string> nonexistentIds, List<string> errorIds) retRemove = await StudentService.removeStudentClassInfo(    _azureCosmos, _dingDing, _option,school, json.GetProperty("students").EnumerateArray());
+                    await StudentService.CheckStudent(_serviceBus, _configuration, _azureCosmos, school, webStudents, preStudents);
+                    return Ok(new { code = $"{school}", ids = retRemove.studs, retRemove.nonexistentIds, retRemove.errorIds });
+                }
+                else
+                {
+                    return Ok(new { error = 2, msg = "学段信息错误!" });
+                }
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "学生列表格式错误" });
+            }
+        }
+
+        /// <summary>
+        /// 创建或更新教学班基本信息
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("upsert-teach-groups")]
+        [ApiToken(Auth = "1206", Name = "创建或更新教学班", RW = "W", Limit = false)]
+        public async Task<IActionResult> UpsertTeachGroups(GroupListDtoImpt json) {
+            var (_, school) = HttpContext.GetApiTokenInfo();
+            var groupListsDto = json.groupLists;
+            List<GroupList> groupLists = new List<GroupList>(); ;
+            List<Dictionary<string, string>> errorData = new List<Dictionary<string, string>>();
+            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            foreach (var list in groupListsDto) {
+                Period period = data.period.Find(x => x.id.Equals($"{list.periodId}"));
+                if (period != null)
+                {
+                    GroupList groupList = null;
+                    if (string.IsNullOrWhiteSpace(list.id))
+                    {
+                        groupList = new GroupList()
+                        {
+                            pk = "GroupList",
+                            id = Guid.NewGuid().ToString(),
+                            code = $"GroupList-{school}",
+                            name = list.name,
+                            periodId = list.periodId,
+                            scope = "school",
+                            school = school,
+                            type = "teach",
+                            year = list.year,
+                            froms = 3
+                        };
+                        groupList = await GroupListService.CheckListNo(groupList, _azureCosmos, _dingDing, _option);
+                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(groupList, new PartitionKey(groupList.code));
+                    }
+                    else
+                    {
+                        Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{list.id}", new PartitionKey($"GroupList-{school}"));
+                        if (response.Status == 200)
+                        {
+                            JsonDocument jsonDocument = JsonDocument.Parse(response.Content);
+                            groupList = jsonDocument.RootElement.ToObject<GroupList>();
+                            groupList.name = string.IsNullOrWhiteSpace(list.name) ? groupList.name : list.name;
+                            groupList.periodId = string.IsNullOrWhiteSpace(list.periodId) ? groupList.periodId : list.periodId;
+                            groupList.school = school;
+                            groupList.scope = "school";
+                            groupList.froms = 3;
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(groupList, groupList.id, new PartitionKey(groupList.code));
+                        }
+                        else
+                        {
+                            groupList = new GroupList()
+                            {
+                                id = Guid.NewGuid().ToString(),
+                                code = $"GroupList-{school}",
+                                name = list.name,
+                                periodId = list.periodId,
+                                scope = "school",
+                                school = school,
+                                type = "teach",
+                                year = list.year,
+                                froms = 3
+                            };
+                            groupList = await GroupListService.CheckListNo(groupList, _azureCosmos, _dingDing, _option);
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(groupList, new PartitionKey(groupList.code));
+                        }
+                    }
+                    if (groupList != null) {
+                        groupLists.Add(groupList);
+                    }
+                }
+                else
+                {
+                    errorData.Add(new Dictionary<string, string> { { "group",list.name}, { "periodId",list.periodId} });
+                    // return Ok(new { error = 2, msg ="学段不存在!" });
+                }
+            }
+             
+            return Ok(new { groupLists, errorData });
+        }
+
+        public class MemberImpt {
+            public List<Member> members { get; set; } = new List<Member>();
+            public string groupId { get; set; } 
+        }
+
+        /// <summary>
+        /// 导入教学班学生
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("import-teach-members")]
+        [ApiToken(Auth = "1207", Name = "导入教学班学生", RW = "W", Limit = false)]
+        public async Task<IActionResult> ImportTeachMembers(MemberImpt json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            //School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            List<Member> members = json.members;
+            var tmds = members.Where(x => x.type == 1);
+            var stus = members.Where(x => x.type == 2);
+            List<Student> students = await StudentService.GeStudentData(_azureCosmos, school, stus?.Select(x => x.id));
+            List<TmdInfo> infos = null;
+            string tmdstr = "";
+            try
+            {
+                var content = new StringContent(tmds.Select(x => x.id).ToJsonString(), Encoding.UTF8, "application/json");
+                tmdstr = await _coreAPIHttpService.GetUserInfos(content);
+                infos = tmdstr.ToObject<List<TmdInfo>>();
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"{_coreAPIHttpService.options.Get("Default").location}用户转换失败:{_coreAPIHttpService.options.Get("Default").url}{tmdstr}\n {ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
+                //return Ok(new { error =3, msg = "醍摩豆ID验证错误!" });
+            }
+            var unexist_student = stus.Select(x => x.id).Except(students.Select(y => y.id));
+            var unexist_tmdids = tmds.Select(x => x.id).Except(infos.Select(y => y.id));
+            Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{json.groupId}", new PartitionKey($"GroupList-{school}"));
+            if (response.Status == 200)
+            {
+                JsonDocument jsonDocument = JsonDocument.Parse(response.Content);
+                var list =  jsonDocument.RootElement.ToObject<GroupList>();
+                if (list.type.Equals("teach") && list.school.Equals(school))
+                {
+                    if (infos.Any())
+                    {
+                        infos.ToList().ForEach(x => {
+                            if (!list.members.Where(z => z.type == 1).Select(x => x.id).Contains(x.id))
+                            {
+                                GroupListService.JoinList(list, x.id , 1 , school);
+                            }
+                        });
+                    }
+                    if (stus.Any()) 
+                    {
+                        stus.ToList().ForEach(x => {
+                            if (!list.members.Where(z => z.type == 2).Select(x => x.id).Contains(x.id)) {
+                                GroupListService.JoinList(list, x.id ,2 , school);
+                            }    
+                        });
+                    }
+                    list = await GroupListService.CheckListNo(list, _azureCosmos, _dingDing, _option);
+                    list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                    return Ok(new { unexist_student, unexist_tmdids, import_list=list });
+                }
+                else {
+                    return Ok(new { error = 3, msg = $"名单类型不是教学班或者不是当前学校的名单!{list.type},{list.school}" });
+                }
+            }
+            else
+            {
+                return Ok(new { error = 2, msg = "名单错误!" });
+            }
+        }
+
+        /// <summary>
+        /// 移除教学班学生
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("remove-teach-members")]
+        [ApiToken(Auth = "1208", Name = "移除教学班学生", RW = "W", Limit = false)]
+        public async Task<IActionResult> RemoveTeachMembers(JsonElement json) {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            json.TryGetProperty("stuids", out JsonElement _stuids);
+            json.TryGetProperty("tmdids", out JsonElement _tmdids);
+            if (json.TryGetProperty("groupId", out JsonElement _groupId)) { return Ok(new { error = 1, msg = "名单错误!" }); }
+            List<string> stuids = null;
+            if (_stuids.ValueKind.Equals(JsonValueKind.Array)) {
+                stuids = _stuids.ToObject<List<string>>();
+            }
+            List<string> tmdids = null;
+            if (_tmdids.ValueKind.Equals(JsonValueKind.Array))
+            {
+                tmdids = _tmdids.ToObject<List<string>>();
+            }
+            if (tmdids.Any() || stuids.Any())
+            {
+                // School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+                Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{_groupId}", new PartitionKey($"GroupList-{school}"));
+                if (response.Status == 200)
+                { 
+                    JsonDocument document= JsonDocument.Parse(response.Content);
+                    var  list= document.RootElement.Deserialize<GroupList>();
+                    List<string> remove_tmdids = new List<string>();
+                    if (tmdids.Any()) {
+                        tmdids.ForEach(x => {
+                            int len= list.members.RemoveAll(z => z.id.Equals(x) && z.type == 1);
+                            if (len > 0) {
+                                remove_tmdids.Add(x);
+                            }
+                        });
+                    }
+                    List<string> remove_stuids = new List<string>();
+                    if (stuids.Any())
+                    {
+                        stuids.ForEach(x => {
+                            int len = list.members.RemoveAll(z => z.id.Equals(x) && z.type == 2);
+                            if (len > 0)
+                            {
+                                remove_stuids.Add(x);
+                            }
+                        });
+                    }
+                    list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                    return Ok(new { remove_stuids, remove_tmdids, list });
+                }
+                else {
+                    return Ok(new { error = 2, msg = "名单错误!" });
+                }
+            }
+            else 
+            {
+                 return Ok(new { error = 2, msg = "移除的名单人员为空!" }); 
+            }
+        }
+    }
+}

+ 172 - 0
TEAMModelBI/Controllers/OpenApi/Business/RoomController.cs

@@ -0,0 +1,172 @@
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.IdentityModel.Tokens.Jwt;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.Models.Dto;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Helper.Common.StringHelper;
+using System.Dynamic;
+using Azure;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+using Azure.Messaging.ServiceBus;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.Filter;
+using Azure.Storage.Blobs.Models;
+using HTEXLib.COMM.Helpers;
+using Microsoft.AspNetCore.Authorization;
+namespace TEAMModelAPI.Controllers
+{
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    [Route("{scope}")]
+    [ApiController]
+    public class RoomController : ControllerBase
+    {
+        private AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly AzureServiceBusFactory _serviceBus;
+        private readonly AzureStorageFactory _azureStorage;
+        public IConfiguration _configuration { get; set; }
+        public RoomController(AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option, AzureServiceBusFactory serviceBus, AzureStorageFactory azureStorage, IConfiguration configuration)
+        {
+            _azureCosmos = azureCosmos;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _serviceBus = serviceBus;
+            _configuration = configuration;
+            _azureStorage = azureStorage;
+        }
+        /// <summary>
+        /// 获取物理教室列表
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-room-list")]
+        [ApiToken(Auth = "1401", Name = "获取物理教室列表", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetRoomList(JsonElement json)
+        {
+            var client = _azureCosmos.GetCosmosClient();
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            StringBuilder sql = new StringBuilder($"select value(c) from c where 1=1 ");
+            json.TryGetProperty("openType", out JsonElement openType);
+            json.TryGetProperty("no", out JsonElement no);
+            if (!string.IsNullOrWhiteSpace($"{openType}"))
+            {
+                sql.Append($" and c.openType='{openType}'");
+            }
+            if (!string.IsNullOrWhiteSpace($"{no}"))
+            {
+                sql.Append($" and c.no='{no}'");
+            }
+            List<Room> rooms = new List<Room>();
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<Room>(queryText: sql.ToString(),
+            requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Room-{school}") }))
+            {
+                rooms.Add(item);
+            }
+            return Ok(new { rooms = rooms.Select(x => new { x.id, x.name, x.x, x.y, x.openType, x.style, x.area, x.address, school = school }) });
+        }
+        /// <summary>
+        /// 获取物理教室详细信息
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-room-info")]
+        [ApiToken(Auth = "1402", Name = "获取物理教室详细信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetRoomInfo(JsonElement json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            if (!json.TryGetProperty("roomId", out JsonElement roomId)) return BadRequest();
+            Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School")
+              .ReadItemStreamAsync($"{roomId}", new PartitionKey($"Room-{school}"));
+            if (response.Status == 200)
+            {
+                JsonDocument document = JsonDocument.Parse(response.Content);
+                Room room = document.RootElement.Deserialize<Room>();
+                return Ok(new { room.id, room.name, room.x, room.y, room.openType, room.style, room.area, room.address, school = school });
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "教室不存在!" });
+            }
+        }
+
+        public class RoomsDto
+        {
+            public List<RoomDto> rooms { get; set; } = new List<RoomDto>();
+
+        }
+
+        /// <summary>
+        /// 创建或更新教学班基本信息
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("upsert-room-infos")]
+        [ApiToken(Auth = "1403", Name = "创建或更新教学班", RW = "W", Limit = false)]
+        public async Task<IActionResult> UpsertRoomInfo(RoomsDto json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            var rooms = json.rooms ;
+            List<Room> db_rooms = new List<Room>();
+            List<Room> roomCreate = new List<Room>();
+            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            string sql = $"select value(c) from c  where c.id in({string.Join(",", rooms.Select(x => $"'{x.id}'"))})";
+            await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
+                .GetItemQueryIterator<Room>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Room-{school}") }))
+            {
+                db_rooms.Add(item);
+            }
+            //不存在的教室,可以被直接创建
+            var unexistRoomIds = rooms.Select(x=>x.id).Except(db_rooms.Select(x => x.id));
+            foreach (var roomId in unexistRoomIds) {
+                var room_web = rooms.Find(x => x.id.Equals(roomId));
+                if (room_web != null) {
+                    var room = new Room
+                    {
+                        id = room_web.id,
+                        name = room_web.name,
+                        code = $"Room-{school}",
+                        pk = "Room",
+                        no = room_web.no,
+                        area = room_web.area,
+                        address = room_web.address,
+                    };
+                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(room, new PartitionKey(room.code));
+                    roomCreate.Add(room);
+                }
+            }
+            foreach (var room in db_rooms) {
+                var room_web = rooms.Find(x => x.id.Equals(room.id));
+                if (room_web != null)
+                {
+                    room.name = string.IsNullOrWhiteSpace(room_web.name) ? room.name : room_web.name;  
+                    room.code = $"Room-{school}";
+                    room.pk = "Room";
+                    room.area= string.IsNullOrWhiteSpace(room_web.area) ? room.area : room_web.area; 
+                    room.no =string.IsNullOrWhiteSpace(room_web.no)?room.no : room_web.no;
+                    room.address = string.IsNullOrWhiteSpace(room_web.address) ? room.address : room_web.address; 
+                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(room,room.id, new PartitionKey(room.code));
+                }
+            }
+            return Ok(new { roomUpdate= db_rooms, roomCreate= roomCreate });
+        }
+    }
+}

+ 91 - 0
TEAMModelBI/Controllers/OpenApi/Business/SchoolController.cs

@@ -0,0 +1,91 @@
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.DI;
+using System.Text.Json;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Extension;
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using System.IO;
+using System.Dynamic;
+using System.Net.Http;
+using System.Net;
+using Newtonsoft.Json;
+using System.Linq;
+using StackExchange.Redis;
+using static TEAMModelOS.SDK.Models.Teacher;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.Filter;
+using Microsoft.AspNetCore.Authorization;
+using HTEXLib.COMM.Helpers;
+using TEAMModelOS.SDK.Models.Service;
+using TEAMModelOS.SDK.Models.Table;
+
+namespace TEAMModelAPI.Controllers
+{
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    [ApiController]
+    [Route("{scope}")]
+    public class SchoolController : ControllerBase
+    {
+        public AzureCosmosFactory _azureCosmos;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly AzureRedisFactory _azureRedis;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly IConfiguration _configuration;
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        public SchoolController(CoreAPIHttpService coreAPIHttpService, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration)
+        {
+            _azureCosmos = azureCosmos;
+            _azureStorage = azureStorage;
+            _azureRedis = azureRedis;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _configuration = configuration;
+            _coreAPIHttpService=coreAPIHttpService;
+        }
+        /// <summary>
+        ///  学校基础信息
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-schools")]
+        [ApiToken(Auth = "1000", Name = "合作商获取可访问的学校列表", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetSchools() {
+            var (id, _) = HttpContext.GetApiTokenInfo();
+            var table = _azureStorage.GetCloudTableClient().GetTableReference("IESOpenApi");
+            List<BusinessSchool> schools=  await table.FindListByDict<BusinessSchool>(new Dictionary<string, object> { { "PartitionKey", $"BusinessSchool-{id}" } });
+            return Ok(new { schools = schools.Select(x => new {id =x.RowKey,x.name,x.picture })});
+        }
+        /// <summary>
+        ///  学校基础信息
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-school-info")]
+        [ApiToken(Auth = "1001",Name = "学校基础信息", RW = "R", Limit =false)]
+        public async Task<IActionResult> GetSchoolInfo()
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            List<dynamic> period = new List<dynamic>();
+            data.period.ForEach(x => { period.Add(new { x.subjects ,x.grades,x.name,x.id,x.campusId,x.semesters}); });
+            return Ok(new { 
+                id = data.id, name = data.name, data.areaId, type = data.type, 
+                data.region, data.province, data.city, data.dist,
+                campuses=data.campuses,
+                period
+            });
+        }
+    }
+}

+ 351 - 0
TEAMModelBI/Controllers/OpenApi/Business/TeacherController.cs

@@ -0,0 +1,351 @@
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.IdentityModel.Tokens.Jwt;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.Models.Dto;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Helper.Common.StringHelper;
+using System.Dynamic;
+using Azure;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+using Azure.Messaging.ServiceBus;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.Filter;
+using Azure.Storage.Blobs.Models;
+using HTEXLib.COMM.Helpers;
+using Microsoft.AspNetCore.Authorization;
+using System.Net.Http;
+using System.ComponentModel.DataAnnotations;
+
+namespace TEAMModelAPI.Controllers
+{
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    [Route("{scope}")]
+    [ApiController]
+    public class TeacherController : ControllerBase
+    {
+        private AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly AzureServiceBusFactory _serviceBus;
+        private readonly AzureStorageFactory _azureStorage;
+        public IConfiguration _configuration { get; set; }
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        public TeacherController(CoreAPIHttpService coreAPIHttpService, AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option, AzureServiceBusFactory serviceBus, AzureStorageFactory azureStorage, IConfiguration configuration)
+        {
+            _azureCosmos = azureCosmos;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _serviceBus = serviceBus;
+            _configuration = configuration;
+            _azureStorage = azureStorage;
+            _coreAPIHttpService = coreAPIHttpService;
+        }
+
+        /// <summary>
+        ///  获取学校教师列表
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-teacher-list")]
+        [ApiToken(Auth = "1501", Name = "学校教师列表", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetTeacherList(JsonElement json)
+        {
+
+            json.TryGetProperty("searchKey", out JsonElement _searchKey);
+            List<CoreUser> coreUsers = new List<CoreUser>();
+            IEnumerable<string> unexist = null;
+            if (_searchKey.ValueKind.Equals(JsonValueKind.Array))
+            {
+                List<string> searchKey = _searchKey.ToObject<List<string>>();
+                var keys = searchKey.Where(x => !string.IsNullOrWhiteSpace(x));
+                var content = new StringContent(keys.ToJsonString(), Encoding.UTF8, "application/json");
+                string ujson = await _coreAPIHttpService.GetUserInfos(content);
+                if (!string.IsNullOrWhiteSpace(ujson))
+                {
+                    coreUsers = ujson.ToObject<List<CoreUser>>();
+                }
+                if (coreUsers.Any())
+                {
+                    unexist = searchKey.Except(coreUsers.Select(x => x.searchKey));
+                }
+                else
+                {
+                    return Ok(new { error = 1, msg = "没有找到对应的教师信息!" });
+                }
+            }
+
+
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            List<SchoolTeacher> teachers = new List<SchoolTeacher>();
+            string insql = "";
+            if (coreUsers.Any())
+            {
+                insql = $"   c.id in  ({string.Join(",", coreUsers.Select(x => $"'{ x.id}'"))}) ";
+            }
+            string sql = $"select c.id,c.name ,c.picture,c.job ,c.subjectIds,c.roles from c where   {insql}";
+            await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<SchoolTeacher>
+                (queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Teacher-{school}") }))
+            {
+                teachers.Add(item);
+            }
+            var teacherIds = coreUsers.Select(x => x.id).Except(teachers.Select(x => x.id));
+            List<CoreUser> unjoined = coreUsers.FindAll(x => teacherIds.Contains(x.id));
+            List<dynamic> tchs = new List<dynamic>();
+            teachers.Select(x => new { x.id, x.name, x.picture, x.job, x.subjectIds, x.roles }).ToList().ForEach(x => {
+                var coreUser = coreUsers.Find(c => c.id.Equals(x.id));
+                if (coreUser != null)
+                {
+                    tchs.Add(new { x.id, coreUser.name, coreUser.picture, x.job, x.subjectIds, x.roles, coreUser.searchKey, school });
+                }
+            });
+            return Ok(new
+            {
+                teachers = tchs,
+                unjoined = unjoined.Select(x => new { x.id, x.name, x.picture, x.searchKey }),
+                unexist = unexist
+            });
+        }
+        /// <summary>
+        /// 获取学校教师信息
+        /// </summary>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-teacher-info")]
+        [ApiToken(Auth = "1502", Name = "学校教师信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetTeacherInfo(JsonElement json)
+        {
+            json.TryGetProperty("tmdid", out JsonElement _tmdid);
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            Azure.Response responseSchoolTch = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School")
+                .ReadItemStreamAsync($"{_tmdid}", new PartitionKey($"Teacher-{school}"));
+            Azure.Response responseTch = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher")
+                 .ReadItemStreamAsync($"{_tmdid}", new PartitionKey($"Base"));
+            Teacher teacher = null;
+            if (responseTch.Status == 200)
+            {
+                teacher = JsonDocument.Parse(responseTch.Content).RootElement.Deserialize<Teacher>();
+
+            }
+            else
+            {
+                return Ok(new { error = 3, msg = "账号未创建!" });
+            }
+            if (responseSchoolTch.Status == 200 && teacher != null)
+            {
+                SchoolTeacher schoolTeacher = JsonDocument.Parse(responseSchoolTch.Content).RootElement.Deserialize<SchoolTeacher>();
+                return Ok(new { teacher.id, teacher.name, teacher.picture, schoolTeacher.job, schoolTeacher.status, schoolTeacher.roles, schoolTeacher.subjectIds, school = teacher.schools?.Find(x => x.schoolId.Equals(school)) });
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "教师未就职该学校!" });
+            }
+        }
+
+
+
+
+        /// <summary>
+        /// 批量导入教师信息,并加入学校。可以导入学科,但需要填写学段id
+        /// </summary>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("import-school-teacher")]
+        [ApiToken(Auth = "1503", Name = "学校教师信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> ImportSchoolTeacher(ImportTechDto json)
+        {
+            //如果需要同时导入学科,则需要填写学段
+
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            List<ImportTech> teachers = json.teachers;
+            List<string> searchKey = teachers.Select(x => x.id).ToList();
+            string ujson = null;
+            var keys = searchKey.Where(x => !string.IsNullOrWhiteSpace(x));
+            if (keys.Any())
+            {
+                var content = new StringContent(keys.ToJsonString(), Encoding.UTF8, "application/json");
+                ujson = await _coreAPIHttpService.GetUserInfos(content);
+            }
+            List<CoreUser> coreUsers = new List<CoreUser>();
+            if (!string.IsNullOrWhiteSpace(ujson))
+            {
+                coreUsers = ujson.ToObject<List<CoreUser>>();
+            }
+            IEnumerable<string> unexist = new List<string>();
+            if (coreUsers.Any())
+            {
+                unexist = searchKey.Except(coreUsers.Select(x => x.id));
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "没有找到对应的教师信息!" });
+            }
+            var exist = coreUsers.Select(x => x.id);
+            //注册了账号的教师
+            teachers = teachers.Where(x => exist.Contains(x.id)).ToList();
+
+            List<Teacher> teachersList = new List<Teacher>();
+            List<SchoolTeacher> schoolTeachers = new List<SchoolTeacher>();
+            string sql = $"select value(c) from c where c.id in ({string.Join(",", teachers.Select(x => $"'{x.id}'"))})";
+            await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
+                .GetItemQueryIterator<Teacher>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
+            {
+                teachersList.Add(item);
+            }
+            await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
+              .GetItemQueryIterator<SchoolTeacher>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Teacher-{school}") }))
+            {
+                schoolTeachers.Add(item);
+            }
+            long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            //学校学科发生变化。
+            List<SchoolTeacher> schoolTeachersAdd = new List<SchoolTeacher>();
+            bool baseChange = false;
+            foreach (var item in teachers)
+            {
+                var teacher = teachersList.Find(x => x.id.Equals(item.id));
+                var coreUser = coreUsers.Find(x => x.id.Equals(item.id));
+                if (teacher != null)
+                {
+                    var sch = teacher.schools?.Find(x => x.schoolId.Equals(school));
+                    if (sch == null)
+                    {
+                        if (teacher.schools.IsNotEmpty())
+                        {
+                            teacher.schools.Add(new Teacher.TeacherSchool { schoolId = school, name = data.name, status = "invite", time = now, picture = data.picture, areaId = data.areaId });
+                        }
+                        else
+                        {
+                            teacher.defaultSchool = school;
+                            teacher.size = teacher.size + 1;
+                            teacher.schools = new List<Teacher.TeacherSchool> { new Teacher.TeacherSchool { schoolId = school, name = data.name, status = "invite", time = now, picture = data.picture, areaId = data.areaId } };
+                        }
+                    }
+                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey("Base"));
+                }
+                else
+                {
+
+                    teacher = new Teacher
+                    {
+                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
+                        id = coreUser.id,
+                        name = coreUser.name,
+                        picture = coreUser.picture,
+                        defaultSchool = school,
+                        size = 2,
+                        code = "Base",
+                        pk = "Base",
+                        schools = new List<Teacher.TeacherSchool> { new Teacher.TeacherSchool { schoolId = school, name = data.name, status = "invite", time = now, picture = data.picture, areaId = data.areaId } }
+                    };
+                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).CreateItemAsync(teacher, new PartitionKey("Base"));
+                }
+                var schoolTeacher = schoolTeachers.Find(x => x.id.Equals(item.id));
+                //处理导入的学科
+                List<string> subjectIds = new List<string>();
+                if (item.subjects.IsNotEmpty() && !string.IsNullOrWhiteSpace(item.periodId))
+                {
+                    item.subjects.ForEach(s => {
+                        //同名学科
+                        var subject = data.period.Find(x => x.id.Equals(item.periodId))?.subjects?.Find(x => x.id.Equals(s.id));
+                        if (subject == null)
+                        {
+                            subject = data.period.Find(x => x.id.Equals(item.periodId))?.subjects?.Find(x => x.name.Equals(s.name));
+                        }
+                        else
+                        {
+                            subjectIds.Add(subject.id);
+                        }
+                        if (subject == null)
+                        {
+                            var period = data.period.Find(x => x.id.Equals(item.periodId));
+                            if (period != null)
+                            {
+                                period.subjects.Add(new Subject { id = s.id, name = s.name, type = 2 });
+                                subjectIds.Add(s.id);
+                                baseChange = true;
+                            }
+                        }
+                    });
+                }
+                if (schoolTeacher == null)
+                {
+                    schoolTeacher = new SchoolTeacher
+                    {
+                        id = item.id,
+                        name = coreUser.name,
+                        picture = coreUser.picture,
+                        job = item.job,
+                        subjectIds = subjectIds,
+                        roles = new List<string> { "teacher" },
+                        permissions = new List<string> { "content-read", "exercise-read", "knowledge-read", "syllabus-read" },
+                        status = "invite",
+                        code = $"Teacher-{school}",
+                        pk = "Teacher",
+                        createTime = now,
+                    };
+                    schoolTeachersAdd.Add(schoolTeacher);
+                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(schoolTeacher, new PartitionKey(schoolTeacher.code));
+                }
+                else
+                {
+                    if (subjectIds.IsNotEmpty())
+                    {
+                        subjectIds.ForEach(x => {
+                            if (!schoolTeacher.subjectIds.Contains(x))
+                            {
+                                schoolTeacher.subjectIds.Add(x);
+                            }
+                        });
+                    }
+                    schoolTeacher.job = string.IsNullOrWhiteSpace(item.job) ? schoolTeacher.job : item.job;
+                    schoolTeachersAdd.Add(schoolTeacher);
+                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(schoolTeacher, schoolTeacher.id, new PartitionKey(schoolTeacher.code));
+                }
+            }
+            if (baseChange)
+            {
+                await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(data, data.id, new PartitionKey("Base"));
+            }
+            return Ok(new { teachers = schoolTeachersAdd.Select(x => new { x.id, x.name, x.picture, x.job, x.subjectIds, x.roles, school }) });
+        }
+    }
+
+    public class ImportTechDto
+    {
+        public List<ImportTech> teachers { get; set; } = new List<ImportTech>();
+    }
+    public class ImportTech
+    {
+        [Required(ErrorMessage = "教师id必须设置")]
+        public string id { get; set; }
+        public List<ImportTechSubject> subjects { get; set; }
+        [RegularExpression(@"[0-9a-zA-Z]{8}(-[0-9a-zA-Z]{4}){3}-[0-9a-zA-Z]{12}", ErrorMessage = "学段的uuid格式错误!")]
+        public string periodId { get; set; }
+        public string job { get; set; }
+    }
+    public class ImportTechSubject
+    {
+        [RegularExpression(@"[0-9a-zA-Z]{8}(-[0-9a-zA-Z]{4}){3}-[0-9a-zA-Z]{12}", ErrorMessage = "科目的uuid格式错误!")]
+        public string id { get; set; }
+        [Required(ErrorMessage = "科目名称 必须设置")]
+        public string name { get; set; }
+    }
+
+}

+ 0 - 62
TEAMModelBI/Filter/ApiTokenAttribute.cs

@@ -1,62 +0,0 @@
-using Microsoft.AspNetCore.Mvc.Filters;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Options;
-using System;
-using TEAMModelOS.Models;
-using TEAMModelOS.SDK.DI;
-
-namespace TEAMModelBI.Filter
-{
-    public class ApiTokenAttribute : Attribute, IFilterFactory 
-    {
-
-        public bool IsReusable => throw new NotImplementedException();
-
-        /// <summary>
-        /// 是否开启限流策略
-        /// </summary>
-        public bool Limit { get; set; }
-
-        /// <summary>
-        /// 授权序列
-        /// </summary>
-        public string Auth { get; set; }
-
-        public IFilterMetadata CreateInstance(IServiceProvider services)
-        {
-            var option = services.GetService<IOptions<Option>>();
-            var azureRedis = services.GetService<AzureRedisFactory>();
-            return new InternalAuthTokenFilter(option, azureRedis, Auth, Limit);
-        }
-
-        private class InternalAuthTokenFilter : IResourceFilter 
-        {
-            private readonly Option _option;
-            //private readonly string _roles;
-            private readonly string _auth;
-            private readonly bool _limit;
-            private readonly AzureRedisFactory _azureRedis;
-
-
-            public InternalAuthTokenFilter(IOptions<Option> option, AzureRedisFactory azureRedis, string auth, bool limit)
-            {
-                _option = option.Value;
-                _auth = auth;
-                _limit = limit;
-                _azureRedis = azureRedis;
-            }
-
-            public void OnResourceExecuting(ResourceExecutingContext context)
-            {
-
-            }
-
-            public void OnResourceExecuted(ResourceExecutedContext context)
-            {
-
-            }
-
-        }
-
-    }
-}

+ 32 - 33
TEAMModelBI/Startup.cs

@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.SpaServices;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
@@ -15,12 +16,16 @@ using System.Linq;
 using System.Threading.Tasks;
 using TEAMModelBI.DI;
 using TEAMModelBI.DI.BIAzureStorage;
+using TEAMModelBI.Filter;
 using TEAMModelBI.Models;
+using TEAMModelOS.Filter;
 using TEAMModelOS.Models;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Filter;
+using TEAMModelOS.SDK.Helper.Common.ReflectorExtensions;
+using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Service;
 using VueCliMiddleware;
 
@@ -173,7 +178,7 @@ namespace TEAMModelBI
         }
 
         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
-        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, AzureStorageFactory azureStorage)
         {
             if (env.IsDevelopment())
             {
@@ -190,37 +195,6 @@ namespace TEAMModelBI
             //调用放在之后、UseRouting 和 UseCors,但在 UseEndpoints之前
             app.UseAuthentication();
             app.UseAuthorization();
-
-            //app.UseEndpoints(endpoints =>
-            //{
-            //    endpoints.MapControllers();
-            //});
-
-            //app.UseSpa(spa =>
-            //{
-            //    if (env.IsDevelopment())
-            //        spa.Options.SourcePath = "ClientApp/";
-            //    else
-            //        spa.Options.SourcePath = "dist";
-            //    if (env.IsDevelopment())
-            //    {
-            //        spa.UseVueCli(npmScript: "serve");
-            //    }
-            //});
-
-            //app.UseSpa(spa =>
-            //{
-            //    spa.Options.SourcePath = "ClientApp/";
-            //    if (env.IsDevelopment())
-            //    {
-            //        //spa.UseProxyToSpaDevelopmentServer("https://localhost:5001");
-            //        //spa.Options.StartupTimeout = new TimeSpan(0, 0, 80);
-            //        //spa.UseVueCli(npmScript: "serve"); 
-            //        //spa.UseProxyToSpaDevelopmentServer("https://localhost:5001");
-            //        spa.UseVueCli(npmScript: "serve");
-            //    }
-            //});
-
             app.UseEndpoints(endpoints =>
             {
                 endpoints.MapControllers();
@@ -243,9 +217,34 @@ namespace TEAMModelBI
                     );
 #else
                 endpoints.MapFallbackToFile("index.html");
-#endif             
+#endif
 
             });
+
+#if DEBUG
+            //在开发模式时,自检 [ApiToken(Auth = "1")] 有重复的接口 https://teammodelos.table.core.chinacloudapi.cn/IESOpenApi
+            List<ApiTokenAttribute> auths = new List<ApiTokenAttribute>();
+            (List<OpenApi> openApis, List<ApiTokenAttribute> attributes) = ReflectorExtensions.GetMethodCustomAttribute<ApiTokenAttribute, HttpPostAttribute>(new string[] { "TEAMModelBI" });
+            attributes.GroupBy(x => x.Auth).ToList().ForEach(x => {
+                if (x.Count() > 1)
+                {
+                    throw new Exception($"接口Auth重复定义{x.ToList()}");
+                }
+            });
+
+            var table = azureStorage.GetCloudTableClient().GetTableReference("IESOpenApi");
+            try
+            {
+                foreach (var item in openApis)
+                {
+                    _ = table.SaveOrUpdate<OpenApi>(item);
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+            }
+#endif
         }
     }
 }

+ 0 - 7
TEAMModelBI/appsettings.Development.json

@@ -29,12 +29,6 @@
     "Cosmos": {
       "ConnectionString": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;"
     },
-    "CosmosUrl": {
-      "ConnectionString": "https://cdhabookdep-free.documents.azure.cn:443/"
-    },
-    "CosmosKey": {
-      "ConnectionString": "JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A=="
-    },
     "Redis": {
       "ConnectionString": "52.130.252.100:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240"
     },
@@ -53,7 +47,6 @@
       "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodellog;AccountKey=lxVDrgs+6rKtmASL3k1WrarrEd5Rk42wS1Mu5+sqQlPya1JLSlFDtnZUvMPeHHe7zlESfn/1NY7CZdGviy2UCw==;BlobEndpoint=https://teammodellog.blob.core.chinacloudapi.cn/;QueueEndpoint=https://teammodellog.queue.core.chinacloudapi.cn/;TableEndpoint=https://teammodellog.table.core.chinacloudapi.cn/;FileEndpoint=https://teammodellog.file.core.chinacloudapi.cn/;"
     },
     "Cosmos": {
-      //"ConnectionString": "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", //本地
       "ConnectionString": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;" //测试站
     },
     "Redis": {

+ 25 - 8
TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs

@@ -1517,8 +1517,22 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                 {
                                     if (scope.Equals("private"))
                                     {
-
-                                        if (teacher.lessonLimit != -1)
+                                        int  lessonLimit = teacher.lessonLimit;
+                                        long blobsize = 0;
+                                        var value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", tmdid);
+                                        if (value != default && !value.IsNullOrEmpty)
+                                        {
+                                            JsonElement record = value.ToString().ToObject<JsonElement>();
+                                            if (record.TryGetInt64(out blobsize))
+                                            {
+                                            }
+                                        }
+                                        //剩余空间小于2G 
+                                        if (teacher.size * 1073741824 - blobsize < 2147483648)
+                                        {
+                                            lessonLimit = -1;
+                                        }
+                                        if ( lessonLimit != -1)
                                         {
 
                                             HashSet<string> ids = new HashSet<string>();
@@ -1530,13 +1544,15 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
 
                                                 ids.Add(item);
                                             }
+                                            // 220601  收藏不限條數,但空間不足時,僅保留最後一次上傳的課例   ()
                                             //包含收藏的本人的个人课例
-                                            string favorite_count_sql = $"select value(c.id) from  c where c.type='LessonRecord' and c.owner='{tmdid}'   and c.scope='private' ";
-                                            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetItemQueryIterator<string>(
-                                                queryText: favorite_count_sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Favorite-{tmdid}") }))
-                                            {
-                                                ids.Add(item);
-                                            }
+                                            //string favorite_count_sql = $"select value(c.id) from  c where c.type='LessonRecord' and c.owner='{tmdid}'   and c.scope='private' ";
+                                            //await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetItemQueryIterator<string>(
+                                            //    queryText: favorite_count_sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Favorite-{tmdid}") }))
+                                            //{
+                                            //    ids.Add(item);
+                                            //}
+                                          
                                             //教师个人预设的,可以通过设置的方式增加
                                             int limit = teacher.lessonLimit;
                                             if (teacher.lessonLimit == 0)
@@ -1544,6 +1560,7 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                                 //未设置的的采用系统设置的默认值50
                                                 limit = Constant.private_lesson_limit;
                                             }
+
                                             if (ids.Count >= limit)
                                             {
                                                 // 1-时间戳,7-时间戳

+ 4 - 2
TEAMModelOS.SDK/Models/Cosmos/Student/Parent.cs

@@ -12,7 +12,7 @@ namespace TEAMModelOS.SDK.Models
         // code = "Base-Parent"
 
         //绑定信息的key(手机号,邮箱,醍摩豆id)
-        public List<BindKey> bindKey { get; set; } = new List<BindKey>();
+        
         //姓名 姓名
         public string name { get; set; }
         //监护人:父亲,母亲,或者其他监护人
@@ -21,7 +21,9 @@ namespace TEAMModelOS.SDK.Models
         /// 头像
         /// </summary>
         public string picture { get; set; }
-
+        public string tmdid { get; set; }
+        public string mobile { get; set; }
+        public string mail { get; set; }
     }
     public class ParentChildren
     {

+ 6 - 2
TEAMModelOS.SDK/Models/Cosmos/Student/Student.cs

@@ -43,10 +43,10 @@ namespace TEAMModelOS.SDK.Models
         public long createTime { get; set; }
         //public List<StudentParent> parents { get; set; }= new List<StudentParent>();
     }
-    public class StudentParent
+    public class Guardian
     {
         //绑定信息的key(手机号,邮箱,醍摩豆id)
-        public List<BindKey> bindKey { get; set; } = new List<BindKey>();
+       // public List<BindKey> bindKey { get; set; } = new List<BindKey>();
         //姓名 姓名
         public string name { get; set; }
         //监护人:父亲,母亲,或者其他监护人
@@ -55,6 +55,10 @@ namespace TEAMModelOS.SDK.Models
         /// 头像
         /// </summary>
         public string picture { get; set; }
+        public string tmdid { get; set; }
+        public string mobile { get; set; }
+        public string mail { get; set; }
+
     }
     public class BindKey
     {

+ 23 - 3
TEAMModelOS/Controllers/Both/LessonRecordController.cs

@@ -287,6 +287,11 @@ namespace TEAMModelOS.Controllers
                 roles = _roles.ToJsonString().ToObject<List<string>>();
             }
             if (!request.TryGetProperty("scope", out JsonElement _scope)) return BadRequest();
+            request.TryGetProperty("managePage", out JsonElement _managePage);
+            bool managePage = false;
+            if (_managePage.ValueKind.Equals(JsonValueKind.True)) {
+                managePage = true;
+            }
             StringBuilder sql = new StringBuilder();
             sql.Append("select c.id,c.groupIds,c.courseId from c   ");
             Dictionary<string ,object> dict =  GetLessonCond(request);
@@ -381,8 +386,11 @@ namespace TEAMModelOS.Controllers
                 }
                 sqlShow = $" and (array_contains(c.show,'student') or array_contains(c.show,'all')  {autoSql} ) ";
             }
-            
-            cosmosDbQuery.QueryText = cosmosDbQuery.QueryText.Replace("where", $" where (c.status<>404 or IS_DEFINED(c.status) = false ) and  array_length(c.groupIds)>0 {sqlPrivate} {sqlShow}  and  ");
+            string sql_status_managePage = " (c.status<>404 or IS_DEFINED(c.status) = false ) and ";
+            if (managePage) {
+                sql_status_managePage = "";
+            }
+            cosmosDbQuery.QueryText = cosmosDbQuery.QueryText.Replace("where", $" where {sql_status_managePage} array_length(c.groupIds)>0 {sqlPrivate} {sqlShow}  and  ");
             List<LessonRecord> records = new List<LessonRecord>();
             await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname).GetItemQueryIterator<LessonRecord>(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey(code) }))
             {
@@ -621,6 +629,12 @@ namespace TEAMModelOS.Controllers
                 roles = _roles.ToJsonString().ToObject<List<string>>();
             }
             if (!request.TryGetProperty("scope", out JsonElement _scope)) return BadRequest();
+            request.TryGetProperty("managePage", out JsonElement _managePage);
+            bool managePage = false;
+            if (_managePage.ValueKind.Equals(JsonValueKind.True))
+            {
+                managePage = true;
+            }
             StringBuilder sql = new StringBuilder();
             sql.Append("select   value(c) from c ");
             int pageCount = 10;
@@ -736,7 +750,13 @@ namespace TEAMModelOS.Controllers
                     }
                     sqlShow = $" and (array_contains(c.show,'student') or array_contains(c.show,'all')  {autoSql} ) ";
                 }
-                cosmosDbQuery.QueryText = cosmosDbQuery.QueryText.Replace("where", $" where (c.status<>404 or IS_DEFINED(c.status) = false ) and  array_length(c.groupIds)>0 {sqlPrivate}  {sqlShow} and  ");
+
+                string sql_status_managePage = "(c.status<>404 or IS_DEFINED(c.status) = false ) and  ";
+                if (managePage)
+                {
+                    sql_status_managePage = "";
+                }
+                cosmosDbQuery.QueryText = cosmosDbQuery.QueryText.Replace("where", $" where  {sql_status_managePage}  array_length(c.groupIds)>0 {sqlPrivate}  {sqlShow} and  ");
                 await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname)
                    .GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, continuationToken: continuationToken,
                    requestOptions: new QueryRequestOptions() { MaxItemCount = pageCount, PartitionKey = new PartitionKey(code) }))