Browse Source

Merge branch 'develop' into Ruby/Tpe

ruby 1 year ago
parent
commit
35193f5897
100 changed files with 6474 additions and 10484 deletions
  1. 2 0
      .gitignore
  2. 0 635
      TEAMModelAPI/Controllers/Business/CourseController.cs
  3. 0 565
      TEAMModelAPI/Controllers/Business/ExamController.cs
  4. 0 506
      TEAMModelAPI/Controllers/Business/GroupListController.cs
  5. 0 172
      TEAMModelAPI/Controllers/Business/RoomController.cs
  6. 0 91
      TEAMModelAPI/Controllers/Business/SchoolController.cs
  7. 0 351
      TEAMModelAPI/Controllers/Business/TeacherController.cs
  8. 0 26
      TEAMModelAPI/Program.cs
  9. 0 31
      TEAMModelAPI/Properties/launchSettings.json
  10. 0 142
      TEAMModelAPI/Startup.cs
  11. 0 14
      TEAMModelAPI/TEAMModelAPI.csproj
  12. 0 72
      TEAMModelAPI/appsettings.Development.json
  13. 0 22
      TEAMModelAPI/appsettings.json
  14. 0 2
      TEAMModelAPI/说明.md
  15. 1 1
      TEAMModelBI/ClientApp/package.json
  16. 1 1
      TEAMModelBI/ClientApp/public/index.html
  17. 29 1
      TEAMModelBI/ClientApp/src/api/index.js
  18. BIN
      TEAMModelBI/ClientApp/src/assets/img/default1.png
  19. BIN
      TEAMModelBI/ClientApp/src/assets/img/default2.png
  20. BIN
      TEAMModelBI/ClientApp/src/assets/img/default3.png
  21. BIN
      TEAMModelBI/ClientApp/src/assets/img/default4.png
  22. BIN
      TEAMModelBI/ClientApp/src/assets/img/last-cost.png
  23. BIN
      TEAMModelBI/ClientApp/src/assets/img/notspecial-icon.png
  24. BIN
      TEAMModelBI/ClientApp/src/assets/img/now-cost.png
  25. BIN
      TEAMModelBI/ClientApp/src/assets/img/special-icon.png
  26. 1 0
      TEAMModelBI/ClientApp/src/components/echarts/Xline.vue
  27. 83 0
      TEAMModelBI/ClientApp/src/components/echarts/commonRadar.vue
  28. 2 0
      TEAMModelBI/ClientApp/src/main.js
  29. 18 0
      TEAMModelBI/ClientApp/src/router/index.js
  30. 1 0
      TEAMModelBI/ClientApp/src/static/country.json
  31. 16 2
      TEAMModelBI/ClientApp/src/store/index.js
  32. 80 0
      TEAMModelBI/ClientApp/src/store/module/config.js
  33. 3 1
      TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue
  34. 35 3
      TEAMModelBI/ClientApp/src/view/common/aside.vue
  35. 62 48
      TEAMModelBI/ClientApp/src/view/index/index.vue
  36. 156 0
      TEAMModelBI/ClientApp/src/view/issueCoupons/consolidationCoupon.vue
  37. 986 0
      TEAMModelBI/ClientApp/src/view/issueCoupons/crteadCoupon.vue
  38. 22 0
      TEAMModelBI/ClientApp/src/view/issueCoupons/index.vue
  39. 181 0
      TEAMModelBI/ClientApp/src/view/issueCoupons/notice.vue
  40. 225 15
      TEAMModelBI/ClientApp/src/view/product/index.vue
  41. 37 18
      TEAMModelBI/ClientApp/src/view/schoolServe/school.vue
  42. 2 2
      TEAMModelBI/ClientApp/src/view/schoolmanage/schoolAnalyse.vue
  43. 93 15
      TEAMModelBI/ClientApp/src/view/systemConfig/pushmsg/createdpush.vue
  44. 4 1
      TEAMModelBI/ClientApp/src/view/systemConfig/pushmsg/index.vue
  45. 1118 0
      TEAMModelBI/ClientApp/src/view/systemConfig/server/index.vue
  46. 728 115
      TEAMModelBI/ClientApp/src/view/userInquire/details.vue
  47. 126 109
      TEAMModelBI/ClientApp/src/view/userInquire/ies.vue
  48. 158 38
      TEAMModelBI/ClientApp/src/view/userInquire/index.vue
  49. 103 68
      TEAMModelBI/ClientApp/src/view/userInquire/iot.vue
  50. 80 24
      TEAMModelBI/ClientApp/src/view/userInquire/socrates.vue
  51. 7 2
      TEAMModelBI/ClientApp/src/view/userInquire/ticket.vue
  52. 304 0
      TEAMModelBI/ClientApp/src/view/userInquire/updCodeW.vue
  53. 67 15
      TEAMModelBI/ClientApp/src/view/userInquire/userdetail.vue
  54. 2 2
      TEAMModelBI/Controllers/BIBlob/AnalyseFileController.cs
  55. 205 0
      TEAMModelBI/Controllers/BICommon/BICouponController.cs
  56. 8 2
      TEAMModelBI/Controllers/BICommon/BINoticeController.cs
  57. 109 3
      TEAMModelBI/Controllers/BIHome/OnLineController.cs
  58. 83 73
      TEAMModelBI/Controllers/BINormal/BatchAreaController.cs
  59. 18 3
      TEAMModelBI/Controllers/BIProductAnalysis/ProductAnalysisController.cs
  60. 124 0
      TEAMModelBI/Controllers/BISchool/BatchSchoolController.cs
  61. 170 0
      TEAMModelBI/Controllers/BISchool/SchoolController.cs
  62. 1 1
      TEAMModelBI/Controllers/BITest/Ies5TestController.cs
  63. 832 197
      TEAMModelBI/Controllers/BITmid/TmidController.cs
  64. 35 7
      TEAMModelBI/Controllers/Census/SchoolController.cs
  65. 20 21
      TEAMModelBI/Controllers/RepairApi/InitialAreaController.cs
  66. 2 1
      TEAMModelBI/Controllers/RepairApi/SchoolRepController.cs
  67. 0 113
      TEAMModelBI/Properties/ServiceDependencies/teammodelbi-rc - Web Deploy/profile.arm.json
  68. 3 3
      TEAMModelBI/TEAMModelBI.csproj
  69. 131 0
      TEAMModelBI/Tool/Extension/GeoRegion.cs
  70. 0 264
      TEAMModelFunction/.gitignore
  71. 0 548
      TEAMModelFunction/ActivityHttpTrigger.cs
  72. 0 342
      TEAMModelFunction/CourseServiceBus.cs
  73. 0 89
      TEAMModelFunction/LessonHttpTrigger.cs
  74. 0 155
      TEAMModelFunction/MonitorCosmosDB.cs
  75. 0 1033
      TEAMModelFunction/MonitorServicesBus.cs
  76. 0 175
      TEAMModelFunction/Properties/ServiceDependencies/TEAMModelOSFunction - Zip Deploy/profile.arm.json
  77. 0 113
      TEAMModelFunction/Properties/ServiceDependencies/TEAMModelOSFunction - Zip 部署/profile.arm.json
  78. 0 113
      TEAMModelFunction/Properties/ServiceDependencies/TEAMModelOSFunction - 压缩部署/profile.arm.json
  79. 0 175
      TEAMModelFunction/Properties/ServiceDependencies/teammodelos-func-v4 - Zip Deploy/profile.arm.json
  80. 0 175
      TEAMModelFunction/Properties/ServiceDependencies/teammodelosfunction-test - Zip Deploy/profile.arm.json
  81. 0 175
      TEAMModelFunction/Properties/ServiceDependencies/teammodelosfunction__test - 压缩部署/profile.arm.json
  82. 0 8
      TEAMModelFunction/Properties/launchSettings.json
  83. 0 3
      TEAMModelFunction/Properties/serviceDependencies.json
  84. 0 3
      TEAMModelFunction/Properties/serviceDependencies.local.json
  85. 0 611
      TEAMModelFunction/ScsApisHttpTrigger.cs
  86. 0 34
      TEAMModelFunction/Startup.cs
  87. 0 43
      TEAMModelFunction/TEAMModelFunction.csproj
  88. 0 427
      TEAMModelFunction/TriggerCorrect.cs
  89. 0 997
      TEAMModelFunction/TriggerExam.cs
  90. 0 170
      TEAMModelFunction/TriggerExamLite.cs
  91. 0 229
      TEAMModelFunction/TriggerHomework.cs
  92. 0 175
      TEAMModelFunction/TriggerStudy.cs
  93. 0 398
      TEAMModelFunction/TriggerSurvey.cs
  94. 0 318
      TEAMModelFunction/TriggerVote.cs
  95. 0 19
      TEAMModelFunction/host.json
  96. 0 21
      TEAMModelFunction/local.settings.json
  97. 0 35
      TEAMModelGrpc/Dockerfile
  98. 0 46
      TEAMModelGrpc/GrpcHealthCheck/GrpcHealthChecksEndpointRouteBuilderExtensions.cs
  99. 0 56
      TEAMModelGrpc/GrpcHealthCheck/GrpcHealthChecksPublisher.cs
  100. 0 0
      TEAMModelGrpc/GrpcHealthCheck/GrpcHealthChecksServiceExtensions.cs

+ 2 - 0
.gitignore

@@ -267,3 +267,5 @@ TEAMModelOS.FunctionV4/Properties/ServiceDependencies/TEAMModel-Test - Zip Deplo
 TEAMModelOS.FunctionV4/Properties/ServiceDependencies/teammodelfunction-rc - Zip Deploy/
 /TEAMModelOS.FunctionV4/Properties/serviceDependencies.teammodelfunction-rc - Zip Deploy.json
 /TEAMModelOS/.local-chromium
+
+TEAMModelBI/Properties/ServiceDependencies/teammodelbi-RC - Web Deploy/profile.arm.json

+ 0 - 635
TEAMModelAPI/Controllers/Business/CourseController.cs

@@ -1,635 +0,0 @@
-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 = "获取课程列表信息", RWN = "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 = "课程详细信息", RWN = "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 = "试卷和评测的条件信息", RWN = "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 = "课程详细信息", RWN = "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 = "更新课程的排课信息", RWN = "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
-            });
-        }
-        
-    }
-}

+ 0 - 565
TEAMModelAPI/Controllers/Business/ExamController.cs

@@ -1,565 +0,0 @@
-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 = "试卷和评测的条件信息", RWN = "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; }
-        }
-
-
-    }
-}

+ 0 - 506
TEAMModelAPI/Controllers/Business/GroupListController.cs

@@ -1,506 +0,0 @@
-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 = "学校名单列表", RWN = "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 = "获取名单详细信息和成员信息", RWN = "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 = "导入行政班学生", RWN = "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 = "更新行政班学生", RWN = "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 = "移除行政班学生", RWN = "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 = "创建或更新教学班", RWN = "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 = "导入教学班学生", RWN    = "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 = "移除教学班学生", RWN = "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 = "移除的名单人员为空!" }); 
-            }
-        }
-    }
-}

+ 0 - 172
TEAMModelAPI/Controllers/Business/RoomController.cs

@@ -1,172 +0,0 @@
-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 = "获取物理教室列表", RWN= "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 = "获取物理教室详细信息", RWN= "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 = "创建或更新教学班", RWN= "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 });
-        }
-    }
-}

+ 0 - 91
TEAMModelAPI/Controllers/Business/SchoolController.cs

@@ -1,91 +0,0 @@
-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 = "合作商获取可访问的学校列表", RWN= "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 = "学校基础信息", RWN= "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
-            });
-        }
-    }
-}

+ 0 - 351
TEAMModelAPI/Controllers/Business/TeacherController.cs

@@ -1,351 +0,0 @@
-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 - 26
TEAMModelAPI/Program.cs

@@ -1,26 +0,0 @@
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace TEAMModelAPI
-{
-    public class Program
-    {
-        public static void Main(string[] args)
-        {
-            CreateHostBuilder(args).Build().Run();
-        }
-
-        public static IHostBuilder CreateHostBuilder(string[] args) =>
-            Host.CreateDefaultBuilder(args)
-                .ConfigureWebHostDefaults(webBuilder =>
-                {
-                    webBuilder.UseStartup<Startup>();
-                });
-    }
-}

+ 0 - 31
TEAMModelAPI/Properties/launchSettings.json

@@ -1,31 +0,0 @@
-{
-  "$schema": "http://json.schemastore.org/launchsettings.json",
-  "iisSettings": {
-    "windowsAuthentication": false,
-    "anonymousAuthentication": true,
-    "iisExpress": {
-      "applicationUrl": "http://localhost:58541/",
-      "sslPort": 44333
-    }
-  },
-  "profiles": {
-    "IIS Express": {
-      "commandName": "IISExpress",
-      "launchBrowser": true,
-      "launchUrl": "http://doc.teammodel.cn:4999/web/#/16",
-      "environmentVariables": {
-        "ASPNETCORE_ENVIRONMENT": "Development"
-      }
-    },
-    "TEAMModelAPI": {
-      "commandName": "Project",
-      "launchBrowser": true,
-      "launchUrl": "http://doc.teammodel.cn:4999/web/#/16",
-      "environmentVariables": {
-        "ASPNETCORE_ENVIRONMENT": "Development"
-      },
-      "applicationUrl": "https://localhost:5001;http://localhost:5000",
-      "dotnetRunMessages": "true"
-    }
-  }
-}

+ 0 - 142
TEAMModelAPI/Startup.cs

@@ -1,142 +0,0 @@
- using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.HttpsPolicy;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using TEAMModelOS.Models;
-using TEAMModelOS.SDK.DI;
-using System.IdentityModel.Tokens.Jwt;
-using Microsoft.AspNetCore.Authentication.JwtBearer;
-using Microsoft.IdentityModel.Tokens;
-using TEAMModelOS.Filter;
-using TEAMModelOS.SDK.Helper.Common.ReflectorExtensions;
-using System.Reflection;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.Models;
-
-namespace TEAMModelAPI
-{
-    public class Startup
-    {
-        readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
-        public Startup(IConfiguration configuration)
-        {
-            Configuration = configuration;
-        }
-
-        public IConfiguration Configuration { get; }
-
-        // This method gets called by the runtime. Use this method to add services to the container.
-        public void ConfigureServices(IServiceCollection services)
-        {
-           
-            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
-            services.AddAuthentication(options => options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
-                .AddJwtBearer(options => //AzureADJwtBearer
-                {
-                    //options.SaveToken = true; //驗證令牌由服務器生成才有效,不適用於服務重啟或分布式架構
-                    options.Authority = Configuration["Option:Authority"];
-                    options.Audience = Configuration["Option:Audience"];
-                    options.RequireHttpsMetadata = true;
-                    options.TokenValidationParameters = new TokenValidationParameters
-                    {
-                        RoleClaimType = "roles",
-                        ValidAudiences = new string[] { Configuration["Option:Audience"], $"api://{Configuration["Option:Audience"]}" }
-                    };
-                    options.Events = new JwtBearerEvents();
-                    //下列事件有需要紀錄則打開
-                    //options.Events.OnMessageReceived = async context => { await Task.FromResult(0); };
-                    //options.Events.OnForbidden = async context => { await Task.FromResult(0); };
-                    //options.Events.OnChallenge = async context => { await Task.FromResult(0); };
-                    //options.Events.OnAuthenticationFailed = async context => { await Task.FromResult(0); };
-                    options.Events.OnTokenValidated = async context =>
-                    {
-                        if (!context.Principal.Claims.Any(x => x.Type.Equals("http://schemas.microsoft.com/identity/claims/scope")) //ClaimConstants.Scope
-                        && !context.Principal.Claims.Any(y => y.Type .Equals("roles"))) //ClaimConstants.Roles //http://schemas.microsoft.com/ws/2008/06/identity/claims/role
-                        {
-                            //TODO 需處理額外授權非角色及範圍的訪問異常紀錄
-                            throw new UnauthorizedAccessException("Neither scope or roles claim was found in the bearer token.");
-                        }
-                        await Task.FromResult(0);
-                    };
-                });
-            //設定跨域請求
-            services.AddCors(options =>
-            {
-                options.AddPolicy(MyAllowSpecificOrigins,
-                builder =>
-                {
-                    builder.WithOrigins("http://teammodelos-test.chinacloudsites.cn",
-                                        "https://www.teammodel.cn", "https://localhost:5001",
-                                        "http://localhost:5000", "http://localhost:64524",
-                                        "https://localhost:44341", "https://localhost:8888", "http://localhost:8888")
-                    .AllowAnyHeader()
-                    .AllowAnyMethod();
-                });
-            });
-            services.AddControllers().AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = false; });
-            services.AddAzureStorage(Configuration.GetValue<string>("Azure:Storage:ConnectionString"));
-            services.AddAzureRedis(Configuration.GetValue<string>("Azure:Redis:ConnectionString"));
-            services.AddAzureCosmos(Configuration.GetValue<string>("Azure:Cosmos:ConnectionString"));
-            services.AddAzureServiceBus(Configuration.GetValue<string>("Azure:ServiceBus:ConnectionString"));
-            services.AddMemoryCache();
-            services.AddSnowflakeId(Convert.ToInt64(Configuration.GetValue<string>("Option:LocationNum")), 1);
-            services.AddHttpClient();
-            services.AddHttpClient<DingDing>();
-            services.AddCoreAPIHttpService(Configuration);
-            //HttpContextAccessor,并用来访问HttpContext。(提供組件或非控制器服務存取HttpContext)
-            services.AddHttpContextAccessor();
-            services.Configure<Option>(options => Configuration.GetSection("Option").Bind(options));
-           
-        }
-
-        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
-        public async void Configure(IApplicationBuilder app, IWebHostEnvironment env,AzureStorageFactory azureStorage)
-        {
-            if (env.IsDevelopment())
-            {
-                app.UseDeveloperExceptionPage();
-            }
-
-            app.UseHttpsRedirection();
-
-            app.UseRouting();
-            app.UseCors(MyAllowSpecificOrigins); //使用跨域設定
-            app.UseAuthentication();
-            app.UseAuthorization();
-            app.UseEndpoints(endpoints =>
-            {
-                endpoints.MapControllers();
-            });
-#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[] { "TEAMModelAPI" });
-            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)
-                {
-                    await table.SaveOrUpdate<OpenApi>(item);
-                }
-            } catch (Exception ex) {
-                Console.WriteLine(ex.Message);
-            }
-#endif
-        }
-    }
-}

+ 0 - 14
TEAMModelAPI/TEAMModelAPI.csproj

@@ -1,14 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
-
-  <PropertyGroup>
-    <TargetFramework>net6.0</TargetFramework>
-  </PropertyGroup>
-
-  <ItemGroup>
-    <None Remove="Controllers\Business\说明.md" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <ProjectReference Include="..\TEAMModelOS.SDK\TEAMModelOS.SDK.csproj" />
-  </ItemGroup>
-</Project>

+ 0 - 72
TEAMModelAPI/appsettings.Development.json

@@ -1,72 +0,0 @@
-{
-  "Logging": {
-    "LogLevel": {
-      "Default": "Information",
-      "Microsoft": "Warning",
-      "Microsoft.Hosting.Lifetime": "Information"
-    }
-  },
-  "AllowedHosts": "*",
-  "Option": {
-    "Location": "China-Dep",
-    "LocationNum": "1",
-    "HostName": "localhost:5001",
-    "AllowedHosts": [ "localhost", "*.teammodel.cn", "*.teammodel.net", "*.habookaclass.biz", "test" ],
-    "Issuer": "www.teammodel.cn",
-    "JwtSecretKey": "fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=",
-    "Exp": 86400,
-    "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
-    "HttpTrigger": "https://teammodelosfunction-test.chinacloudsites.cn/api/"
-  },
-  "Azure": {
-    "Storage": {
-      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodeltest;AccountKey=O2W2vadCqexDxWO+px+QK7y1sHwsYj8f/WwKLdOdG5RwHgW/Dupz9dDUb4c1gi6ojzQaRpFUeAAmOu4N9E+37A==;EndpointSuffix=core.chinacloudapi.cn"
-    },
-    "Cosmos": {
-      "ConnectionString": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;"
-    },
-    "Redis": {
-      "ConnectionString": "52.130.252.100:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240"
-    },
-    "ServiceBus": {
-      "ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
-      "ActiveTask": "dep-active-task",
-      "ItemCondQueue": "dep-itemcond"
-    }
-    //"Storage": {
-    //  "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelos;AccountKey=Dl04mfZ9hE9cdPVO1UtqTUQYN/kz/dD/p1nGvSq4tUu/4WhiKcNRVdY9tbe8620nPXo/RaXxs+1F9sVrWRo0bg==;EndpointSuffix=core.chinacloudapi.cn"
-    //},
-    //"Cosmos": {
-    //  "ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;"
-    //},
-    //"Redis": {
-    //  "ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False"
-    //},
-    //"ServiceBus": {
-    //  "ConnectionString": "Endpoint=sb://coreiotservicebuscnpro.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=llRPBMDJG9w1Nnifj+pGhV0g4H2REcq0PjvX2qqpcOg=",
-    //  "ActiveTask": "active-task",
-    //  "ItemCondQueue": "itemcond"
-    //}
-  },
-  "HaBookAuth": {
-    "CoreId": {
-      "userinfo": "https://api2.teammodel.cn/Oauth2/GetUserInfos"
-    },
-    "Account": "https://account.teammodel.cn",
-    "CoreAPI": "https://api2.teammodel.cn",
-    "CoreService": {
-      "clientID": "c7317f88-7cea-4e48-ac57-a16071f7b884",
-      "clientSecret": "kguxh:V.PLmxBdaI@jnrTrDSth]A3346",
-      "deviceinfo": "https://api2.teammodel.cn/oauth2/getdeviceinfos",
-      "sendnotification": "https://api2.teammodel.net/service/sendnotification",
-      "getnotification": "https://api2.teammodel.net/service/getnotification",
-      "delnotification": "https://api2.teammodel.net/service/delnotification"
-    }
-  },
-  "DingDingAuth": {
-    "Agentld": "1290158212",
-    "appKey": "dingrucgsnt8p13rfbgd",
-    "appSecret": "Gyx_N57yZslhQOAhAPlvmCwOp_qTm1DScKbd5OoOE0URAW4eViYA2Sk_ZxKb-8WG",
-    "getuserinfo_bycode": "https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=xxx&timestamp=xxx&signature=xxx"
-  }
-}

+ 0 - 22
TEAMModelAPI/appsettings.json

@@ -1,22 +0,0 @@
-{
-  "Logging": {
-    "LogLevel": {
-      "Default": "Information",
-      "Microsoft": "Warning",
-      "Microsoft.Hosting.Lifetime": "Information"
-    }
-  },
-  "AllowedHosts": "*",
-  "Option": {
-    "Location": "China",
-    "LocationNum": "8",
-    "HostName": "localhost:5001",
-    "AllowedHosts": [ "localhost", "*.teammodel.cn", "*.teammodel.net", "*.habookaclass.biz", "test" ],
-    "Authority": "https://login.chinacloudapi.cn/4807e9cf-87b8-4174-aa5b-e76497d7392b/v2.0", //China:"https://login.chinacloudapi.cn/4807e9cf-87b8-4174-aa5b-e76497d7392b/v2.0", //Global:"https://login.microsoftonline.com/73a2bcc5-fe99-4566-aa8a-07e7bb287df1/v2.0"
-    "Audience": "72643704-b2e7-4b26-b881-bd5865e7a7a5", //China:"72643704-b2e7-4b26-b881-bd5865e7a7a5",Global:"8768b06f-c5c5-4b0c-abfb-d7ded354626d"
-    "Issuer": "www.teammodel.cn",
-    "JwtSecretKey": "fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=",
-    "Exp": 86400,
-    "IdTokenSalt": "8263692E2213497BB55E74792B7900B4"
-  }
-}

+ 0 - 2
TEAMModelAPI/说明.md

@@ -1,2 +0,0 @@
-企业接入,也必须有学校进行授权。企业业务允许的授权范围内。
-请求端,需要在开放平台备注域名,ip白名单。

+ 1 - 1
TEAMModelBI/ClientApp/package.json

@@ -27,7 +27,7 @@
         "less": "^4.1.2",
         "qs": "^6.10.1",
         "splitpanes": "^3.1.1",
-        "vue": "^3.2.0",
+        "vue": "^3.2.26",
         "vue-clipboard3": "^2.0.0",
         "vue-i18n": "^9.2.2",
         "vue-loader-v16": "npm:vue-loader@^16.0.0-alpha.3",

+ 1 - 1
TEAMModelBI/ClientApp/public/index.html

@@ -12,7 +12,7 @@
     </title>
 </head>
 <script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
-<script src="https://at.alicdn.com/t/c/font_2934132_zba0ifa4ele.js"></script>
+<script src="https://at.alicdn.com/t/c/font_2934132_mzapgo0jijg.js"></script>
 <script src="../src/access/iconfont.js"></script>
 
 <body>

+ 29 - 1
TEAMModelBI/ClientApp/src/api/index.js

@@ -219,6 +219,14 @@ export default {
     getallSchool(data) {
         return post('/batchschool/get-allscinfo', data)
     },
+    //透過位置取得學校資料
+    getSchooBasicInfo(data) {
+        return post('/batchschool/get-school-basic-info', data)
+    },
+    //弱歸戶
+    updUserSchoolW(data) {
+        return post('/batchschool/upd-user-schoolw', data)
+    },    
 
     //首页dashboard数据接口
     //获取各城市的学校数量(bar)
@@ -578,5 +586,25 @@ export default {
     /*ID查询 相关*/
     getUserdatas(data) {
         return post('/tmid/get-tmidstics',data)
-     }
+    },
+    /*ID查询 IOT相关*/
+    getUserIOT(data) {
+        return post('/tmid/get-tmid-iot',data)
+    },
+
+    /*優惠券相關*/
+    // 建立優惠券
+    crtCoupon(data) {
+        return post('/coupon/create-coupon',data)
+    },
+    // 歸戶
+    consolidationCoupon(data) {
+        return post('/coupon/consolidation-coupon',data)
+    },
+
+    /*簡版通知*/
+    // 發送
+    pushNotify(data) {
+        return post('/coupon/push-notify',data)
+    }
 }

BIN
TEAMModelBI/ClientApp/src/assets/img/default1.png


BIN
TEAMModelBI/ClientApp/src/assets/img/default2.png


BIN
TEAMModelBI/ClientApp/src/assets/img/default3.png


BIN
TEAMModelBI/ClientApp/src/assets/img/default4.png


BIN
TEAMModelBI/ClientApp/src/assets/img/last-cost.png


BIN
TEAMModelBI/ClientApp/src/assets/img/notspecial-icon.png


BIN
TEAMModelBI/ClientApp/src/assets/img/now-cost.png


BIN
TEAMModelBI/ClientApp/src/assets/img/special-icon.png


+ 1 - 0
TEAMModelBI/ClientApp/src/components/echarts/Xline.vue

@@ -59,6 +59,7 @@ class InitChart {
     this.state.chart.setOption({
       tooltip: datas.tooltip ? datas.tooltip : '',
       legend: datas.legend ? datas.legend : '',
+      toolbox: datas.toolbox? datas.toolbox : '',
       grid: datas.grid ? datas.grid : '',
       xAxis: datas.xAxis ? datas.xAxis : '',
       yAxis: datas.yAxis ? datas.yAxis : '',

+ 83 - 0
TEAMModelBI/ClientApp/src/components/echarts/commonRadar.vue

@@ -0,0 +1,83 @@
+<!--基础折线图-->
+<template>
+    <div ref="myEcharts" :style="{ height, width }"></div>
+  </template>
+  <script>
+  import { ref, onMounted, nextTick, watch, getCurrentInstance } from 'vue'
+  import * as echarts from 'echarts'
+  export default {
+    name: 'baseBar',
+    props: {
+      width: {
+        type: String,
+        default: '100%',
+      },
+      height: {
+        type: String,
+        default: '100%',
+      },
+      radarData: {
+        type: Object,
+        default: () => { },
+      },
+      title: {
+        type: String,
+        default: '',
+      },
+    },
+    setup (props) {
+      const myEcharts = ref(null)
+      let { proxy } = getCurrentInstance()
+      const chart = new InitChart(props, myEcharts)
+      onMounted(() => {
+        chart.init(props.radarData, proxy)
+      })
+      watch(
+        props,
+        (nweProps) => {
+          nextTick(() => {
+            nweProps ? chart.init(props.radarData, proxy) : ''
+          })
+        },
+        { immediate: true, deep: true }
+      )
+      return {
+        myEcharts,
+      }
+    },
+  }
+  class InitChart {
+    constructor(props, myEcharts) {
+      this.props = props
+      this.myEcharts = myEcharts
+      this.state = {
+        chart: null,
+      }
+    }
+    init (datas, proxy) {
+      console.log(datas, '简单Radar的调用')
+      this.state.chart && this.destory()
+      this.state.chart = echarts.init(this.myEcharts.value)
+      this.state.chart.setOption({
+        backgroundColor: datas.backgroundColor? datas.backgroundColor : '',
+        tooltip: datas.tooltip ? datas.tooltip : '',
+        grid: datas.grid ? datas.grid : '',
+        radar: datas.radar? datas.radar : '',
+        series: datas.series ? datas.series : '',
+      })
+      window.addEventListener('resize', () => {
+        this.state.chart.resize()
+      })
+    }
+  
+    destory () {
+      this.state.chart.dispose()
+      window.removeEventListener('resize', () => {
+        console.log('事件移除')
+      })
+    }
+  }
+  </script>
+  <style lang="less"></style>
+  
+  

+ 2 - 0
TEAMModelBI/ClientApp/src/main.js

@@ -18,6 +18,8 @@ import PersonalPhoto from './components/public/personalPhoto/index.vue'
 import zhCn from "element-plus/lib/locale/lang/zh-cn";
 import 'dayjs/locale/zh-cn';
 
+store.dispatch('config/checkSrvAdr');// 檢查現在站的位置
+
 const app = createApp(App)
 app.config.globalProperties.$api = axios
 app.config.globalProperties.$access = inspect

+ 18 - 0
TEAMModelBI/ClientApp/src/router/index.js

@@ -223,6 +223,24 @@ const routes = [{
                 isShow: true,
                 component: () => require.ensure([], (require) => require(`@/view/userInquire/index.vue`))
             },
+            //服务器管理
+            {
+                name: "server",
+                path: "server",
+                permission: "",
+                roles: ['admin'],
+                isShow: true,
+                component: () => require.ensure([], (require) => require(`@/view/systemConfig/server/index.vue`))
+            },
+            //優惠券發行
+            {
+                name: 'issuecoupons',
+                path: 'issuecoupons',
+                permission: "",
+                roles: ['admin'],
+                isShow: true,
+                component: () => require.ensure([], (require) => require(`@/view/issueCoupons/index.vue`))
+            },
         ]
     },
     //消息通知跳转页面

File diff suppressed because it is too large
+ 1 - 0
TEAMModelBI/ClientApp/src/static/country.json


+ 16 - 2
TEAMModelBI/ClientApp/src/store/index.js

@@ -1,4 +1,6 @@
 import { createStore } from 'vuex'
+import config from './module/config'
+
 export default createStore({
     state: {
         organizationData: [], //组织架构数据
@@ -22,7 +24,9 @@ export default createStore({
         areaClickschool: {},
         areaClickCounselor: '',
         areaClickRoles: '',
-        msgData: {}
+        msgData: {},
+        transmitvalue:[],
+        hiteachVs:''
     },
     mutations: {
         //修改组织架构
@@ -99,9 +103,19 @@ export default createStore({
         //复用消息
         copyMsgs(state, value) {
             state.msgData = value
+        },
+        //保存产品使用->ID查询用户列表
+        transmitUsers(state,value){
+            state.transmitvalue=value
+        },
+        //ID查询内  获取HiTeach 最新版本号
+        getHiteachv(state,value){
+            state.hiteachVs=value
         }
     },
     actions: {},
     getters: {},
-    modules: {}
+    modules: {
+        config
+    }
 })

+ 80 - 0
TEAMModelBI/ClientApp/src/store/module/config.js

@@ -0,0 +1,80 @@
+export default {
+    namespaced: true,
+    state: {
+        srvAdr: '', // 伺服器位置 China, Global
+        srvAdrType: '', // 正式站 product 測試站 test
+        China: {
+            srvAdr: 'China',
+            domainUrl: [
+                {
+                    station: 'product',
+                    url: 'https://bi.teammodel.cn'
+                },
+                {
+                    station: 'rc',
+                    url: 'https://bi-rc.teammodel.cn'
+                },
+            ]
+        },
+        Global: {
+            srvAdr: 'Global',
+            domainUrl: [
+                {
+                    station: 'product',
+                    url: 'https://bi.teammodel.net'
+                },
+                {
+                    station: 'rc',
+                    url: 'https://bi-rc.teammodel.net'
+                },
+            ]
+        }
+    },
+    getters: {
+        getSrvAdr: state => state.srvAdr,
+    },
+    mutations: {
+        setSrvAdr(state, data) {
+            state.srvAdr = data
+        },
+        setSrvAdrType(state, data) {
+            state.srvAdrType = data
+        }
+    },
+    actions: {
+        checkSrvAdr(context) {
+            let domainUrl = window.location.hostname
+
+            let domainUrlArray = []
+
+            context.state.China.domainUrl.forEach(function (item) {
+                item.srvAdr = 'China'
+                domainUrlArray.push(item)
+            })
+            context.state.Global.domainUrl.forEach(function (item) {
+                item.srvAdr = 'Global'
+                domainUrlArray.push(item)
+            })
+
+            let stationSetting = domainUrlArray.find(function (item) {
+                return item.url.indexOf(domainUrl) >= 0
+            })
+
+            if (!stationSetting) {
+                stationSetting = {}
+                stationSetting.station = 'test'
+                stationSetting.srvAdr = 'Global'
+            }
+            context.commit('setSrvAdr', stationSetting.srvAdr)
+            context.commit('setSrvAdrType', stationSetting.station)
+
+            localStorage.setItem('srvAdr', stationSetting.srvAdr)
+            localStorage.setItem('station', stationSetting.station)
+
+        },
+        setSrvAdr(context, param) {
+            localStorage.setItem('srvAdr', param)
+            context.commit('setSrvAdr', param)
+        }
+    }
+}

+ 3 - 1
TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue

@@ -967,6 +967,7 @@ export default {
           (notjoinSchool.value = [],res.scInfos.forEach((item)=>{!item.areaId ? notaredSchool.push(item):''}),notaredSchool.forEach((item)=>{item.checkstate=false}),notjoinSchool.value=notaredSchool,notjoinPrimitive.value=notaredSchool,loadingSchoolList.value = false):
           ''
         })
+     console.log(notjoinSchool.value,'数据学校')
     }
     //区域内添加学校
     function areaAddschool (schoolcode) {
@@ -1730,6 +1731,7 @@ export default {
 } */
 .list-school-logo {
   width: 20%;
+  text-align: center;
 }
 
 .list-school-name {
@@ -2627,7 +2629,7 @@ export default {
 
 .details-list-school .el-image {
   width: 60%;
-  margin: 3% 0% 0% 3%;
+  /* margin: 3% 0% 0% 3%; */
 }
 
 .areamanabox .el-table__header-wrapper {

+ 35 - 3
TEAMModelBI/ClientApp/src/view/common/aside.vue

@@ -42,7 +42,7 @@
 //基础菜单
 
 import { Location, Document, Menu as IconMenu, Setting } from '@element-plus/icons'
-import { getCurrentInstance, ref, watch, onMounted, reactive, toRefs } from 'vue'
+import { getCurrentInstance, ref, watch, onMounted, reactive, toRefs, computed } from 'vue'
 import { useStore } from 'vuex'
 import { useRouter } from 'vue-router'
 import router from '@/router/index.js'
@@ -55,6 +55,9 @@ export default {
     IconMenu,
   },
   setup () {
+    const store = useStore()
+    const srvType = computed(() => store.getters["config/getSrvAdr"]);
+    
     console.log('调用了一次这个页面')
     let { proxy } = getCurrentInstance()
     let menuWidth = ref('64px')
@@ -134,13 +137,30 @@ export default {
             sort: 7,
           },
           {
-            name: '用户查询',
+            name: '用户相關',
             router: '/home/userinquire',
             icon: '#icon-a-97-yonghuchaxun',
             permission: [],
             isShow: true,
             sort: 8,
           },
+          // {
+          //   name: '服务器情况',
+          //   router: '/home/server',
+          //   icon: '#icon-fuwuqi2',
+          //   permission: [],
+          //   isShow: true,
+          //   sort: 19,
+          // },
+          {
+            name: '發優惠券',
+            router: '/home/issuecoupons',
+            icon: '#icon-Ticket',
+            permission: [],
+            isShow: true,
+            sort: 6,
+            srvType: 'Global'
+          },
         ],
       },
       {
@@ -302,8 +322,8 @@ export default {
       },
     ]
     const isCollapse = ref(true)
-    const store = useStore()
     const shenfen = ref('admin')
+
     //路由
     const routers = useRouter()
     let indexMenu = reactive({ currentRoutePath: routers.currentRoute.value.path })
@@ -384,6 +404,18 @@ export default {
           }
         }
       }
+
+      // 新增功能限制
+      for (let i in menuList.value) {
+        let menuChild = menuList.value[i]
+        for (let y in menuChild.child) {
+          let menuSrvType = menuChild.child[y].srvType
+          if(menuSrvType && menuSrvType != srvType.value){
+            menuChild.child.splice(y, 1)
+          }
+        }
+      }
+
       console.log(menuList.value, result, '菜单')
       //router内容
       let nowUrl = routers.currentRoute.value.path

+ 62 - 48
TEAMModelBI/ClientApp/src/view/index/index.vue

@@ -208,7 +208,7 @@
                 </div>
                 <div class="commonbox-versions" v-loading="loading.versions" element-loading-background="rgba(0, 0, 0, 0.2)">
                   <div class="commonbox-versions-title">
-                    <p class="versions-title-name">自訂版</p>
+                    <p class="versions-title-name">评测版</p>
                     <p class="versions-title-num">数量:
                       <span>{{ versionsData.custom.num }}</span>
                     </p>
@@ -3040,47 +3040,61 @@ export default {
       console.log()
       let marjorArr = []; let standardArr = []; let basicsArr = []; let customArr = [];
        // 專業版
-       schoolList ? schoolList.forEach((item) => {
-         (item.edition == null || item.edition.scaleVersion == null) 
-         && item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && item.service.includes('YPXSJ6NJ') 
-         ? marjorArr.push(item) : '' }) : ''
+      //  schoolList ? schoolList.forEach((item) => {
+      //    (item.edition == null || item.edition.scaleVersion == null)  && item.code ==='BIRel'
+      //    && item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && item.service.includes('YPXSJ6NJ') 
+      //    ? marjorArr.push(item) : '' }) : ''
+      //  11.14日修正  关于学校版本问题   根据edition   current /1基础   /2标准   /3专业
+      schoolList ? schoolList.forEach((item) => {
+         item.edition   && item.edition.current === 3 && item.code ==='BIRel' ? marjorArr.push(item):''
+        //  item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') &&  item.service.includes('YPXSJ6NJ') && item.code ==='BIRel'  ?  marjorArr.push(item):''
+       }) : ''
        // 標準版
-       schoolList ? schoolList.forEach((item) => { 
-        (item.edition == null || item.edition.scaleVersion == null) 
-        && item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && (!item.service.includes('YPXSJ6NJ')) ? standardArr.push(item) : '' }) : ''
+      //  schoolList ? schoolList.forEach((item) => { 
+      //   (item.edition == null || item.edition.scaleVersion == null) && item.code ==='BIRel'
+      //   && item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && (!item.service.includes('YPXSJ6NJ')) ? standardArr.push(item) : '' }) : ''
+      schoolList ? schoolList.forEach((item) => { 
+        item.edition  && item.edition.current === 2 && item.code ==='BIRel' ? standardArr.push(item):''
+        // item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && item.code ==='BIRel' ? standardArr.push(item):''
+      }) : ''
        // 基礎版
-       schoolList ? schoolList.forEach((item) => { 
-        (item.edition == null || item.edition.scaleVersion == null) 
-        && !item.service.includes('IPDYZYLC') && !item.service.includes('YMPCVCIM') ? basicsArr.push(item) : '' }) : ''
-       // 自訂版
-       schoolList ? schoolList.forEach((item) => { 
-        item.edition !== null && item.edition.scaleVersion !== null ? customArr.push(item) : '' }) : ''           
-        // res.scInfos.forEach((item)=>{
-        //   //item.versions= item.service.includes('YPXSJ6NJ') && item.service.includes('B6V5J6NP') ? '专业版':item.service.includes('YMPCVCIM') ? '标准版':'基础版'}),
-        //   if (item.edition !== null) {
-        //         if (item.edition.scaleVersion !== null && item.edition.scaleVersion !== "") {
-        //           item.versions = item.edition.scaleVersion;
-        //         } else {
-        //           item.versions = item.service.includes('YPXSJ6NJ') && item.service.includes('B6V5J6NP') ? marjorArr.push(item) : item.service.includes('YMPCVCIM') ? standardArr.push(item) : '基础版';
-        //         }
-        //       } else {
-        //         item.versions = item.service.includes('YPXSJ6NJ') && item.service.includes('B6V5J6NP') ? '专业版' : item.service.includes('YMPCVCIM') ? '标准版' : '基础版';
-        //       }
-        // }),
+      schoolList ? schoolList.forEach((item) => { 
+        item.code === 'BIRel' && (item.edition == null || (item.edition && item.edition.current == null) || (item.edition && item.edition.current === 1 && (item.edition.scaleVersion == null || item.edition.scaleVersion == ''))) ? basicsArr.push(item):''
+      }) : ''
+      //  schoolList ? schoolList.forEach((item) => { 
+      //   (item.edition == null || item.edition.scaleVersion == null) && item.code ==='BIRel'
+      //   && !item.service.includes('IPDYZYLC') && !item.service.includes('YMPCVCIM') ? basicsArr.push(item) : '' }) : ''
+      // schoolList ? schoolList.forEach((item) => { 
+      //   item.edition  &&  item.edition.current === 1 && item.code ==='BIRel' && !item.service.includes('B6V5J6NP') ? basicsArr.push(item):
+      //   item.edition ==null && item.code ==='BIRel' ? basicsArr.push(item):''
+      //   // !item.service.includes('IPDYZYLC') && !item.service.includes('YMPCVCIM') && item.code ==='BIRel' ? basicsArr.push(item):''
+      // }) : ''
+       // 评测版
+      schoolList ? schoolList.forEach((item) => { 
+        item.edition !== null && item.code === 'BIRel' && item.edition.scaleVersion == '评测版' ? customArr.push(item) : ''
+      }) : ''    
+
+        // schoolList ? schoolList.forEach((item) => {
+        //   item.service.includes('YPXSJ6NJ') && item.service.includes('B6V5J6NP') && item.service.includes('YMPCVCIM') && item.code ==='BIRel' ? marjorArr.push(item):
+        //   item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && (!item.service.includes('YPXSJ6NJ')) && item.code ==='BIRel' ? standardArr.push(item):
+        //   !item.service.includes('IPDYZYLC') && !item.service.includes('YMPCVCIM') && item.service.includes('B6V5J6NP') && item.code ==='BIRel'   ? customArr.push(item):
+        //   !item.service.includes('IPDYZYLC') && !item.service.includes('YMPCVCIM') && item.code ==='BIRel'  ? basicsArr.push(item):''
+        // }):''
+        //计算版本占比
         console.log(basicsArr,standardArr,marjorArr,customArr,'数组')
         versionsData.value.basics.num = basicsArr.length >0 ?basicsArr.length :0
-        versionsData.value.basics.proportion = (( basicsArr.length / schoolList.length) * 100).toFixed(1)
+        versionsData.value.basics.proportion = (( basicsArr.length /areaAspectsData.value[2].num) * 100).toFixed(1)
         versionsData.value.standard.num = standardArr.length >0 ? standardArr.length:0
-        versionsData.value.standard.proportion = ((standardArr.length / schoolList.length) * 100).toFixed(1)
+        versionsData.value.standard.proportion = ((standardArr.length / areaAspectsData.value[2].num) * 100).toFixed(1)
         versionsData.value.major.num = marjorArr.length >0 ?marjorArr.length:0
-        versionsData.value.major.proportion = ((marjorArr.length / schoolList.length) * 100).toFixed(1)
+        versionsData.value.major.proportion = ((marjorArr.length / areaAspectsData.value[2].num) * 100).toFixed(1)
         versionsData.value.custom.num = customArr.length >0 ? customArr.length:0
-        versionsData.value.custom.proportion = ((customArr.length / schoolList.length) * 100).toFixed(1)
+        versionsData.value.custom.proportion = ((customArr.length / areaAspectsData.value[2].num) * 100).toFixed(1)
         console.log(versionsData.value.basics.num,versionsData.value.basics.proportion,'基础')
         console.log(versionsData.value.standard.num,versionsData.value.standard.proportion,'标准')
         console.log(versionsData.value.major.num,versionsData.value.major.proportion,'专业')
         console.log( versionsData.value.custom.num,versionsData.value.custom.proportion,'自订')
-         let dataBasics = {
+        let dataBasics = {
               title: {
                 text: '{a|' + versionsData.value.basics.proportion + '}{c|%}' + '\n' + '基础版占比',
                 x: 'center',
@@ -3120,7 +3134,7 @@ export default {
                   },
                   data: [
                     {
-                      value: versionsData.value.basics.proportion,
+                      value: Number(versionsData.value.basics.proportion),
                       name: '',
                       itemStyle: {
                         normal: {
@@ -3146,7 +3160,7 @@ export default {
                       },
                     },
                     {
-                      value: 100 - 78,
+                      value: 100 - versionsData.value.basics.proportion,
                       name: '',
                       label: {
                         normal: {
@@ -3162,8 +3176,8 @@ export default {
                   ],
                 },
               ],
-          }
-          let dataStandard = {
+        }
+        let dataStandard = {
               title: {
                 text: '{a|' + versionsData.value.standard.proportion + '}{c|%}' + '\n' + '标准版占比',
                 x: 'center',
@@ -3229,7 +3243,7 @@ export default {
                       },
                     },
                     {
-                      value: 100 - 78,
+                      value: 100 - versionsData.value.standard.proportion,
                       name: '',
                       label: {
                         normal: {
@@ -3245,8 +3259,8 @@ export default {
                   ],
                 },
               ],
-            }
-          let dataMajor = {
+        }
+        let dataMajor = {
               title: {
                 text: '{a|' + versionsData.value.major.proportion + '}{c|%}' + '\n' + '专业版占比',
                 x: 'center',
@@ -3312,7 +3326,7 @@ export default {
                       },
                     },
                     {
-                      value: 100 - 78,
+                      value: 100 - versionsData.value.major.proportion,
                       name: '',
                       label: {
                         normal: {
@@ -3328,10 +3342,10 @@ export default {
                   ],
                 },
               ],
-            }
-          let dataCustom = {
+        }
+        let dataCustom = {
               title: {
-                text: '{a|' + versionsData.value.custom.proportion + '}{c|%}' + '\n' + '自訂版占比',
+                text: '{a|' + versionsData.value.custom.proportion + '}{c|%}' + '\n' + '评测版占比',
                 x: 'center',
                 y: 'center',
                 textStyle: {
@@ -3395,7 +3409,7 @@ export default {
                       },
                     },
                     {
-                      value: 100 - 78,
+                      value: 100 - versionsData.value.custom.proportion,
                       name: '',
                       label: {
                         normal: {
@@ -3411,11 +3425,11 @@ export default {
                   ],
                 },
               ],
-          }
-          totalArea.value.pie1 = dataBasics
-          totalArea.value.pie2 = dataStandard
-          totalArea.value.pie3 = dataMajor
-          totalArea.value.pie4 = dataCustom
+        }
+        totalArea.value.pie1 = dataBasics
+        totalArea.value.pie2 = dataStandard
+        totalArea.value.pie3 = dataMajor
+        totalArea.value.pie4 = dataCustom
         loading.value.versions = false
       }
       }).catch((error) => {

+ 156 - 0
TEAMModelBI/ClientApp/src/view/issueCoupons/consolidationCoupon.vue

@@ -0,0 +1,156 @@
+<template>
+    <div>
+        <el-form ref="ruleFormRef" :model="consolidationForm" :rules="rules" label-width="120px">
+            <el-form-item label="站別" prop="srvAdr">
+                <el-radio-group v-model="consolidationForm.srvAdr">
+                    <el-radio label="Global" size="large" border>國際站</el-radio>
+                    <el-radio label="China" size="large" border>大陸站</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item label="券號" prop="coupon">
+                <el-input style="width: 500px;" v-model="consolidationForm.coupon" placeholder="請輸入券號" />
+            </el-form-item>
+            <el-form-item label="醍摩豆ID" prop="targets">
+                <div style="display: flex;align-items: flex-end;">
+                    <el-input style="width: 300px;" v-model="consolidationForm.targets" :rows="6" type="textarea" placeholder="請填入教師ID, 並用換行分隔" />
+                    <div style="margin-left: 5px;">總共 {{ targetsCount }} 位</div>
+                </div>
+            </el-form-item>
+            <el-form-item>
+                <el-button type="primary" @click="submitForm(ruleFormRef)" :loading="loading">歸戶</el-button>
+                <el-button @click="resetForm(ruleFormRef)" :loading="loading">重置</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+<script setup>
+import { reactive, ref, computed, getCurrentInstance, markRaw } from 'vue'
+import { Warning, SuccessFilled } from '@element-plus/icons'
+import { ElMessageBox } from 'element-plus'
+let { proxy } = getCurrentInstance()
+const targetsCount = ref(0)
+const ruleFormRef = ref()
+const loading = ref(false)
+const consolidationForm = reactive({
+    srvAdr: '',
+    coupon: '',
+    targets: ""
+})
+
+const checkTargets = (rule, value, callback) => {
+    let isErr = false
+    function isArrayRep(array){
+        var result = new Set();
+        var repeat = new Set();
+        array.forEach(item => {
+            result.has(item) ? repeat.add(item) : result.add(item);
+        })
+        // console.log(result); // {1, 2, "a", 3, "b"}
+        // console.log(repeat); // {1, "a"}
+        // console.log(repeat.size)
+        if(repeat.size != 0){
+            return true
+        } else {
+            return false
+        }
+    }
+    if(value && !/^[0-9\n]+$/.test(value)){
+        isErr = true
+        callback(new Error("只能輸入醍摩豆ID與換行"))
+    } else if(value && isArrayRep(value.split('\n'))){
+        isErr = true
+        callback(new Error("醍摩豆ID有重複"))
+    } else if(value){
+        let errIds = []
+        let tmp = value.split('\n')
+        tmp.forEach(e=> {
+            if(e.length != 10) {
+                errIds.push(e)
+            } else {
+                let now = Math.floor(new Date().getTime() / 1000)
+                let orgId = parseInt(e)
+                if(parseInt(e.substring(0, 1)) >= 6){
+                    orgId -= 5000000000
+                }
+
+                if(orgId > now){
+                    errIds.push(e)
+                }
+            }
+        })
+
+        if(errIds.length > 0){
+            // console.log(errIds, 'errIds')
+            isErr = true
+            callback(new Error("請檢查醍摩豆ID是否符合格式或有空格"))
+        }
+    }
+
+    if(!isErr && value != ''){
+        let tArray = value.split('\n')
+        targetsCount.value = tArray.length
+    } else {
+        targetsCount.value = 0
+    }
+
+    callback()
+}
+
+const rules = reactive({
+    srvAdr: [{required: true, trigger: "blur", message: '請選擇一個站別' }],
+    coupon: [{required: true, trigger: "blur", message: '請選擇一個發券類型' }],
+    targets: [{required: true, validator: checkTargets, trigger: "blur"}],
+})
+
+const submitForm = formEl => {
+  if (!formEl) return
+  formEl.validate(async (valid, ddd) => {
+    if (valid) {
+
+        ElMessageBox.confirm(
+            '開始歸戶?',
+            '',
+            {
+                type: 'info',
+                confirmButtonText: '歸戶'
+            }
+        ).then(async ()=>{
+            loading.value = true
+            let consolidationData = {
+                srvAdr: consolidationForm.srvAdr,
+                ids: consolidationForm.targets.split('\n'),
+                coupon: consolidationForm.coupon
+            }
+            await proxy.$api.consolidationCoupon(consolidationData).then((res) => {
+                console.log(res, '歸戶成功')
+                ElMessageBox.alert('成功', '歸戶',
+                    {
+                        type: 'info',
+                        icon: markRaw(SuccessFilled),
+                    }
+                )
+                resetForm(formEl) // 欄位清除
+            }).catch(e=>{
+                ElMessageBox.alert('歸戶失敗', '歸戶',
+                    {
+                        type: 'warning',
+                        icon: markRaw(Warning),
+                    }
+                )
+            }).finally(() => {
+                loading.value = false
+            })
+        })
+    } else {
+        console.log("error submit!")
+        return false
+    }
+  })
+}
+
+const resetForm = formEl => {
+    if (!formEl) return
+    formEl.resetFields()
+}
+
+</script>

+ 986 - 0
TEAMModelBI/ClientApp/src/view/issueCoupons/crteadCoupon.vue

@@ -0,0 +1,986 @@
+<template>
+    <div style="position: relative;">
+        <!-- 隱藏按鈕 -->
+        <div style="width: 100px; height:100px;position: absolute;right: 0;z-index: 10;" @click="showClick()"></div>
+        <el-form ref="ruleFormRef" :model="crtCouponForm" :rules="rules" label-width="120px">
+            <el-form-item label="發券位置" prop="srvAdr">
+                <el-radio-group v-model="crtCouponForm.srvAdr">
+                    <el-radio label="Global" size="large" border>國際站</el-radio>
+                    <el-radio label="China" size="large" border>大陸站</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item v-if="!detailSettingFlag" label="活動票券" prop="eventType">
+                <el-radio-group v-model="eventType" @change="setEventType">
+                    <el-radio label="hiteach50-3"  border>Hiteach 50 第三階段</el-radio>
+                    <el-radio label="hiteach333-1"  border>HiTeach 333 第一階段</el-radio>
+                    <el-radio label="hiteach333-3"  border>HiTeach 333 第三階段</el-radio>
+                    <el-radio label="hiteachBookSPLicense"  border>HiTeach專書贈送授權</el-radio>
+                    <el-radio label="fbGroupOpening"  border>HiTeach社團開幕活動</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item v-if="detailSettingFlag" label="票券類型" prop="couponType" >
+                <el-select v-model="crtCouponForm.couponType" placeholder="請選擇" clearable style="width: 500px;">
+                    <el-option label="公開型" value="Public" />
+                    <el-option label="事件型" value="Event" />
+                    <el-option label="大量生成" value="General" />
+                </el-select>
+            </el-form-item>
+            <el-form-item v-if="detailSettingFlag && crtCouponForm.couponType != 'General'" label="票券名稱" prop="couponName" >
+                <el-input v-model="crtCouponForm.couponName" placeholder="範例: TEAM10T2G(不填會自動生成)" style="width: 500px;"/>
+            </el-form-item>
+            <el-form-item v-if="detailSettingFlag" label="活動名稱" prop="eventName">
+                <el-input v-model="crtCouponForm.eventName" placeholder="範例: hiteach333-1" style="width: 500px;"/>
+            </el-form-item>
+            <el-form-item label="到期時間" prop="expire">
+                <el-date-picker 
+                v-model="crtCouponForm.expire" 
+                type="datetime" 
+                style="width: 500px;" 
+                :disabled-date="disabledDate" 
+                :shortcuts="shortcuts"/>
+            </el-form-item>
+            <el-form-item v-if="crtCouponForm.couponType == 'Public'" label="兌換上限" prop="maxTaker">
+                <el-input-number v-model="crtCouponForm.maxTaker" :min="0"  :disabled="!maxTakerFlag" style="margin-right: 6px;"/>
+                <el-checkbox v-model="maxTakerFlag" label="啟用" size="large" />
+            </el-form-item>
+            <el-form-item v-if="crtCouponForm.couponType == 'General'" label="生成券數" prop="quantity">
+                <el-input-number v-model="crtCouponForm.quantity" :min="0"  />
+            </el-form-item>
+            <el-form-item v-if="detailSettingFlag" label="規則" prop="rule">
+                <div style="max-height: 330px;overflow: scroll;">
+                    <div v-for="(rule, rIndex) in crtCouponForm.rule" class="ruleBox">
+                        <el-button :icon="Plus" circle @click="addRule(rIndex)" style="margin-right: 5px;"/>
+                        <div class="rule">
+                            條件:
+                            <div class="ruleStr">{{ translateRule(rule.q) }}</div>
+                            <div v-for="(item, index) in rule.q" style="text-align:left;">
+                                <el-button-group style="margin-right: 5px;">
+                                    <el-button :icon="Plus" @click="addCondition(rIndex, index)" />
+                                    <el-button :icon="CloseBold" @click="delCondition(rIndex, index)" :disabled="index == 0" />
+                                </el-button-group>
+                                <el-select v-model="item.operator" :disabled="index == 0" clearable :placeholder="index == 0 ? ' ' : '請選擇'" style="width: 100px;">
+                                    <el-option v-for="(o, i) in operatorList" :label="o.label" :value="o.val" :key="i" />
+                                </el-select>
+                                <el-select v-model="item.type" placeholder="檢核屬性" clearable style="width: 250px;">
+                                    <el-option  v-for="(t, i) in typeList" :label="t.label" :value="t.val" :key="i"/>
+                                </el-select>
+                                <el-select v-model="item.how" placeholder="判斷方式" style="width: 120px;" clearable :change="(item.how == 'is null' || item.how == 'isnot null') ? item.val = '' : item.val = item.val">
+                                    <el-option  v-for="(h, i) in howList" :label="h.label" :value="h.val" :key="i"/>
+                                </el-select>
+                                <el-input  v-model="item.val" placeholder="數值" style="width: 100px;" :disabled="(item.how == 'is null' || item.how == 'isnot null')"/>
+                            </div>
+                            獲得增益:
+                            <div style="text-align:left;">
+                                <el-select v-model="rule.b" placeholder="請選擇" clearable style="width: 500px;">
+                                    <el-option  v-for="(b, i) in ruleBList" :label="b.label" :value="b.val" :key="i"/>
+                                </el-select>
+                            </div>
+                            獲得積分: 
+                            <div style="text-align:left;">
+                                <el-input-number v-model="rule.p" :min="0"  />
+                            </div>
+                        </div>
+                        <el-button v-if="rIndex != 0" :icon="CloseBold" circle @click="delRule(rIndex)" style="margin-right: 5px;"/>
+                    </div>
+
+                </div>
+            </el-form-item>
+            <el-form-item label="票券資訊" prop="info">
+                <div style="display: flex;">
+                    <el-card v-for="info in crtCouponForm.info" style="width: 400px;margin-right:7px;">
+                        <template #header>
+                            <div style="text-align: left;font-weight: bold;font-size: 17px;">
+                                {{langToName(info.l)}}
+                            </div>
+                        </template>
+                        <div style="text-align: left;">
+                            票券標題:<el-input v-model="info.n" :readonly="!detailSettingFlag"/>
+                            連結:<el-input v-model="info.u" :readonly="!detailSettingFlag"/>
+                        </div>
+                        <template #footer>
+                            <div style="display: flex;justify-content: center;">
+                                <div class="coupons">
+                                    <div class="coupons-cont">
+                                        <div class="hole"/>
+                                        <div class="coupons-cont-box">
+                                            <div class="coupons-cont-box-title">{{ info.n }}</div>
+                                            <div class="coupons-cont-box-exp" >
+                                                {{ '有效期限: ' + convertDate(crtCouponForm.expire) }}
+                                            </div>
+                                            <div class="coupons-cont-box-link">
+                                                <el-button round size="small" @click="linkToPage(info.u)">了解更多</el-button>
+                                            </div>
+                                        </div>
+                                    </div>
+                                    <div class="coupons-btn">
+                                        <div class="coupons-btn-hole-positon">
+                                            <div class="hole"/> 
+                                        </div>
+                                        <div class="icon-box">
+                                            <el-icon :size="23" style="transform:rotate(-50deg);">
+                                            <Ticket />
+                                            </el-icon>
+                                        </div>
+                                        {{ '兌換' }}
+                                    </div>
+                                </div>
+                            </div>
+                        </template>
+                    </el-card>
+                </div>
+            </el-form-item>
+            <el-form-item v-if="crtCouponForm.couponType == 'Event'" label="指定醍摩豆ID" prop="targets">
+                <div style="display: flex;align-items: flex-end;">
+                    <el-input style="width: 300px;" v-model="crtCouponForm.targets" :rows="6" type="textarea" placeholder="請填入教師ID, 並用換行分隔" />
+                    <div style="margin-left: 5px;">總共 {{ targetsCount }} 位</div>
+                </div>
+            </el-form-item>
+            <el-form-item v-if="crtCouponForm.couponType == 'Event'">
+                <el-checkbox v-model="consolidationFlag" label="直接歸戶給以上老師" size="large" />
+            </el-form-item>
+            <el-form-item>
+                <el-button type="primary" @click="submitForm(ruleFormRef)" :loading="loading">建立優惠券</el-button>
+                <el-button @click="resetForm(ruleFormRef)" :loading="loading">重置</el-button>
+            </el-form-item>
+            <el-form-item label="優惠券"  style="margin-top: 50px;max-width: 600px;">
+                <el-input :rows="6" type="textarea" v-model="couponResult" :readonly="true" style="margin-bottom: 5px;"/>
+                <el-button type="primary" :icon="CopyDocument" @click="copyDocument(couponResult)">複製優惠券</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+
+<script setup>
+import { reactive, ref, computed, getCurrentInstance, markRaw } from 'vue'
+import { Ticket, Plus, CloseBold, Warning, CopyDocument, SuccessFilled } from '@element-plus/icons'
+import { ElMessageBox } from 'element-plus'
+let { proxy } = getCurrentInstance()
+
+const clickCount = ref(0)
+const detailSettingFlag = ref(false)
+
+const showClick = ()=>{
+    clickCount.value++
+    if(clickCount.value == 10){
+        detailSettingFlag.value = !detailSettingFlag.value
+        clickCount.value = 0
+    }
+}
+
+const targetsCount = ref(0)
+
+const maxTakerFlag = ref(false)
+const consolidationFlag = ref(false)
+const loading = ref(false)
+const couponResult = ref('')
+const shortcuts = [
+    {
+        text: '一個月後',
+        value: () => {
+            const date = new Date()
+            date.setTime(date.getTime() + 30 * 3600 * 1000 * 24)
+            return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59)
+        },
+    },
+    {
+        text: '二個月後',
+        value: () => {
+            const date = new Date()
+            date.setTime(date.getTime() + 60 * 3600 * 1000 * 24)
+            return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59)
+        },
+    },
+    {
+        text: '三個月後',
+        value: () => {
+            const date = new Date()
+            date.setTime(date.getTime() + 90 * 3600 * 1000 * 24)
+            return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59)
+        },
+    },
+]
+const eventType= ref('')
+
+const setEventType = (type)=>{
+    switch(type){
+        case 'hiteach50-3':
+            crtCouponForm.couponType =  'Event'
+            crtCouponForm.eventName = 'hiteach50-3'
+            crtCouponForm.rule[0].q = [
+                {
+                    operator: '',
+                    type: 'GetWebIRS50EventType',
+                    how: '==',
+                    val: 'hiteach50'
+                },
+                {
+                    operator: '&&',
+                    type: 'GetWebIRS50TimeStep2',
+                    how: '!=',
+                    val:'-1'
+                },
+                {
+                    operator: '&&',
+                    type: 'GetWebIRS50TimeStep2',
+                    how: 'isnot null',
+                    val:''
+                }
+            ]
+            crtCouponForm.rule[0].b = '901003'
+            crtCouponForm.info[0].l = 'zh-tw' 
+            crtCouponForm.info[0].n = '教師自主增能三'
+            crtCouponForm.info[0].u = 'https://www.habook.com/zh-tw/event.php?act=view&id=170'
+            crtCouponForm.info[1].l = 'zh-cn'
+            crtCouponForm.info[1].n = '教师自主增能阶段三'
+            crtCouponForm.info[1].u = 'https://www.habook.com.cn/event.php?act=view&id=50'
+            crtCouponForm.info[2].l = 'en-us'
+            crtCouponForm.info[2].n = 'Self-enhancement Plan Stage 3'
+            crtCouponForm.info[2].u = 'https://www.habook.com/en/event.php?act=view&id=170'
+        break
+        case 'hiteach333-1':
+            crtCouponForm.couponType =  'Event'
+            crtCouponForm.eventName = 'hiteach333-1'
+            crtCouponForm.rule[0].q = [
+                {
+                    operator: '',
+                    type: 'GetWebIRS50TimeStep1',
+                    how: 'is null',
+                    val:''
+                }
+            ]
+            crtCouponForm.rule[0].b = '901003'
+            crtCouponForm.info[0].l = 'zh-tw' 
+            crtCouponForm.info[0].n = 'HiTeach 333 階段一'
+            crtCouponForm.info[0].u = 'https://www.habook.com/zh-tw/event.php?act=view&id=162'
+            crtCouponForm.info[1].l = 'zh-cn'
+            crtCouponForm.info[1].n = 'HiTeach 333 阶段一'
+            crtCouponForm.info[1].u = 'https://www.habook.com.cn/event.php?act=view&id=47'
+            crtCouponForm.info[2].l = 'en-us'
+            crtCouponForm.info[2].n = 'HiTeach 333 Stage 1'
+            crtCouponForm.info[2].u = 'https://www.habook.com/en/event.php?act=view&id=162'
+        break
+        case 'hiteach333-3':
+            crtCouponForm.couponType =  'Event'
+            crtCouponForm.eventName = 'hiteach333-3'
+            crtCouponForm.rule[0].q = [
+                {
+                    operator: '',
+                    type: 'GetWebIRS50EventType',
+                    how: '==',
+                    val: 'hiteach333'
+                },
+                {
+                    operator: '&&',
+                    type: 'GetWebIRS50TimeStep2',
+                    how: '!=',
+                    val:'-1'
+                },
+                {
+                    operator: '&&',
+                    type: 'GetWebIRS50TimeStep2',
+                    how: 'isnot null',
+                    val:''
+                }
+            ]
+            crtCouponForm.rule[0].b = '901003'
+            crtCouponForm.info[0].l = 'zh-tw' 
+            crtCouponForm.info[0].n = 'HiTeach 333 階段三'
+            crtCouponForm.info[0].u = 'https://www.habook.com/zh-tw/event.php?act=view&id=162'
+            crtCouponForm.info[1].l = 'zh-cn'
+            crtCouponForm.info[1].n = 'HiTeach 333 阶段三'
+            crtCouponForm.info[1].u = 'https://www.habook.com.cn/event.php?act=view&id=47'
+            crtCouponForm.info[2].l = 'en-us'
+            crtCouponForm.info[2].n = 'HiTeach 333 Stage 3'
+            crtCouponForm.info[2].u = 'https://www.habook.com/en/event.php?act=view&id=162'
+        break
+        case 'hiteachBookSPLicense':
+            crtCouponForm.couponType =  'Event'
+            crtCouponForm.eventName = 'hiteachBookSPLicense'
+            crtCouponForm.rule[0].b = '901003'
+            crtCouponForm.info[0].l = 'zh-tw' 
+            crtCouponForm.info[0].n = 'HiTeach專書贈送授權'
+            crtCouponForm.info[0].u = 'https://www.habook.com/zh-tw'
+            crtCouponForm.info[1].l = 'zh-cn'
+            crtCouponForm.info[1].n = 'HiTeach专书赠送授权'
+            crtCouponForm.info[1].u = 'https://www.habook.com.cn/'
+            crtCouponForm.info[2].l = 'en-us'
+            crtCouponForm.info[2].n = 'HiTeach Book Special License'
+            crtCouponForm.info[2].u = 'https://www.habook.com/en/'
+        break
+        case 'fbGroupOpening':
+            crtCouponForm.couponType =  'Event'
+            crtCouponForm.eventName = 'fbGroupOpening'
+            crtCouponForm.rule[0].b = '901008'
+            crtCouponForm.info[0].l = 'zh-tw' 
+            crtCouponForm.info[0].n = 'HiTeach社團開幕活動'
+            crtCouponForm.info[0].u = 'https://www.habook.com/zh-tw'
+            crtCouponForm.info[1].l = 'zh-cn'
+            crtCouponForm.info[1].n = 'HiTeach社团开幕活动'
+            crtCouponForm.info[1].u = 'https://www.habook.com.cn/'
+            crtCouponForm.info[2].l = 'en-us'
+            crtCouponForm.info[2].n = 'Facebook Group Opening'
+            crtCouponForm.info[2].u = 'https://www.habook.com/en/'
+        break
+    }
+}
+
+const operatorList = [
+    { label: "或", val: "||" },
+    { label: "而且", val: "&&"}
+]
+const typeList = [
+    { label: "年資", val: "TenureID"},
+    { label: "T綠燈(Total)", val: "TGreen"},
+    { label: "T數據(Total)", val: "TData"},
+    { label: "T綠燈(月)", val: "TGreenMonth"},
+    { label: "T數據(月)", val: "TDataMonth"},
+    { label: "綁定手機號", val: "Mobile"},
+    { label: "綁定Mail", val: "Mail"},
+    { label: "取得WebIRS50的時間", val: "TimeForWebIRS50Get"},
+    { label: "取得智慧評分模組的時間", val: "TimeForSmartRatingGet"},
+    { label: "取得AI文字分析的時間", val: "TimeForAitextGet"},
+    { label: "取得蘇格拉底小數據的時間", val: "TimeForSokliteGet"},
+    { label: "333和50 第一階段取得的時間", val: "GetWebIRS50TimeStep1"},
+    { label: "333和50 第二階段取得的時間", val: "GetWebIRS50TimeStep2"},
+    { label: "333和50 第三階段取得的時間", val: "GetWebIRS50TimeStep3"},
+    { label: "取得參加333還是50", val: "GetWebIRS50EventType"},
+    { label: "是否完善進階資訊", val: "FillBaseEx" }
+]
+
+const howList = [
+    { label: "大於", val: ">"},
+    { label: "小於", val: "<"},
+    { label: "等於", val: "=="},
+    { label: "不等於", val: "!="},
+    { label: "大於等於", val: ">="},
+    { label: "小於等於", val: "<="},
+    { label: "是", val: "is"},
+    { label: "不是", val: "isnot"},
+    { label: "是空的", val: "is null"},
+    { label: "不是空的", val: "isnot null"}
+]
+
+const ruleBList = [
+    { label: "AI文字分析模組(展延)", val: "901001"},
+    { label: "AI蘇格拉底小數據(展延)", val: "901002"},
+    { label: "Web IRS 50人 (展延3個月)", val: "901003"},
+    { label: "Web IRS 50人 (延長1個月)", val: "901004"},
+    { label: "智慧評分 (一年)", val: "901005"},
+    { label: "HiTeachCC-6任務數(展延)", val: "903001"},
+    { label: "HiTeachCC-10任務數(展延)", val: "903002"},
+    { label: "HiTeachCC-100連線數(展延)", val: "903003"},
+    { label: "HiTeachCC-200連線數(展延)", val: "903004"},
+    { label: "小組協作(一年)", val: "901006"},
+    { label: "AI GPT(一年)", val: "901007"},
+    { label: "智慧評分 (三個月)", val: "901008"}
+]
+
+const crtCouponForm = reactive({
+    srvAdr: '',
+    couponType: "",
+    couponName: "",
+    expire: "",
+    eventName: "",
+    maxTaker: -1,
+    quantity: 0,
+    rule:[
+        {
+            // 條件
+            "q": [
+                {
+                    operator: '',
+                    type: '',
+                    how: '',
+                    val:''
+                },
+            ],
+            "b": "", // 給的權益
+            "p": "0", // 給的積分
+        }
+    ],
+    info: [
+        {
+            "l": "zh-tw",
+            "n": "",
+            "u": ""
+        },
+        {
+            "l": "zh-cn",
+            "n": "",
+            "u": ""
+        },
+        {
+            "l": "en-us",
+            "n": "",
+            "u": ""
+        }
+    ],
+    targets: ""
+})
+
+// 翻譯條件字串
+const translateRule = (q)=>{
+    let str = ''
+    q.forEach(e => {
+        
+        let o = operatorList.find(i=> i.val == e.operator)
+        if(o) str += o.label +' '
+
+        let t = typeList.find(i=> i.val == e.type)
+        if(t) str += t.label +' '
+
+        let h = howList.find(i=> i.val == e.how)
+        if(h) str += h.label +' '
+
+        if(e.how != 'is null' && e.how != 'isnot null') str += e.val +' '
+    });
+    return str
+}
+
+// 增加規則
+const addRule = (rIndex) => {
+    crtCouponForm.rule.splice(rIndex+1, 0,  {
+        "q": [
+            {
+                operator: '',
+                type: '',
+                how: '',
+                val:''
+            }
+        ],
+        "b": "",
+        "p": "0"
+    })
+}
+
+// 刪除規則
+const delRule = (rIndex) => {
+    crtCouponForm.rule.splice(rIndex, 1)
+}
+
+// 增加條件
+const addCondition = (rIndex, index) => {
+    crtCouponForm.rule[rIndex].q.splice(index+1, 0, {
+        operator: '',
+        type: '',
+        how: '',
+        val:''
+    })
+}
+
+// 刪除條件
+const delCondition = (rIndex, index) => {
+    crtCouponForm.rule[rIndex].q.splice(index, 1)
+}
+
+// 語系轉字串
+const langToName = (lang) => {
+    switch(lang){
+        case 'zh-tw':
+            return '繁體中文'
+        case 'zh-cn':
+            return '簡體中文'
+        case 'en-us':
+            return '英文'
+    }
+}
+
+// 跳轉url測試
+const linkToPage = (url) => {
+    try {        
+        if(url != ''){
+            var temp = new URL(url);
+            window.open(url, '_blank')
+        } else {
+            ElMessageBox.alert('請確認網址格式', '了解更多',
+                {
+                    type: 'warning',
+                    icon: markRaw(Warning),
+                }
+            )
+        }
+    } catch (err) {
+        ElMessageBox.alert('請確認網址格式', '了解更多',
+            {
+                type: 'warning',
+                icon: markRaw(Warning),
+            }
+        )
+    }
+}
+
+// 日曆元件限制設定
+const disabledDate = time => {
+    if(!detailSettingFlag.value) {
+        if(time.getTime() > (Date.now() + 7776000000)){ // 不能超過3個月
+            return true
+        } else if(time.getTime() < Date.now()- 3600 * 1000 * 24){
+            return true
+        }
+    } else {
+        true
+    }
+}
+
+// 時間轉型
+const convertDate = computed(()=>{
+    return function(val){
+        let date = new Date(val).getTime()
+        if(date.toString().substring(0,1) !== '9'){
+            if(date.toString().length < 13) date = date * 1000
+            return date ? new Date(parseInt(date)).toLocaleDateString() : ''
+        } else {
+            return null
+        }
+    }
+})
+
+const ruleFormRef = ref()
+
+const checkRule = (rule, value, callback) => {
+    let isCheck = false
+    value.forEach(e=>{
+        if(e.b == ""){
+            isCheck = true
+        }
+
+        e.q.forEach((q) => {
+            if(q.operator != ""){
+                isCheck = true
+            }
+            if(q.type != ""){
+                isCheck = true
+            }
+            if(q.how != ""){
+                isCheck = true
+            }
+            if(q.val != ""){
+                isCheck = true
+            }
+        })
+    })
+
+    if(isCheck){
+        let errC = 0
+        value.forEach(e=>{
+            if(e.b == ""){
+                errC++
+            }
+
+            e.q.forEach((q, i) => {
+                if(i != 0 && q.operator == ""){
+                    errC++
+                }
+                if(q.type == ""){
+                    errC++
+                }
+                if(q.how == ""){
+                    errC++
+                }
+                if(q.how != 'is null' && q.how != 'isnot null' && q.val == ""){
+                    errC++
+                }
+            })
+        })
+        if(errC > 0){
+            callback(new Error("請完成票券規則設定, 至少需要給予權益"))
+        }
+    }
+    callback()
+}
+
+const checkQuantity = (rule, value, callback) => {
+    if(!value && value < 1) {
+        callback(new Error("生成券數最少為1"))
+    }
+    callback()
+}
+
+const checkMaxTaker = (rule, value, callback) => {
+    if(maxTakerFlag.value){
+        if(value < 1){
+            callback(new Error("兌換上限不能小於1"))
+        }
+    }
+    callback()
+}
+
+const checkTargets = (rule, value, callback) => {
+    let isErr = false
+    if(value && !/^[0-9\n]+$/.test(value)){
+        isErr = true
+        callback(new Error("只能輸入醍摩豆ID與換行"))
+    } else if(consolidationFlag.value && !value) {
+        isErr = true
+        callback(new Error("請填入要歸戶的醍摩豆ID"))
+    } else if(value && isArrayRep(value.split('\n'))){
+        isErr = true
+        callback(new Error("醍摩豆ID有重複"))
+    } else if(value){
+        let errIds = []
+        let tmp = value.split('\n')
+        tmp.forEach(e=> {
+            if(e.length != 10) {
+                errIds.push(e)
+            } else {
+                let now = Math.floor(new Date().getTime() / 1000)
+                let orgId = parseInt(e)
+                if(parseInt(e.substring(0, 1)) >= 6){
+                    orgId -= 5000000000
+                }
+
+                if(orgId > now){
+                    errIds.push(e)
+                }
+            }
+        })
+
+        if(errIds.length > 0){
+            // console.log(errIds, 'errIds')
+            isErr = true
+            callback(new Error("請檢查醍摩豆ID是否符合格式或有空格"))
+        }
+    }
+
+    if(!isErr && value != ''){
+        let tArray = value.split('\n')
+        targetsCount.value = tArray.length
+    } else {
+        targetsCount.value = 0
+    }
+
+    callback()
+}
+
+function isArrayRep(array){
+    var result = new Set();
+    var repeat = new Set();
+    array.forEach(item => {
+        result.has(item) ? repeat.add(item) : result.add(item);
+    })
+    // console.log(result); // {1, 2, "a", 3, "b"}
+    // console.log(repeat); // {1, "a"}
+    // console.log(repeat.size)
+    if(repeat.size != 0){
+        return true
+    } else {
+        return false
+    }
+}
+
+const checkCupoInfo = (rule, value, callback) => {
+    let errC = 0
+    value.forEach(e => {
+        if(!e.n) errC ++
+        if(!e.u) errC ++
+    });
+    if(errC > 0){
+        callback(new Error("請完成票券資訊設定"))
+    } else {
+        callback()
+    }
+}
+
+const checkEventType = (rule, value, callback) => {    
+    if(eventType.value == '') callback(new Error("請選擇一個優惠券活動"))
+    callback()
+}
+
+const checkExpire = (rule, value, callback) => {
+    if(!value){
+        callback(new Error("請輸入到期時間"))
+    } else {
+        let timestemp = new Date(value).getTime()
+        console.log(timestemp)
+        console.log(Date.now())
+        console.log(timestemp - Date.now())
+        if(Math.floor((timestemp - Date.now())/1000) < 60 *60){
+            callback(new Error("限制時間至少要大於一小時"))
+        }
+    }
+    callback()
+}
+
+const rules = reactive({
+    couponType: [{required: true, trigger: "blur", message: '請選擇一個發券類型' }],
+    eventName: [{required: true, trigger: "blur", message: '請輸入活動名稱'}],
+    expire: [{required: true, validator: checkExpire, trigger: "blur"}],
+    maxTaker: [{validator: checkMaxTaker, trigger: "blur"}],
+    quantity: [{required: true,validator: checkQuantity, trigger: "blur"}],
+    rule: [{required: true, validator: checkRule, trigger: "blur"}],
+    info: [{required: true, validator: checkCupoInfo, trigger: "blur"}],
+    targets: [{required: true, validator: checkTargets, trigger: "blur"}],
+    srvAdr: [{required: true, trigger: "blur", message: '請選擇一個站別' }],
+    eventType: [{required: true, trigger: "blur", validator: checkEventType}],
+})
+
+const submitForm = formEl => {
+  if (!formEl) return
+  formEl.validate(async (valid, ddd) => {
+    if (valid) {
+        console.log("submit!")
+
+        ElMessageBox.confirm(
+            '確認建立此優惠券嗎?',
+            '',
+            {
+                type: 'info',
+                confirmButtonText: '我確定'
+            }
+        ).then(async ()=>{
+            loading.value = true
+        
+            let success = false
+            let data = JSON.parse(JSON.stringify(crtCouponForm))
+            data.expire = Math.floor( new Date(crtCouponForm.expire).getTime() / 1000)
+            crtCouponForm.rule.forEach((e, i)=>{
+                let qStr = ""
+                e.q.forEach(qe => {
+                    let values = Object.values(qe)
+                    values.forEach(v => {
+                        if(v != '') qStr += v + ' '
+                    })
+                })
+                data.rule[i].q = qStr
+            })
+            data.maxTaker = crtCouponForm.maxTaker == 0 ? -1 : crtCouponForm.maxTaker
+            data.targets = []
+            if(crtCouponForm.targets != ''){
+                data.targets = crtCouponForm.targets.split('\n')
+            }
+            
+            await proxy.$api.crtCoupon(data).then((res) => {
+                couponResult.value = '' // 先清空
+                if(res.coupons){
+                    res.coupons.forEach(e=>{
+                        couponResult.value += (e+'\n')
+                    })
+                } else if(res.coupon){
+                    couponResult.value = res.coupon
+                }
+                success = true
+            }).catch(e=>{
+                ElMessageBox.alert('請確認優惠券設定是否合乎格式', '建立優惠券',
+                    {
+                        type: 'warning',
+                        icon: markRaw(Warning),
+                    }
+                )
+            }).finally(() => {
+                loading.value = false
+            })
+
+            if(consolidationFlag.value == true && success) {
+                loading.value = true
+                let consolidationData = {
+                    srvAdr: crtCouponForm.srvAdr,
+                    ids: crtCouponForm.targets.split('\n'),
+                    coupon: couponResult.value
+                }
+                await proxy.$api.consolidationCoupon(consolidationData).then((res) => {
+                    consolidationFlag.value = false
+                    console.log(res, '歸戶成功')
+                }).catch(e=>{
+                    ElMessageBox.alert('歸戶失敗', '歸戶',
+                        {
+                            type: 'warning',
+                            icon: markRaw(Warning),
+                        }
+                    )
+                }).finally(() => {
+                    loading.value = false
+                })
+            }
+
+            if(success){
+                ElMessageBox.alert('成功', '建立優惠券',
+                    {
+                        type: 'info',
+                        icon: markRaw(SuccessFilled),
+                    }
+                )
+                resetForm(formEl) // 欄位清除
+            }
+        })
+    } else {
+        console.log("error submit!")
+        return false
+    }
+  })
+}
+
+const resetForm = formEl => {
+    if (!formEl) return
+    formEl.resetFields()
+    crtCouponForm.info = [
+        {
+            "l": "zh-tw",
+            "n": "",
+            "u": ""
+        },
+        {
+            "l": "zh-cn",
+            "n": "",
+            "u": ""
+        },
+        {
+            "l": "en-us",
+            "n": "",
+            "u": ""
+        }
+    ]
+
+    crtCouponForm.rule = [
+        {
+            "q": [
+                {
+                    operator: '',
+                    type: '',
+                    how: '',
+                    val:''
+                }
+            ],
+            "b": "",
+            "p": "0"
+        }
+    ]
+
+    crtCouponForm.targets = ''
+    eventType.value = ''
+    consolidationFlag.value= false
+    crtCouponForm.couponType = ''
+}
+
+const copyDocument = (data) => {
+    navigator.clipboard.writeText(data)
+    .then(() => {
+        ElMessageBox.alert('複製成功', '複製優惠券',
+        {
+            type: 'info',
+            icon: markRaw(CopyDocument),
+        }
+    )
+    });
+}
+
+</script>
+
+<style scoped>
+.ruleBox{
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    margin-bottom: 5px;
+}
+
+.ruleBox .rule{
+    text-align: left;
+    border: 1px solid #dcdfe6;
+    padding: 6px 11px;
+    border-radius: 5px;
+    margin-right: 5px;
+}
+
+.ruleBox .rule .ruleStr{
+    min-height: 36px;
+    max-width: 550px;
+    border: 1px solid #e4e7ed;
+    padding: 1px 11px;
+    border-radius: 5px;
+    background-color: #f5f7fa;
+}
+.coupons {
+    box-shadow: 0px 3px 2px 2px #E0E0E0;
+    border-radius: 10px;
+    background-color: #ffffff;
+    display: flex;
+    width: 100%;
+    margin-bottom: 10px;
+    align-items: stretch;
+    font-family: "Noto Sans CJK TC", "serif";
+    max-width: 330px;
+    min-height: 100px;
+}
+.coupons-cont {
+    flex: 2;
+    padding: 8px 16px;
+    position: relative;
+    display: flex;
+    align-items: center;
+}
+.coupons-cont .hole {
+    position: absolute;
+    width: 20px;
+    height: 20px;
+    border-radius: 50%;
+    background-color: #ffffff;
+    left: -9px;
+    box-shadow: #e0e0e0 3px 0px 2px 0px;
+}
+.coupons-cont-box {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+}
+.coupons-cont-box-title {
+    font-size: 16px;
+    font-weight: bold;
+    white-space: pre-line;
+    text-align: left;
+    line-height: 1.3;
+}
+.coupons-cont-box-link {
+    text-align: left;
+	font-size: 13px;
+}
+.coupons-cont-box-exp {
+    display: flex;
+    font-size: 12px;
+}
+.coupons-cont-box-exp.isExpiringSoon {
+    color: #f57c00;
+    font-weight: bold;
+}
+.coupons-btn {
+    position: relative;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 15px;
+    border-left: 1px dashed #9e9e9e;
+    background-color: #03a9f4;
+    color: #f3f3f3;
+    border-top-right-radius: 10px;
+    border-bottom-right-radius: 10px;
+    flex-direction: column;
+    flex: 1;
+}
+.coupons-btn.exchange {
+    background-color: #9e9e9e;
+}
+.coupons-btn-hole-positon {
+    position: absolute;
+    height: 100%;
+    width: 100%;
+    display: flex;
+    justify-content: flex-end;
+    align-items: center;
+}
+.coupons-btn-hole-positon .hole {
+    width: 20px;
+    height: 20px;
+    border-radius: 50%;
+    position: absolute;
+    background-color: #ffffff;
+    right: -9px;
+}
+.coupons-btn .icon-box {
+    border: 1px solid #fff;
+    display: flex;
+    border-radius: 50%;
+    padding: 4px;
+}
+ 
+</style>

+ 22 - 0
TEAMModelBI/ClientApp/src/view/issueCoupons/index.vue

@@ -0,0 +1,22 @@
+<template>
+  <el-tabs type="border-card">
+      <el-tab-pane label="建立優惠券"><CrteadCoupon /></el-tab-pane>
+    <el-tab-pane label="優惠券歸戶"><ConsolidationCoupon /></el-tab-pane>
+    <el-tab-pane label="通知"><Notice /></el-tab-pane>
+  </el-tabs>
+</template>
+<script>
+import CrteadCoupon from './crteadCoupon.vue'
+import ConsolidationCoupon from './consolidationCoupon.vue'
+import Notice from './notice.vue'
+export default {
+  components: {
+    CrteadCoupon,
+    ConsolidationCoupon,
+    Notice
+  },
+  setup () {
+
+  }
+}
+</script>

+ 181 - 0
TEAMModelBI/ClientApp/src/view/issueCoupons/notice.vue

@@ -0,0 +1,181 @@
+<template>
+    <div>
+        <el-form ref="ruleFormRef" :model="noticeForm" :rules="rules" label-width="120px">
+            <el-form-item label="站別" prop="srvAdr">
+                <el-radio-group v-model="noticeForm.srvAdr">
+                    <el-radio label="Global" size="large" border>國際站</el-radio>
+                    <el-radio label="China" size="large" border>大陸站</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item label="標題" prop="title">
+                <el-input style="width: 500px;" v-model="noticeForm.title" placeholder="請輸入標題" />
+            </el-form-item>
+            <el-form-item label="內容" prop="body">
+                <el-input style="width: 500px;" :rows="6" type="textarea" v-model="noticeForm.body" placeholder="請輸入通知內容" />
+            </el-form-item>
+            <el-form-item label="醍摩豆ID" prop="targets">
+                <div style="display: flex;align-items: flex-end;">
+                    <el-input style="width: 300px;" v-model="noticeForm.targets" :rows="6" type="textarea" placeholder="請填入教師ID, 並用換行分隔" />
+                    <div style="margin-left: 5px;">總共 {{ targetsCount }} 位</div>
+                </div>
+            </el-form-item>
+            <el-form-item label="發送者" prop="sender">
+                <el-radio-group v-model="noticeForm.sender">
+                    <el-radio label="HiTeach" size="large" border>HiTeach</el-radio>
+                    <el-radio label="IES" size="large" border>IES</el-radio>
+                    <el-radio label="Sokrates" size="large" border>Sokrates</el-radio>
+                    <!-- <el-radio label="HiTA" size="large" border>HiTA</el-radio> -->
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item>
+                <el-button type="primary" @click="submitForm(ruleFormRef)" :loading="loading">發送</el-button>
+                <el-button @click="resetForm(ruleFormRef)" :loading="loading">重置</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+<script setup>
+import { reactive, ref, computed, getCurrentInstance, markRaw } from 'vue'
+import { Warning, SuccessFilled } from '@element-plus/icons'
+import { ElMessageBox } from 'element-plus'
+let { proxy } = getCurrentInstance()
+const targetsCount = ref(0)
+const ruleFormRef = ref()
+const loading = ref(false)
+const noticeForm = reactive({
+    srvAdr: '',
+    title: '',
+    body: '',
+    targets: "",
+    sender: '',
+    hubName: 'hita5' // 暫時固定
+})
+
+const checkTargets = (rule, value, callback) => {
+    let isErr = false
+    function isArrayRep(array){
+        var result = new Set();
+        var repeat = new Set();
+        array.forEach(item => {
+            result.has(item) ? repeat.add(item) : result.add(item);
+        })
+        // console.log(result); // {1, 2, "a", 3, "b"}
+        // console.log(repeat); // {1, "a"}
+        // console.log(repeat.size)
+        if(repeat.size != 0){
+            return true
+        } else {
+            return false
+        }
+    }
+    if(value && !/^[0-9\n]+$/.test(value)){
+        isErr = true
+        callback(new Error("只能輸入醍摩豆ID與換行"))
+    } else if(value && isArrayRep(value.split('\n'))){
+        isErr = true
+        callback(new Error("醍摩豆ID有重複"))
+    } else if(value){
+        let errIds = []
+        let tmp = value.split('\n')
+        tmp.forEach(e=> {
+            if(e.length != 10) {
+                errIds.push(e)
+            } else {
+                let now = Math.floor(new Date().getTime() / 1000)
+                let orgId = parseInt(e)
+                if(parseInt(e.substring(0, 1)) >= 6){
+                    orgId -= 5000000000
+                }
+
+                if(orgId > now){
+                    errIds.push(e)
+                }
+            }
+        })
+
+        if(errIds.length > 0){
+            // console.log(errIds, 'errIds')
+            isErr = true
+            callback(new Error("請檢查醍摩豆ID是否符合格式或有空格"))
+        }
+    }
+
+    if(!isErr && value != ''){
+        let tArray = value.split('\n')
+        targetsCount.value = tArray.length
+    } else {
+        targetsCount.value = 0
+    }
+
+    callback()
+}
+
+const rules = reactive({
+    srvAdr: [{required: true, trigger: "blur", message: '請選擇一個站別' }],
+    title: [{required: true, trigger: "blur", message: '請填寫標題' }],
+    body: [{required: true, trigger: "blur", message: '請填寫通知內容' }],
+    targets: [{required: true, validator: checkTargets, trigger: "blur"}],
+    sender: [{required: true, trigger: "blur", message: '請選擇一個產品接收'}],
+})
+
+const submitForm = formEl => {
+  if (!formEl) return
+  formEl.validate(async (valid, ddd) => {
+    if (valid) {
+
+        ElMessageBox.confirm(
+            '發送此通知?',
+            '',
+            {
+                type: 'info',
+                confirmButtonText: '發送'
+            }
+        ).then(async ()=>{
+            let request = {
+                srvAdr: noticeForm.srvAdr,
+                title: noticeForm.title,
+                body: noticeForm.body,
+                tags: [],
+                sender: noticeForm.sender,
+                hubName: noticeForm.hubName,
+            }
+            
+            noticeForm.targets.split('\n').forEach(e =>{
+                request.tags.push(e + '_' +request.sender)
+            })
+            console.log(request)
+
+            loading.value = true
+            await proxy.$api.pushNotify(request).then((res) => {
+                console.log(res, '發送成功')
+                ElMessageBox.alert('成功', '發送通知',
+                    {
+                        type: 'info',
+                        icon: markRaw(SuccessFilled),
+                    }
+                )
+                resetForm(formEl) // 欄位清除
+            }).catch(e=>{
+                ElMessageBox.alert('失敗', '發送通知',
+                    {
+                        type: 'warning',
+                        icon: markRaw(Warning),
+                    }
+                )
+            }).finally(() => {
+                loading.value = false
+            })
+        })
+    } else {
+        console.log("error submit!")
+        return false
+    }
+  })
+}
+
+const resetForm = formEl => {
+    if (!formEl) return
+    formEl.resetFields()
+}
+
+</script>

+ 225 - 15
TEAMModelBI/ClientApp/src/view/product/index.vue

@@ -1,6 +1,6 @@
 <template>
   <!--外层所有数据-->
-  <div class="productbox" v-if="showState==='default'">
+  <div class="productbox" v-loading="initLoading" v-if="showState==='default'"  element-loading-text="正在准备数据中...">
     <div class="header-select">
       <el-collapse v-model="activeNames" accordion>
         <el-collapse-item title="数据筛选" name="1">
@@ -95,7 +95,7 @@
                   <span class="filtratebox-phase-title subclass">精准选择:</span>
                   <div class="filtratebox-phase-content precise">
                     <div v-if="clickNum.district ===1" class="schoolclass">
-                      <el-cascader v-model="optionsValue" :options="options" :props="areaProps" clearable />
+                      <el-cascader v-model="optionsValue" :options="options" :props="areaProps" clearable   placeholder="请选择要统计的城市或区"/>
                     </div>
                     <div v-else-if="clickNum.district ===0" class="aresclass">
                       <el-select v-model="optionsValue" placeholder="请选择要统计的省份" clearable>
@@ -264,16 +264,81 @@
       </template>
     </el-dialog>
   </div>
+  <div class="dialog-teachlist" v-if="teachtableShow">
+      <el-dialog v-model="teachtableShow" title="教师详细列表" width="55%">
+      <div class="header-title">
+        <div class="header-title-schoolname">{{touchNowteach.name}}</div>
+        <div class="header-title-content">
+          <div class="header-title-num">共 <span style="color:#409EFF">{{teachData.length}}</span> 名用户</div>
+          <div class="header-title-btn">
+            <el-button size="small" type="primary" v-if="deleteSchoolArr.length >0" @click="seachAllteach"  :icon="Search">个人数据查询</el-button>
+            <el-button size="small" type="info" disabled :icon="Search" v-else>个人数据查询</el-button>
+          </div>
+          <div class="header-title-hint" v-show="deleteSchoolArr.length >0">
+            <span>目前支持同时最多10名用户查询</span>
+          </div>
+        </div>
+      </div>
+      <div class="teachlist-table">
+        <el-table ref="multipleTableRef" :data="teachData" style="width: 100%"  height="50vh" @selection-change="selectTeach"  @sort-change="tablesrotChange">
+          <el-table-column type="selection" />
+          <el-table-column label="头像" align="center">
+            <template #default="scope">
+              <el-image style="width: 50px; height: 50px" :src="scope.row.picture" fit="fill" v-if="scope.row.picture"></el-image>
+              <PersonalPhoto style="cursor: pointer;" :name="scope.row.name" width="50px" height="50px" v-else></PersonalPhoto>
+            </template>
+          </el-table-column>  
+          <el-table-column property="name" label="姓名" align="center"/>
+          <el-table-column property="id" label="ID" align="center" sortable />
+          <el-table-column property="schoolCode" label="弱归户" align="center" sortable>
+            <template #default="scope">
+              <div>{{scope.row.schoolCodeW ? scope.row.schoolCodeW:'无'}}</div>
+            </template>
+          </el-table-column>
+          <el-table-column property="schoolCodeW" label="归户" align="center" sortable>
+            <template #default="scope">
+              <div>{{scope.row.schoolCode ? scope.row.schoolCode:'无'}}</div>
+            </template>
+          </el-table-column>
+          <el-table-column label="所在地" property="city" align="center" sortable>
+            <template #default="scope">
+              <div>
+                <span>{{scope.row.province ?scope.row.province:''}}</span>
+                <span>{{scope.row.city ?scope.row.city:''}}</span>
+                <span>{{scope.row.dist ?scope.row.dist:''}}</span>
+                <span>{{scope.row.unitName ? '-'+scope.row.unitName:''}}</span>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column property="levels" label="本学期积分"  align="center" sortable>
+            <!-- <template #default="scope">
+            <div>{{scope.row.points && scope.row.points.level ? scope.row.points.level:0}}</div>
+            </template> -->
+          </el-table-column>
+        </el-table>  
+      </div>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="teachtableShow = false">关闭</el-button>
+        </span>
+      </template>  
+    </el-dialog>
+  </div>
 </template>
 <script setup>
 import option_cn from '@/static/regions/region_cn.json'
+import option_gl from '@/static/regions/region_gl.json'
 import { ref, getCurrentInstance, watch, h, nextTick } from 'vue'
 import { ElMessage, TableV2SortOrder, ElLoading, ElCheckbox,HeaderCellSlotProps,ElPopover} from 'element-plus'
 import { Filter } from '@element-plus/icons'
 import { multipleSheetExport } from '@/until/multipleSheetExport'
 import { Search, CirclePlus } from '@element-plus/icons-vue'
+import { useRouter } from 'vue-router'
+import { useStore } from 'vuex'
 import Details from './details.vue'
 let { proxy } = getCurrentInstance()
+let router=useRouter()
+const store = useStore()
 let drawer = ref(false)
 let direction = ref('ttb')
 let activeNames = ref(['1'])
@@ -346,13 +411,34 @@ let columns = ref([
     sortable:true
   },
   {
-    key: "date",
-    dataKey: "date",
-    title: "时间",
-    width: 100,
+    key: "tLesson",
+    dataKey: "tLesson",
+    title: "T课堂",//显示在单元格表头的文本
+    width: 100,//当前列的宽度,必须设置
     headerClass: 'general',
     sortable:true
   },
+  // {
+  //   key: "date",
+  //   dataKey: "date",
+  //   title: "时间",
+  //   width: 100,
+  //   headerClass: 'general',
+  //   sortable:true
+  // },
+  {
+    key: "handle",
+    title: "",
+    width: 150,
+    align: "center",
+    headerClass: 'btn-class',
+    cellRenderer: (data) =>
+    (
+      <>
+        <el-button type="primary"  onClick={examineAllteach.bind(this,data)}>查看所有教师</el-button>
+      </>
+    )
+  },
   {
     key: "handle",
     title: "操作",
@@ -368,6 +454,8 @@ let columns = ref([
   },
 ])
 const popoverRef = ref()
+const siteValue = window.location.host === 'localhost:5001' ? 'cn' : window.location.host === 'bi.teammodel.cn' ? 'cn' : window.location.host === 'bitest.teammodel.cn' ? 'cn' : 'international'
+const optionsData = siteValue === 'cn' ? option_cn : option_gl
 columns.value[0].headerCellRenderer = (props = HeaderCellSlotProps) => {
       return (
         <div class="items-center justify-center">
@@ -396,7 +484,7 @@ columns.value[0].headerCellRenderer = (props = HeaderCellSlotProps) => {
           </ElPopover>
         </div>
       )
-    }
+}
 const sortState = ref({
   'deviceCnt':TableV2SortOrder.ASC,
   'tmidCnt': TableV2SortOrder.ASC,
@@ -570,7 +658,7 @@ const props2 = {
 }
 const areaProps = {
   multiple: false,
-  checkStrictly: false,
+  checkStrictly:true,
   label: "name",
   value: "name",
 }
@@ -584,7 +672,7 @@ let optionCopy = option_cn
 // }()
 console.log(optionCopy, '省')
 /*地区相关配套json end*/
-let changeHight = ref(56)
+let changeHight = ref(51)
 let exportstate = ref(false)
 let dataForm = ref({
   newData: '',
@@ -663,6 +751,12 @@ let filterType=ref({
    totalShow:true,
    unregistered:true,
 })
+let initLoading=ref(false)
+let teachtableShow=ref(false)
+let teachData=ref([])
+let originalTeachdata=ref([])
+let deleteSchoolArr=ref([])
+let touchNowteach=ref()
 const pickerOptions=function disabledDate(time) {
           return time.getTime() > Date.now();
 }
@@ -684,6 +778,7 @@ const monthOptions=function disabledDate(time){
                 const elTimeData = timeyear.toString() + timemonth.toString();
                 return elTimeData >= nowDate; 
 }
+
 function changeState (value) {
   console.log(value)
   showState.value = 'details'
@@ -700,6 +795,7 @@ function selectBlur (e) {
   dataForm.value.newData = e.target.value;
 }
 function dataInit () {
+  initLoading.value=true
   let dataList = []
   proxy.$api.getCapacity({}).then((res) => {
     console.log(res, 'areList')
@@ -725,17 +821,15 @@ function dataInit () {
       tableData.value = res.scInfos
       console.log(dataSource.value.composite, '检查是否是所有学校')
       filterloding.value = false
+      initLoading.value=false
     }).catch((err) => {
       ElMessage.error('API异常,基础数据获取异常')
       filterloding.value = false
+      initLoading.value=false
     })
   }).catch((err) => {
     ElMessage.error('API异常,基础数据获取异常')
   })
-  let a=proxy.$common.numberToTextWithUnit(123456); 
-  let b=proxy.$common.numberToTextWithUnit(1234567890);
-  let c=proxy.$common.numberToTextWithUnit(12345678901234);
-   console.log(a,b,c,'查看文字反应')
 }
  function serachToresult (startTime, endTime, product, schools, unit) {
   // let data = { "dateFrom": "2023-04-12", "dateTo": "2023-04-19", "prod": "HiTeach", "schoolIds": ["tbslgb", "habook"], "dateUnit": "Day" }
@@ -961,9 +1055,9 @@ function serarchInit (value) {
     // dataSource.value.composite=
     console.log(clickNum.value.subject, '0学区值0')
     options.value = dataSource.value.composite
-    clickNum.value.subject === 2 ? options.value = option_cn : ''
+    clickNum.value.subject === 2 ? options.value = optionsData : ''
   } else if (filterKey === 1) {
-    options.value = option_cn
+    options.value = optionsData
     console.log(clickNum.value.district, '1学区值1')
     clickNum.value.district === 2 ? options.value = dataSource.value.composite : ''
   }
@@ -1399,6 +1493,96 @@ function filterSchooltype(){
   console.log(result,'赋值')
   filterdata.value=result
 }
+//获取查看所有老师BTN
+function examineAllteach(value){
+  let teachList=value.rowData.tmidList
+  touchNowteach.value=value.rowData
+  store.commit('transmitUsers', [])
+  let data={tmids:teachList,mode:'simple'}
+  
+  // 預設搜尋時間範圍(當年1月到當月)
+  let date = new Date()
+  let nowYear = date.getFullYear()
+  let nowMonth = date.getMonth()
+  data.dateUnit = "month"
+  data.dateFrom = nowYear + "-1"
+  data.dateTo = nowYear + "-" + (nowMonth+1)
+  
+  proxy.$api.getUserdatas(data).then((res)=>{
+    console.log(res,'查询老师')
+    res.length >0 ?(res.forEach((item)=>{item.levels=item.points && item.points.level ?item.points.level:0}),teachData.value=res,originalTeachdata.value=res) :(teachData.value=[],ElMessage.info('暂无查询到相应用户数据'))
+    teachtableShow.value=true
+  })
+}
+function selectTeach (value) {
+    deleteSchoolArr.value=value
+    console.log(deleteSchoolArr.value,'6666')
+}
+function seachAllteach(){
+  if(deleteSchoolArr.value.length >10){
+      ElMessage.info('当前查询人数仅支持小于或等于10名用户')
+      return
+  }
+  console.log(deleteSchoolArr.value,'传递出去的参数')
+  store.commit('transmitUsers', deleteSchoolArr.value)
+  router.push({name:'userinquire'})  
+}
+function tablesrotChange(rule){
+  console.log(rule,'规则')
+  let rules=rule.order;let datas=teachData.value
+  //id
+  // if(rule.prop ==="id"){
+  //   rules==='descending' ?  datas.sort((a,b)=>{return b.id -a.id >0}):datas.sort((a,b)=>{return a.id -b.id >0})
+  // }else if(rule.prop !=='id'){
+  //   rules ==="descending" ? datas.sort((a,b)=>{if(b.points && a.points){return b.points.level -a.points.level >0}else{ return false}}):
+  //   datas.sort((a,b)=>{if(b.points && a.points){ return a.points.level -b.points.level >0}else{return false}})
+  // }
+  //积分
+  if(rule.prop ==="levels"){
+    rules ==="descending" ? datas.sort((a,b)=>{if(b.points && a.points){return b.level -a.level >0}}):datas.sort((a,b)=>{if(b.points && a.points){return a.level -b.level >0}})
+  }else if(rule.prop ==="id"){
+    rules==='descending' ?  datas.sort((a,b)=>{return b.id -a.id >0}):datas.sort((a,b)=>{return a.id -b.id >0})
+  }else if(rule.prop ==="schoolCode"){
+    rules==='descending' ? datas.sort((a,b)=>{if(!a.schoolCode ||a.schoolCode === null){return 1}else if(!b.schoolCode || b.schoolCode=== null){return -1}else{return 0}}):datas.sort((a,b)=>{if(!a.schoolCode || a.schoolCode === null){return 0}else if(!b.schoolCode ||b.schoolCode=== null){return 0}else{return -1}})
+  }else if(rule.prop ==="schoolCodeW"){
+    rules==='descending' ? datas.sort((a,b)=>{if(!a.schoolCodeW ||a.schoolCodeW === null){return 1}else if(!b.schoolCodeW ||b.schoolCodeW=== null){return -1}else{return 0}}):datas.sort((a,b)=>{if(!a.schoolCodeW || a.schoolCodeW === null){return 0}else if(!b.schoolCodeW ||b.schoolCodeW=== null){return 0}else{return -1}})
+  }else if(rule.prop ==="city"){
+    rules==='descending' ? datas.sort((a,b)=>{if(a.province && a.city){return -1}else if(b.province && b.city){return -1}else{return 0}}):datas.sort((a,b)=>{if(a.province && a.city){return 1}else if(b.province && b.city){return 1}else{return 0}})
+  }
+
+  // if(rules ==="descending"){
+  //   datas.sort((a,b)=>{
+  //     if(b.points && a.points){
+  //       console.log( b.points.level -a.points.level >0,'进入倒序判断')
+  //       return b.points.level -a.points.level >0
+  //     }else{
+  //       console.log('进入倒序判断error ')
+  //     }
+  //   })
+  // }else{
+  //   datas.sort((a,b)=>{
+  //     if(b.points && a.points){
+  //       console.log('进入正序判断')
+  //       return a.points.level -b.points.level >0
+  //     }else{
+  //       console.log('进入正序判断error')
+  //     }
+  //   })
+  // }
+  console.log(datas,'排序后')
+  teachData.value=JSON.parse(JSON.stringify(datas))
+}
+function filterTag(value){
+  console.log(value,'filter')
+  let datas=originalTeachdata.value
+  let dataArr=[]
+  if(value ==='notDepartment'){
+    datas.forEach((item)=>{!item.schoolCodeW ? dataArr.push(item):''})
+  }else if(value ==='weakDepartment'){
+    datas.forEach((item)=>{item.schoolCodeW ? dataArr.push(item):''})
+  }
+  teachData.value=dataArr
+}
 // init()
 dataInit()
 filterDistrict()
@@ -1602,6 +1786,28 @@ watch(clickNum, (newv) => {
 .school-type {
   display: flex;
 }
+.dialog-teachlist{
+  line-height: 40px;
+}
+.header-title-content{
+  display: flex;
+  flex-direction: row-reverse;
+  position: relative;
+}
+.header-title-schoolname{
+  font-size:20px;
+  text-align: center;
+}
+.header-title-num{
+  margin-left:2%;
+}
+.header-title-hint{
+  position:absolute;
+  top:0%;
+  left:1%;
+  font-size:12px;
+  color:#909399;
+}
 </style>
 <style>
 .data-tables .header-class,
@@ -1663,4 +1869,8 @@ watch(clickNum, (newv) => {
 .data-tables .el-table-v2__header-cell:hover .el-icon{
   display: flex;
 }
+.dialog-teachlist .el-dialog__header{
+  padding: 5px;
+
+}
 </style>

+ 37 - 18
TEAMModelBI/ClientApp/src/view/schoolServe/school.vue

@@ -565,12 +565,10 @@ export default {
         // sortable: true,
          cellRenderer: (data) => (
           <>
-            <div style="color:#000000;" v-show={data.rowData.versions !=='基础版' && data.rowData.versions !=='标准版' && data.rowData.versions !=='专业版'}>{data.rowData.versions}</div>
             <div style="color:#e6a23c;" v-show={data.rowData.versions ==='专业版' ? true:false}>专业版</div>
             <div style="color:#67C23A;" v-show={data.rowData.versions ==='标准版' ? true:false}>标准版</div>
             <div style="color:#409EFF;" v-show={data.rowData.versions ==='基础版' ? true:false}>基础版</div>
-            
-            
+            <div style="color:#fab6b6;" v-show={data.rowData.versions ==='评测版' ? true:false}>评测版</div>
           </>
         ),
       },
@@ -729,7 +727,7 @@ export default {
                       基础版
                     </ElCheckbox>
                     <ElCheckbox v-model={shouldFilter.value.custom} onChange={versionsEstimate}>
-                      自訂
+                      评测
                     </ElCheckbox>
                   </div>
                   {/* <div class="el-table-v2__demo-filter">
@@ -800,7 +798,7 @@ export default {
         res.scInfos.forEach((item)=>{
          // debugger;
           //item.versions= item.service.includes('YPXSJ6NJ') && item.service.includes('B6V5J6NP') ? '专业版':item.service.includes('YMPCVCIM') ? '标准版':'基础版'}),
-          if (item.edition !== null) {
+          /* if (item.edition !== null) {
                 if (item.edition.scaleVersion !== null && item.edition.scaleVersion !== "") {
                   item.versions = item.edition.scaleVersion;
                 } else {
@@ -808,7 +806,22 @@ export default {
                 }
               } else {
                 item.versions = item.service.includes('YPXSJ6NJ') && item.service.includes('B6V5J6NP') ? '专业版' : item.service.includes('YMPCVCIM') ? '标准版' : '基础版';
-              }
+          } */
+          //11.14日修正  关于学校版本问题   根据edition   current /1基础   /2标准   /3专业
+          if (item.code === 'BIRel'){
+            item.edition && item.edition.scaleVersion == '评测版' ? item.versions = '评测版' :
+            item.edition && item.edition.current === 3 ? item.versions = '专业版' :
+            item.edition && item.edition.current === 2 ? item.versions = '标准版' :
+            item.edition == null || (item.edition && item.edition.current == null) || (item.edition && item.edition.current === 1 && (item.edition.scaleVersion == null || item.edition.scaleVersion == '')) ? item.versions = '基础版' : ''
+          }else{
+            item.versions=''
+          }
+          /*
+          item.versions =item.service.includes('YPXSJ6NJ') && item.service.includes('B6V5J6NP') && item.service.includes('YMPCVCIM') ? '专业版':
+          item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && (!item.service.includes('YPXSJ6NJ')) ? '标准版':
+          !item.service.includes('IPDYZYLC') && !item.service.includes('YMPCVCIM') && item.service.includes('B6V5J6NP')   ?'评测版':
+          !item.service.includes('IPDYZYLC') && !item.service.includes('YMPCVCIM')  ? '基础版':'基础版' 
+                    */
         }),
         tableData.value.push(...res.scInfos),originalNum.value = res.scInfos.length,
         originalData.value = res.scInfos,tablesccnt.value = res.allCnt) 
@@ -1504,6 +1517,7 @@ export default {
     }
     // ※版本判定:1.學校管理(IPDYZYLC) + 學情分析(YMPCVCIM)=「標準版」 
     //             2.學校管理(IPDYZYLC) + 學情分析(YMPCVCIM) + 五育看板(YPXSJ6NJ) =「專業版」  
+    //  11.14日修正  关于学校版本问题   根据edition   current /1基础   /2标准   /3专业
     function versionsEstimate (val) {
       console.log(shouldFilter.value)
       let arrState = shouldFilter.value
@@ -1512,21 +1526,26 @@ export default {
       //debugger;
       // debugger;
        // 專業版
-       arrState.major ? originalData.value.forEach((item) => {
-         (item.edition == null || item.edition.scaleVersion == null || item.edition.scaleVersion == "") 
-         && item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && item.service.includes('YPXSJ6NJ') 
-         ? marjorArr.push(item) : '' }) : ''
+        arrState.major ? originalData.value.forEach((item) => {
+         // item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && item.service.includes('YPXSJ6NJ') ? marjorArr.push(item) : '' }) : '' 
+         item.edition && item.edition.current === 3 && item.code === 'BIRel' ? marjorArr.push(item) : ''
+        }) : ''
        // 標準版
-       arrState.standard ? originalData.value.forEach((item) => { 
-        (item.edition == null || item.edition.scaleVersion == null || item.edition.scaleVersion == "") 
-        && item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && (!item.service.includes('YPXSJ6NJ')) ? standardArr.push(item) : '' }) : ''
+        arrState.standard ? originalData.value.forEach((item) => { 
+         // item.service.includes('IPDYZYLC') && item.service.includes('YMPCVCIM') && (!item.service.includes('YPXSJ6NJ')) ? standardArr.push(item) : ''
+         item.edition && item.edition.current === 2 && item.code === 'BIRel' ? standardArr.push(item) : ''
+        }) : ''
        // 基礎版
-       arrState.basics ? originalData.value.forEach((item) => { 
-        (item.edition == null || item.edition.scaleVersion == null || item.edition.scaleVersion == "") 
-        && !item.service.includes('IPDYZYLC') && !item.service.includes('YMPCVCIM') ? basicsArr.push(item) : '' }) : ''
+        arrState.basics ? originalData.value.forEach((item) => { 
+         // !item.service.includes('IPDYZYLC') && !item.service.includes('YMPCVCIM') && !item.service.includes('B6V5J6NP') ? basicsArr.push(item) : ''
+         item.code === 'BIRel' && (item.edition == null || (item.edition && item.edition.current == null) || (item.edition && item.edition.current === 1 && (item.edition.scaleVersion == null || item.edition.scaleVersion == ''))) ? basicsArr.push(item) : ''
+        }) : '' 
        // 自訂版
-       arrState.custom ? originalData.value.forEach((item) => { 
-        item.edition !== null && item.edition.scaleVersion !== null && item.edition.scaleVersion !== "" ? customArr.push(item) : '' }) : ''           
+        arrState.custom ? originalData.value.forEach((item) => { 
+         // !item.service.includes('IPDYZYLC') && !item.service.includes('YMPCVCIM') && item.service.includes('B6V5J6NP') ? customArr.push(item) : ''
+         item.edition && item.code === 'BIRel' && item.edition.scaleVersion == '评测版' ? customArr.push(item) : ''
+        }) : ''   
+        console.log(marjorArr,standardArr,basicsArr,customArr,'重组')        
       let versionArr = [...marjorArr, ...standardArr, ...basicsArr, ...customArr]
       console.log(versionArr, '合并结果')
       tableData.value = versionArr

+ 2 - 2
TEAMModelBI/ClientApp/src/view/schoolmanage/schoolAnalyse.vue

@@ -2122,7 +2122,7 @@ export default {
           schoolDeatils.value.versions = ''
           anSchool.value.teachNum = res.scStats.tch
           anSchool.value.studentNum = res.scStats.stu
-          anSchool.value.classNum = res.scStats.room
+          anSchool.value.classNum = res.scStats.witRoom
           anSchool.value.classInfoNum = res.scStats.lessStats.all
           detailsLoding.value.header = false
           //处理柱状图
@@ -2832,7 +2832,7 @@ export default {
 .class-info,
 .class-total {
   width: 100%;
-  padding: 0.5% 1%;
+  padding: 1%;
   display: flex;
   flex-wrap: nowrap;
   justify-content: space-between;

+ 93 - 15
TEAMModelBI/ClientApp/src/view/systemConfig/pushmsg/createdpush.vue

@@ -141,7 +141,7 @@
                   <!--学区选择列表(学区)-->
                   <div class="type-list" v-else-if="typeselect ===1">
                     <el-checkbox-group v-model="constructorData.receivedata.area" @change="pitchChange">
-                      <div class="itemtype-area" v-for="item in allList.allArea" :title="item.name">
+                      <div class="itemtype-area" v-for="item in allList.allArea" :key="item" :title="item.name">
                         <el-checkbox :label="item.name" :key="item.id" />
                         <div class="next-icon" @click="subordinate(item.id),typeselect=2,clickname=item.name">
                           下级
@@ -280,7 +280,7 @@
                       </div>
                       <div class="not-inquirebox">
                         <p class="result-titles">查询失败:</p>
-                        <div class="notinquirebox-box" v-for="itemE in batchResult.not">
+                        <div class="notinquirebox-box" v-for="itemE in batchResult.not" :key="itemE">
                           <div class="errorbox" :title="itemE">{{itemE}}</div>
                           <div class="errortitle">未查询到相关信息</div>
                         </div>
@@ -298,7 +298,7 @@
               <el-button size="small" :icon="Delete" @click="clearall">全部清除</el-button>
             </div>
             <div class="receivebox">
-              <el-tag class="crowd-tag" v-for="item in receivedatas" :type="item.dataType==='area' ? 'warning':item.dataType ==='school' ? 'success' :'' " closable @close="removecrowd(item)">
+              <el-tag class="crowd-tag" v-for="item in receivedatas" :key="item" :type="item.dataType==='area' ? 'warning':item.dataType ==='school' ? 'success' :'' " closable @close="removecrowd(item)">
                 {{item.name}}
               </el-tag>
             </div>
@@ -351,7 +351,7 @@
           <div class="crowd">
             <p class="result-title">接收人群</p>
             <div class="crowdbox">
-              <el-tag class="crowd-tag" v-for="item in receivedatas" :type="item.dataType ==='area' ? 'warning':item.dataType ==='school' ? 'success':'' " closable>
+              <el-tag class="crowd-tag" v-for="item in receivedatas" :key="item" :type="item.dataType ==='area' ? 'warning':item.dataType ==='school' ? 'success':'' " closable>
                 {{item.name}}
               </el-tag>
             </div>
@@ -880,21 +880,99 @@ function publish () {
   })
 }
 //system通知  访问TW API内容
-function pushSystem(){
+ function pushSystem(){    
   console.log(constructorData.value)
   console.log(receivedatas.value)
   console.log(constructorData.value.receiveType)
   let tagsData=[]; let receives=constructorData.value.receiveType =='hita5' ? 'HiTA':constructorData.value.receiveType
-  receivedatas.value.forEach((item)=>{tagsData.push(item.id+'_'+receives)})
-  let data=''
-  if(constructorData.value.systemType ==='interior'){
-    data={tags:tagsData,title:constructorData.value.basic.title,body:constructorData.value.basic.content,sender:'HiTeach'}
-  }else{
-    data={hubName:constructorData.value.receiveType,tags:tagsData,title:constructorData.value.basic.title,body:constructorData.value.basic.content,sender:'HiTeach'}
+  receivedatas.value.forEach((item) => { tagsData.push(item.id + '_' + receives) })
+  let action = {};
+  let data = {};
+  // 設定內容
+  if (constructorData.value.basic.callbackstate) {
+    if (constructorData.value.basic.callbackFn === '1') {// 同意拒絕
+      action = {
+        action: [
+          {
+            "type": "click",
+            "label": "同意",
+            "url": constructorData.value.basic.skipUrl,
+            "tokenbindtype": 1
+          },
+          {
+            "type": "click",
+            "label": "拒绝",
+            "url": constructorData.value.basic.skipUrl,
+            "tokenbindtype": 1
+          }
+        ]
+      }
+    } else if (constructorData.value.basic.callbackFn === '2') {// 查看
+      action = {
+        action: [
+          {
+            "type": "click",
+            "label": "查看",
+            "url": constructorData.value.basic.skipUrl,
+            "tokenbindtype": 1
+          }
+        ]
+      }
+    }
   }
-  console.log(data,'通知的参数')
-   proxy.$api.sendPushnotify(data).then((res)=>{
-     ElMessage.success('消息发送成功')
+  if (constructorData.value.systemType === 'interior') {
+    data = { 
+      tags: tagsData, 
+      title: constructorData.value.basic.title, 
+      body: constructorData.value.basic.content, 
+      sender: 'HiTeach',
+      eventId: "BI-send",
+      eventName: "BI_SendNotice",      
+      data: JSON.stringify(action)
+     }
+  } else {    
+    data = { 
+      hubName: constructorData.value.receiveType, 
+      tags: tagsData, 
+      title: constructorData.value.basic.title, 
+      body: constructorData.value.basic.content,       
+      sender: 'HiTeach',
+      eventId: "BI-send",
+      eventName: "BI_SendNotice",
+      data: JSON.stringify(action)     
+    }
+  }
+  //debugger;
+  //处理接受人群分类
+  let areaArr = []; let schoolArr = []; let personageArr = [];
+  receivedatas.value.forEach((item) => { item.hasOwnProperty('dataType') ? item.dataType === 'area' ? areaArr.push({ id: item.id, name: item.name }) : item.dataType === 'school' ? schoolArr.push({ id: item.id, name: item.name }) : '' : personageArr.push({ id: item.id, name: item.name }) })
+  let timePs = new Date().getTime();
+  
+  let submitdata = {
+    type: Number(constructorData.value.basic.type) - 1,
+    jumpUrl: constructorData.value.basic.skipstate ? constructorData.value.basic.skipUrl : '',
+    callbackName: constructorData.value.basic.callbackstate && constructorData.value.basic.callbackFn === '1' ? '同意' : constructorData.value.basic.callbackstate && constructorData.value.basic.callbackFn === '2' ? '查看' : '',
+    refuseName: constructorData.value.basic.callbackstate && constructorData.value.basic.callbackFn === '1' ? '拒绝' : '',
+    theme: constructorData.value.basic.title,
+    content: constructorData.value.basic.content,
+    tmdIds: personageArr,
+    schoolIds: schoolArr,
+    areaIds: areaArr,
+    crowdType: constructorData.value.receiveType,
+    sendTime: timePs,
+    source: constructorData.value.source,
+    isOnlySave: true
+  }
+   proxy.$api.sendPushnotify(data).then(async (res)=>{
+    //debugger;
+    
+      await proxy.$api.sendMsgs(submitdata).then((res_save) => {            
+      }).catch((error) => {
+        ElMessage.error('紀錄API异常,消息发送失败!')
+      })
+    
+
+      await ElMessage.success('消息发送成功'), clearData(), router.push('/home/pushmsg');
    }).catch((error)=>{
     ElMessage.error('API异常,消息发送失败!')
    })
@@ -1023,7 +1101,7 @@ watch(store.state.msgData, (newvalue) => {
   clear: both;
 }
 .clearfix {
-  *zoom: 1;
+  zoom: 1;
 }
 .stepsshow {
   display: flex;

+ 4 - 1
TEAMModelBI/ClientApp/src/view/systemConfig/pushmsg/index.vue

@@ -2,7 +2,7 @@
   <div class="msgbox">
     <div class="header">
       <div class="block">
-        <el-date-picker v-model="value1" type="daterange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" :locale="locale" />
+        <!-- <el-date-picker v-model="value1" type="daterange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" :locale="locale" /> -->
       </div>
       <div>
         <el-button type="primary" @click="skipcreated">
@@ -202,6 +202,7 @@ let tableSelect = ref({
     { value: 'common', label: '普通' },
     { value: 'hint', label: '提示' },
     { value: 'special', label: '特殊' },
+    { value: 'system', label: '系統' },
   ]
 })
 let showState = ref('default')
@@ -243,6 +244,8 @@ function changeTag (val) {
     tableData.value = originalData.value.filter((item) => { return item.type === 3 })
   } else if (values === 'special') {
     tableData.value = originalData.value.filter((item) => { return item.type === 4 })
+  } else if (values === 'system') {
+    tableData.value = originalData.value.filter((item) => { return item.type === 1 })
   }
 }
 function detailsMsg (val) {

File diff suppressed because it is too large
+ 1118 - 0
TEAMModelBI/ClientApp/src/view/systemConfig/server/index.vue


File diff suppressed because it is too large
+ 728 - 115
TEAMModelBI/ClientApp/src/view/userInquire/details.vue


+ 126 - 109
TEAMModelBI/ClientApp/src/view/userInquire/ies.vue

@@ -13,7 +13,7 @@
         </div>
         <el-divider />
             <div class="joinSchool">
-                <div class="joinSchool-item">
+                <div class="joinSchool-item" v-if="iesShow">
                     <div class="joinSchool-img">
                         <svg class="joinSchool-icon" aria-hidden="true">
                             <use xlink:href="#icon-xuexiao8"></use>
@@ -62,18 +62,22 @@
                         <span>默认学校</span>
                     </div>
                 </div>
+                <div class="not-datas" v-else>
+                    暂无学校信息
+                </div>
             </div>
         <el-divider />
             <div class="ies-flex">
-                <div class="ies-flex-echart">
-                    <Pies :piesData="echartsBar"></Pies>
-                </div>
-                <div class="ies-flex-text">
-                    <p>总计:</p>
-                    <p v-for="item in personageSize" :key="item.key">
-                        <span>{{item.title}}:</span><span class="sizenum-text">{{item.value}}</span> GB
-                    </p>
-                </div>
+                <!-- <div class="schools-item" v-for="item in schooldata" :key="item.code">
+                <div class="schools-item-name">{{item.name}}<span class="school-item-edition">专业版</span></div>
+                <p class="schools-item-location">{{item.code}} | {{item.location}}</p>
+                <div class="schools-item-charge">负责课程数<span class="schools-item-charge-num">{{item.class}}</span></div>
+                <div class="schools-item-size">
+                    <p class="schools-item-size-title">学校空间状态</p>
+                    <span class="schools-item-size-text">{{item.totalsize}}GB 中的 {{item.occupy}}GB (20%)</span>
+                </div> -->
+            <!-- </div> -->
+            <!-- <bars :barData="echartsBar"></bars> -->
             </div>
             <div class="dialog-school">
                 <el-dialog v-model="allschoolState" title="加入学校列表" width="50%" :before-close="handleClose">
@@ -120,11 +124,9 @@
  import { ArrowRight } from '@element-plus/icons'
  import * as echarts from 'echarts'
  import bars from '@/components/echarts/commonBar.vue'
- import Pies from './echarts/pie.vue'
  let props = defineProps({
     iesdata: Object,
 })
-let { proxy } = getCurrentInstance()
  let relevancedata = ref([
       { title: '资源数', icon: '#icon-anli', value: 0, key: 'material' },
       { title: '试题数', icon: '#icon-tiku', value: 0, key: 'question' },
@@ -149,78 +151,117 @@ let { proxy } = getCurrentInstance()
       {name:'南京特殊教育师范学院',code:'ntsjsy',location:'中国',class:15,totalsize:300,occupy:75}
  ])
  let allschoolList=ref([])
- let personageSize=ref([
-    {title:'总大小',value:0,key:'total'},
-    {title:'已使用',value:0,key:'used'},
-    {title:'已剩余',value:0,key:'residue'},
-    {title:'学校分配空间',value:0,key:'allocation'}
- ])
+ let iesShow=ref(true)
  let echartsBar=ref({
-    title: {
-        text: 'IES个人空间',
-        x: 'center',
-        y: 'center',
-        textStyle: {
-            fontWeight: 'normal',
-            color: '#0580f2',
-            fontSize: '20'
+    tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+            type: 'shadow'
         }
     },
-    color: ['rgba(176, 212, 251, 1)'], 
-    // legend: {
-    //     show: true,
-    //     itemGap: 12,
-    //     data: ['01', '02']
-    // },
-    "tooltip": {
-        "trigger": 'item',
-        "formatter": "{b} : ({d}%)"
+    grid: {
+        // top: '15%',
+        // right: '3%',
+        // left: '5%',
+        bottom: '8%'
     },
+    xAxis: [{
+        data: ['合作','互动','任务','差异化','测验'],
+        axisLine: {
+            lineStyle: {
+                color: '#333'
+            }
+        },
+        axisLabel: {
+            // margin: 10,
+            color: '#333',
+            textStyle: {
+                fontSize: 10
+            },
+        },
+    }],
+    yAxis: [{
+        name: "课堂型态",
+        nameTextStyle: {
+            color: '#0177d4',
+            fontSize: 12
+        },
+        axisLine: {
+            show:true,
+            lineStyle: {
+                color: '#0177d4',
+                width:'1'
+            }
+        },
+        axisLabel: {
+            color: '#0177d4',
+            fontSize: 16
+        },
+        splitLine: {
+            show:false,
+            lineStyle: {
+                color: '#0177d4'
+            }
+        },
+    }],
     series: [{
-        type: 'pie',
-        clockWise: true,
-        radius: ['55%', '80%'],
-        itemStyle: {
-            normal: {
-                label: {
-                    show: false
-                },
-                labelLine: {
-                    show: false
-                }
+        type: 'bar',
+        data: [300, 450, 770, 203],
+        barWidth: '16px',
+        barBorderRadius: 5,
+        itemStyle:{
+            normal:{
+                color:new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
+                    offset: 0,
+                    color: '#00b0ff'
+                }, {
+                    offset: 0.8,
+                    color: '#7052f4'
+                    }], false),
+               barBorderRadius: 5,
             }
         },
-        hoverAnimation: true, 
-        data: [{
-            value: 80,
-            name: '已使用',
-            itemStyle: {
-                normal: {
-                    color: { // 完成的圆环的颜色
-                        colorStops: [{
-                            offset: 0,
-                            color: '#00cefc' // 0% 处的颜色
-                        }, {
-                            offset: 1,
-                            color: '#367bec' // 100% 处的颜色
-                        }]
+        label: {
+            normal: {
+                show: true,
+                lineHeight: 30,
+                width: 80,
+                height: 30,
+                backgroundColor: 'rgba(0,160,221,0.1)',
+                borderRadius: 200,
+                position: ['-8', '-60'],
+                distance: 1,
+                formatter: [
+                    '    {d|●}',
+                    ' {a|{c}}     \n',
+                    '    {b|}'
+                ].join(''),
+                rich: {
+                    d: {
+                        color: '#3CDDCF',
                     },
-                    label: {
-                        show: false
+                    a: {
+                        color: '#00b0ff',
+                        align: 'center',
                     },
-                    labelLine: {
-                        show: false
-                    }
-                } 
+                    b: {
+                        width: 1,
+                        height: 30,
+                        borderWidth: 1,
+                        borderColor: '#234e6c',
+                        align: 'left'
+                    },
+                }
             }
-        }, {
-            name: '已剩余',
-            value: 20
-        }]
+        }
     }]
  })
  function initdatas(){
     console.log(props.iesdata,'IESde zhi')
+    if(!props.iesdata){
+        iesShow.value=false 
+        return
+    }
     let {resCount,itemCount,paperCount}=props.iesdata
     relevancedata.value[0].value=resCount
     relevancedata.value[1].value=itemCount
@@ -251,29 +292,15 @@ let { proxy } = getCurrentInstance()
         items.size.percentage=Math.round(((items.size.used/ items.size.total).toFixed(2))*100)
         allschoolList.value.push(items)
     })
-    //处理空间大小
-    let {usedSize,surplusSize,totalSize,teachSize}=props.iesdata
-    let transitionUsed=usedSize ?bytesToGB(usedSize):0
-    let transitionSuplus=surplusSize ? bytesToGB(surplusSize):0
-    let transitionTotal=totalSize ? bytesToGB(totalSize):0
-    let transitionTeach=teachSize ? bytesToGB(teachSize):0
-    console.log(transitionUsed,transitionSuplus,transitionTotal,transitionTeach,'各个大小')
-    // echartsBar.value.series[0].data[0].value = (usedSize/totalSize).toFixed(2)*100
-    echartsBar.value.series[0].data[0].value= transitionUsed !==0 ? Math.round((transitionUsed/transitionTotal).toFixed(2)*100):0
-    echartsBar.value.series[0].data[1].value=100-Number(echartsBar.value.series[0].data[0].value)
-    personageSize.value[0].value=transitionTotal
-    personageSize.value[1].value=transitionUsed
-    personageSize.value[2].value=transitionSuplus
-    personageSize.value[3].value=transitionTeach
     console.log(allschoolList.value,'list')
  }
- function bytesToGB(bytes) {
-  const gb = bytes / (1024 * 1024 * 1024);
-  return gb.toFixed(0); // 将结果保留两位小数
-}
  onMounted(() => {
     initdatas()
 })
+watch(()=>props,(newvalue)=>{
+    console.log(newvalue,'有新值进入IES')
+    newvalue.iesdata ? (allschoolList.value=[],initdatas()):''
+},{deep:true})
  </script>
  <style scoped>
  .ies-content{
@@ -316,21 +343,6 @@ let { proxy } = getCurrentInstance()
     justify-content: space-between;
     overflow: hidden;
     overflow-x: auto; */
-    display: flex;
-    align-items: center;
- }
- .ies-flex-echart{
-    width:70%;
-    height:100%;
- }
- .ies-flex-text{
-    width:30%;
-    text-align: left;
-    padding-left: 1%;
-    line-height: 40px;
- }
- .ies-flex-text p{
-    margin-bottom: 5px;
  }
  .schools-item{
     flex: 0 0 40%;
@@ -460,17 +472,20 @@ let { proxy } = getCurrentInstance()
     padding: 1%;
     display: flex;
     flex-wrap: wrap;
+    height:64vh;
+    overflow: hidden;
+    overflow-y: auto;
  }
  .dialogschool-item{
-    width:25%;
+    width:30%;
     padding: 2% 1%;
     justify-content: center;
     align-items: center;
     border:1px solid #ccc;
     border-radius: 5px;
-    margin:0px 10px;
     position:relative;
     overflow: hidden;
+    margin:1%;
  }
  .dialogschool-item-top,.item-content-tile{
     text-align: center;
@@ -539,10 +554,12 @@ let { proxy } = getCurrentInstance()
  .fontsize{
     font-size:12px;
  }
- .sizenum-text{
-    font-weight: bold;
-    color:#409EFF;
- }
+ .not-datas{
+    font-size:16px;
+    font-weight: 700;
+    color: #73767a;
+    line-height: 40px;
+}
  </style>
 <style>
 .dialog-school .el-dialog__body{

+ 158 - 38
TEAMModelBI/ClientApp/src/view/userInquire/index.vue

@@ -1,49 +1,67 @@
 <template>
-    <div class="inquirebox" v-if="pageShow ==='default'">
+    <div class="inquirebox" >
         <div class="inquire-title">
             <p>TEAM Model 智慧教育</p>
         </div>
-        <div class="searchbox" v-loading="searchLoading" element-loading-text="数据搜索中...">
-            <div class="searchbox-title">
-                <p>用户查询</p>
-            </div>
-            <el-divider border-style="dashed" />
-            <div class="searchbox-item">
-                <el-input v-model="searchvalue" placeholder="输入手机号码/醍摩豆账号 进行搜索" class="input-with-select">
-                <template #prepend>
-                    <el-select v-model="selecttypes" placeholder="Select" style="width: 120px">
-                    <el-option label="精准查询" value="precise" />
-                    <!-- <el-option label="批量查询/操作" value="batch" /> -->
-                    </el-select>
-                </template>
-                <template #append>
-                    <el-button :icon="Search" @click="seachSole()"/>
-                </template>
-                </el-input>
-            </div>
-            <!-- <div class="recordbox" v-if="selecttypes==='precise'">
-                <p>搜索记录:</p>
-                <div class="recordbox-item">
-                    <el-tag v-for="tag in tags" :key="tag.name" class="mx-1" closable :type="tag.type">
-                        {{ tag.name }}
-                    </el-tag>
+        <el-tabs v-if="pageShow ==='default'" style="width: 100%;height:100%;" type="card" class="demo-tabs">
+            <el-tab-pane label="用户查询" style="padding: 1%;display: flex;justify-content: center;">
+                <div class="searchbox" v-loading="searchLoading" element-loading-text="数据搜索中...">
+                    <div class="searchbox-title">
+                        <p>用户查询</p>
+                    </div>
+                    <el-divider border-style="dashed" />
+                    <div class="searchbox-item">
+                        <el-input v-model="searchvalue" placeholder="输入手机号码/醍摩豆账号 进行搜索" class="input-with-select">
+                        <template #prepend>
+                            <el-select v-model="selecttypes" placeholder="Select" style="width: 120px">
+                            <el-option label="精准查询" value="precise" />
+                            <!-- <el-option label="批量查询/操作" value="batch" /> -->
+                            </el-select>
+                        </template>
+                        <template #append>
+                            <el-button :icon="Search" @click="seachSole()"/>
+                        </template>
+                        </el-input>
+                    </div>
+                    <div class="recordbox" v-if="selecttypes==='precise'">
+                        <p>搜索记录:</p>
+                        <div class="recordbox-item">
+                            <el-tag v-for="tag in searchRecordsArr"  class="mx-1" closable type="''"  effect="light" @close="deleteLog(tag)" @click="searchvalue=tag">
+                                {{ tag }}
+                            </el-tag>
+                        </div>
+                        <div class="dele-all" v-show="searchRecordsArr.length >0">
+                            <el-icon size="14" @click="deleAllsearch"><Delete /></el-icon>
+                        </div>
+                    </div>
+                    <div class="recordbox" v-else="selecttypes ==='batch'">
+                        <p>搜索结果:</p>
+                    </div>
                 </div>
-            </div>
-            <div class="recordbox" v-else="selecttypes ==='batch'">
-                <p>搜索结果:</p>
-            </div> -->
+            </el-tab-pane>
+            <el-tab-pane label="弱歸戶" style="padding: 1%">
+                <UpdCodeW />
+            </el-tab-pane>
+        </el-tabs>
+        <div class="inquirebox-details" v-else-if="pageShow ==='details'">
+            <Detailsbox :searchdata="searchResult" :defDate="defDate" @parentClick="backClicks"></Detailsbox>
         </div>
     </div>
-    <div class="inquirebox-details" v-else-if="pageShow ==='details'">
-        <Detailsbox :searchdata="searchResult" @parentClick="backClicks"></Detailsbox>
-    </div>
 </template>
 <script setup>
-import { ref, getCurrentInstance, watch, h, nextTick } from 'vue'
+import { ref, getCurrentInstance, watch, h, nextTick,provide } from 'vue'
 import { ElMessage, ElLoading } from 'element-plus'
-import { Search } from '@element-plus/icons'
+import { Search,Delete } from '@element-plus/icons'
 import Detailsbox from './details.vue'
+import UpdCodeW from './updCodeW.vue'
+import {useRoute} from "vue-router"
+import { useStore } from 'vuex'
 let { proxy } = getCurrentInstance()
+let route=useRoute()
+const store = useStore()
+let transmitUser=store.state.transmitvalue
+let transmitModel=ref(transmitUser.length >0 ? true:false)
+console.log(store,'用户传递')
 let tags = ref([
   { name: 'Tag 1', type: '' },
   { name: 'Tag 2', type: 'success' },
@@ -55,25 +73,105 @@ let pageShow = ref('default')
 let searchvalue=ref('')
 let selecttypes = ref('precise')
 let searchResult=ref()
+let defDate = ref()
 let searchLoading=ref(false)
+const searchRecordsArr = ref(localStorage.getItem('searchRecords') ?  JSON.parse(localStorage.getItem('searchRecords')):[]);
 const backClicks=()=>{pageShow.value='default'}
+console.log(searchRecordsArr.value,'搜索记录')
+//逻辑判断  是否是从 产品使用分析跳转过来
+transmitModel.value ? transmitinit():''
+provide('transmitShow',transmitModel.value)
 function seachSole(datavalue) {
     if(!searchvalue.value){
         ElMessage.info('请输入手机号码/ 醍魔豆账号 进行搜索!')
         return
     }
-    let data = {'tmids':[searchvalue.value]}
+    //处理TW用户 ID可能是以0开头的情况。删除掉开头的0
+    if(searchvalue.value.startsWith('0')){
+        searchvalue.value =searchvalue.value.substring(1)
+    }
+    //处理多名用户查询
+    let userArr=''
+    if(searchvalue.value.includes(',') || searchvalue.value.includes(',')){
+        searchvalue.value=searchvalue.value.replace(/,/g, ',');
+        userArr = searchvalue.value.split(',');
+    }
+    if(userArr.length >10){
+            ElMessage.info('同时查询人员不能大于10,请调整查询范围')
+            return
+    }
+    //let testdata=['1524738018','1595321354']
+    let data = ''
+    //let data={'tmids':testdata}
+    searchvalue.value.includes(',') || searchvalue.value.includes(',') ? data={'tmids':userArr}: data = {'tmids':[searchvalue.value]}
     console.log(data)
     searchLoading.value=true
+    let setData={
+        value:searchvalue.value,
+        type:searchvalue.value.includes(',') || searchvalue.value.includes(',') ? 'multiple':'only',
+        time:Date.now()
+    }
+    // 預設搜尋時間範圍(當年1月到當月)
+    let date = new Date()
+    let nowYear = date.getFullYear()
+    let nowMonth = date.getMonth()
+    data.dateUnit = "month"
+    data.dateFrom = nowYear + "-1"
+    data.dateTo = nowYear + "-" + (nowMonth+1)
+
     proxy.$api.getUserdatas(data).then((res) => { 
+        //重置vuex内的值,预防下次Menu进入 自动获取vuex值进行查询
+        store.commit('transmitUsers', [])
         console.log(res, 'user back')
-        res.length >0 ? (searchResult.value=res,searchLoading.value=false,pageShow.value='details'):(ElMessage.error('暂无搜索到相关人员,请检查信息搜索'),searchLoading.value=false)
+        res.length >0 ? 
+        (searchResult.value=res,searchLoading.value=false,pageShow.value='details',defDate.value=[new Date(nowYear, 0), new Date(nowYear, nowMonth)]):
+        (ElMessage.error('暂无搜索到相关人员,请检查信息搜索'),searchLoading.value=false)
+        //搜索记录
+        if(res.length >0){saveSearchRecord(searchvalue.value)}
     }).catch((err) => {
         searchLoading.value=false
         ElMessage.error('API异常,查询失败')
     })
     // pageShow.value='details'
- }
+}
+// 保存搜索记录到localStorage(重复搜索的只记录一个)
+function saveSearchRecord(keyword) {
+  let searchRecords = localStorage.getItem('searchRecords');
+  console.log(searchRecords,'存储数据')
+  !searchRecords ?searchRecords = []:searchRecords = JSON.parse(searchRecords);
+  if (!searchRecords.includes(keyword)) {
+    searchRecords.push(keyword);
+    searchRecordsArr.value.push(keyword)
+  }
+  localStorage.setItem('searchRecords', JSON.stringify(searchRecords));
+}
+function deleteLog(value){
+    console.log(value)
+    let parseSearchRecords=searchRecordsArr.value
+    console.log(parseSearchRecords,'数组内容')
+    let resultNum=parseSearchRecords.findIndex((item)=>{return item ===value})
+    console.log(resultNum,'数字')
+    resultNum !== -1 ? (searchRecordsArr.value.splice(resultNum,1)):''
+    localStorage.setItem('searchRecords', JSON.stringify(searchRecordsArr.value));
+}
+function transmitinit(){
+    console.log('被调用')
+    let users=store.state.transmitvalue
+    let searchvs=''
+    users.forEach(element => {
+        if(searchvs.length ===0){
+            searchvs=element.id
+        }else{
+            searchvs=searchvs+','+element.id
+        }
+    });
+    searchvalue.value=searchvs
+    seachSole()
+}
+function deleAllsearch(){
+    searchRecordsArr.value=[]
+    localStorage.setItem('searchRecords', JSON.stringify(searchRecordsArr.value));
+}
 </script>
 <style scoped>
 .inquirebox{
@@ -89,9 +187,10 @@ function seachSole(datavalue) {
     align-items: center;
     justify-content: center;
     position: relative;
+    /* height: 86vh; */
 }
 .searchbox{
-    width:60%;
+    width: 40vw;
     height:50vh;
     background-color: #fff;
     z-index:999;
@@ -125,6 +224,10 @@ function seachSole(datavalue) {
     padding: 0% 10%;
     line-height: 20px;
     text-align: left;
+    height:15vh;
+    overflow: hidden;
+    overflow-y: auto;
+    position:relative;
 }
 .recordbox p{
     font-size:14px;
@@ -148,4 +251,21 @@ function seachSole(datavalue) {
     font-size:14px;
     display: flex;
 }
+.dele-all{
+    position: absolute;
+    top:1%;
+    right:5%;
+}
+</style>
+<style>
+.demo-tabs .el-tabs__item.is-active{
+    color: #333333;
+    font-weight: bold;
+    font-size: 17px;
+}
+.demo-tabs .el-tabs__item.is-active{
+    border-bottom-color: #fff !important;
+    border-bottom-width: 3px;
+    background-color: #ffffffad;
+}
 </style>

+ 103 - 68
TEAMModelBI/ClientApp/src/view/userInquire/iot.vue

@@ -40,14 +40,14 @@
                 <div class="item-num">{{item.value}}</div>
                 <span class="item-title">{{item.name}}</span>
               </div>
-            </div>
+            </div> -->
             <div class="power-box">
-              <p class="apparatus-title">课堂与授权</p>
+              <p class="inuse-title">课堂与授权</p>
               <div class="power-item" v-for="(item,index) in powerList.class" :key="index">
                 <div class="item-num">{{item.value}}</div>
                 <span class="item-title">{{item.name}}</span>
               </div>
-            </div> -->
+            </div>
           </div>
           <div class="minxinbox">
             <div class="lessons-box">
@@ -123,10 +123,12 @@
   import { ref, getCurrentInstance, defineEmits, computed, onMounted, watch } from 'vue'
   import Xlines from '@/components/echarts/Xline.vue'
   import * as echarts from 'echarts'
+  import { useStore } from 'vuex'
   let props = defineProps({
     detailsData: Object,
   })
   console.log(props.detailsData, '子组件')
+  const store = useStore()
   let value1 = ref('')
   let value = ref()
   let $myemit = defineEmits(['myback'])
@@ -456,6 +458,7 @@
     { title: '学生参与总时数', icon: '#icon-_shijian_xiaoshuai', value: '8小时', key: 'participationnum' },
     { title: '课堂总数', icon: '#icon-ketang', value: '45', key: 'classnum' },
     { title: '课堂总时数', icon: '#icon--shijian ', value: '648', key: 'classtime' },
+    { title: 'HiTeach版本', icon: '#icon-banbenhao ', value: '0', key: 'hiteachVersions' },
   ])
   let powerList = ref({
     facility: [
@@ -464,9 +467,10 @@
       { name: '授权设备', value: 0, }
     ],
     class: [
+      {name:'装置数量',value:0},
       { name: '928授权', value: 0 },
       { name: 'ID授权', value: 0 },
-      { name: '设备授权', value: 0 },
+      { name: '装置授权', value: 0 },
       { name: '综合授权', value: 0 },
     ]
   })
@@ -488,23 +492,30 @@
     { icon: '#icon--caozuorizhi', title: 'IES课程', content: '使用IES课程', state: true, value: 0 },
     { icon: '#icon--caozuorizhi', title: 'webIrs', content: '使用webIrs', state: true, value: 0 },
     { icon: '#icon--caozuorizhi', title: 'IRS', content: '使用IRS', state: true, value: 0 },
-    { icon: '#icon--caozuorizhi', title: 'HiTA', content: '使用HiTA', state: false, value: 0 },
-    { icon: '#icon--caozuorizhi', title: 'HaBoard', content: '使用HaBoard', state: false, value: 0 },
-    { icon: '#icon--caozuorizhi', title: 'IES5资源', content: '使用IES5资源', state: true, value: 0 },
-    { icon: '#icon--caozuorizhi', title: 'T指数', content: '课程T绿灯数', state: true, value: 0 },
+    { icon: '#icon--caozuorizhi', title: 'HiTA', content: '使用HiTA', state: true, value: 0 },
+    { icon: '#icon--caozuorizhi', title: 'HaBoard', content: '使用HaBoard', state: true, value: 0 },
+    { icon: '#icon--caozuorizhi', title: 'HaBoard', content: '使用IES5资源', state: true, value: 0 },
+    { icon: '#icon--caozuorizhi', title: 'text', content: '使用文字云', state: false, value: 0 },
+    { icon: '#icon--caozuorizhi', title: 'ClouDAS', content: '使用ClouDAS', state: false, value: 0 },
+    { icon: '#icon--caozuorizhi', title: 'GPT', content: '使用GPT', state: false, value: 0 },
+    { icon: '#icon--caozuorizhi', title: 'IES5测验', content: '使用IES5卷测验', state: true, value: 0 },
+    { icon: '#icon--caozuorizhi', title: 'Excel测验', content: '使用Excel卷测验', state: true, value: 0 },
+    { icon: '#icon--caozuorizhi', title: '纸本测验', content: '使用纸本测验', state: true, value: 0 },
+    { icon: '#icon--caozuorizhi', title: 'T课堂', content: '符合T课堂数', state: true, value: 0 },
   ])
   let inuseList = ref([
-    { title: '任务数', value: 15, icon: '#icon-renwu', percent: '41.2%', class: 'task', textClass: 'task-text' },
-    { title: '作品数', value: 10, icon: '#icon-yiwancheng-', percent: '30%', class: 'accomplish', textClass: 'accomplish-text' },
-    { title: '题目数', value: 22, icon: '#icon-ic_mianxing_jiakaotimu_1', percent: '10%', class: 'topic', textClass: 'topic-text' },
-    { title: '互动次数', value: 58, icon: '#icon-hudongshequ', percent: '5%', class: 'interaction', textClass: 'interaction-text' },
+    { title: '学习任务数', value: 15, icon: '#icon-renwu', percent: '41.2%', class: 'task', textClass: 'task-text' },
+    { title: '学习作品数', value: 10, icon: '#icon-yiwancheng-', percent: '30%', class: 'accomplish', textClass: 'accomplish-text' },
+    { title: '测验题目数', value: 22, icon: '#icon-ic_mianxing_jiakaotimu_1', percent: '10%', class: 'topic', textClass: 'topic-text' },
+    { title: '学生互动次数', value: 58, icon: '#icon-hudongshequ', percent: '5%', class: 'interaction', textClass: 'interaction-text' },
   ])
   let classType = ref([
     { name: '合作型态课堂', value: 20, percent: '41.2%', class: 'task', textClass: 'task-text' },
     { name: '互动型态课堂', value: 20, percent: '30%', class: 'accomplish', textClass: 'accomplish-text' },
     { name: '任务型态课堂', value: 20, percent: '10%', class: 'topic', textClass: 'topic-text' },
     { name: '差异化形态课堂', value: 20, percent: '5%', class: 'interaction', textClass: 'interaction-text' },
-    { name: '测验型态课堂', value: 30, percent: '15%', class: 'testclass', textClass: 'testclass-text' },
+    { name: '协作型态课堂', value: 30, percent: '15%', class: 'testclass', textClass: 'testclass-text' },
+    { name: '互评型态课堂', value: 30, percent: '15%', class: 'testclass', textClass: 'testclass-text' },
     { name: '无型态课堂', value: 0, percent: '0%', class: 'noneclass', textClass: 'noneclassclass-text' },
     { name: '未上课', value: 0, percent: '0%', class: 'noneclass', textClass: 'noneclassclass-text' },
   ])
@@ -557,7 +568,7 @@
           }
         },
         boundaryGap: true, // 坐标轴两边是否留白
-        data: ['合作型态', '互动型态', '任务型态', '差异化型态', '测验型态', '无型态', '未上课']
+        data: ['合作', '互动', '任务', '差异化', '协作','互评', '无型态', '未上课']
       },
       yAxis: [
         {
@@ -616,7 +627,7 @@
               }
             }
           },
-          barMaxWidth: '20%',
+          barMaxWidth: '15%',
         }
       ]
     }
@@ -631,7 +642,8 @@
     // props.pattern.state ==='school' ? appearState.value='default': props.pattern.state ==='area' ? appearState.value='area':appearState.value='default'
     
     let propsbox=transfervalue? transfervalue:props
-    console.log(propsbox, '数据')
+    
+    console.log(propsbox,props,'数据1234')
     //学校基础信息
     // let { name, region, province, city, dist } = propsbox.detailsData.school
     // schoolData.value.name = appearState.value ==='default' ? name: appearState.value ==='area' ? propsbox.detailsData.name:''
@@ -654,27 +666,39 @@
     basicaList.value[1].value = stuLessonLengMin
     basicaList.value[2].value = lessonRecord
     basicaList.value[3].value = lessonLengMin
-  
+    let versionvalue=store.state.hiteachVs ? store.state.hiteachVs : '无'
+    basicaList.value[4].value =versionvalue
+   console.log(store,'vuex内容')
     //处理课中使用数据
-    let { useIES, useWebIrs, useDeviceIrs, useHita, useHaboard, useIES5Resource, tGreen } = propsbox.detailsData
-    lessonsList.value[0].value = useIES
-    lessonsList.value[1].value = useWebIrs
-    lessonsList.value[2].value = useDeviceIrs
-    lessonsList.value[3].value = useHita
-    lessonsList.value[4].value = useHaboard
-    lessonsList.value[5].value = useIES5Resource
-    lessonsList.value[6].value = tGreen
+    let { useIES, useWebIrs, useDeviceIrs, useHita, useHaboard, useIES5Resource, tGreen,useWordCloud,useClouDAS,useGPT,useIesTest,useExcelTest,usePaperTest,tLesson} = propsbox.detailsData
+    lessonsList.value[0].value = useIES ?useIES:0
+    lessonsList.value[1].value = useWebIrs ? useWebIrs:0
+    lessonsList.value[2].value = useDeviceIrs ? useDeviceIrs:0
+    lessonsList.value[3].value = useHita ? useHita:0
+    lessonsList.value[4].value = useHaboard ?  useHaboard:0
+    lessonsList.value[5].value =useIES5Resource ? useIES5Resource:0
+    //由hita 调整为 文字云
+    lessonsList.value[6].value = useWordCloud ?useWordCloud:0
+    //由HaBoard 调整为 ClouDAS
+    lessonsList.value[7].value = useClouDAS ? useClouDAS:0
+    //增加使用GPT
+    lessonsList.value[8].value = useGPT ?useGPT:0
+    //由IES5资源调整为 使用IES5卷测验
+    lessonsList.value[9].value = useIesTest ? useIesTest:0
+    //新增Excel
+    lessonsList.value[10].value=useExcelTest ? useExcelTest:0
+    //新增纸本
+    lessonsList.value[11].value=usePaperTest ?usePaperTest:0
+    //符合T课堂数
+    lessonsList.value[12].value=tLesson ? tLesson:0
   
-    //授权占比
-    // let { deviceCnt, deviceNoAuth, deviceAuth, lessonCnt928, lessonCntId, lessonCntDevice, lessonCntIdDevice } = propsbox.detailsData
-    // powerList.value.facility[0].value = deviceCnt
-    // // basicaList.value[2].value = deviceCnt
-    // powerList.value.facility[1].value = deviceNoAuth
-    // powerList.value.facility[2].value = deviceAuth
-    // powerList.value.class[0].value = lessonCnt928
-    // powerList.value.class[1].value = lessonCntId
-    // powerList.value.class[2].value = lessonCntDevice
-    // powerList.value.class[3].value = lessonCntIdDevice
+    //授权内容
+    let {lessonCnt928,lessonCntId, lessonCntDevice, lessonCntIdDevice,deviceCnt } = propsbox.detailsData
+    powerList.value.class[0].value = deviceCnt
+    powerList.value.class[1].value = lessonCnt928
+    powerList.value.class[2].value = lessonCntId
+    powerList.value.class[3].value = lessonCntDevice
+    powerList.value.class[4].value = lessonCntIdDevice
     //处理任务数、作品完成、题目等。。。。
     let { mission, missionFin, item, interact } = propsbox.detailsData
     inuseList.value[0].value = mission
@@ -683,25 +707,23 @@
     inuseList.value[3].value = interact
   
     //处理多形态课堂
-    let { lTypeCoop, lTypeIact, lTypeMis, lTypeTst, lTypeDif, lTypeNone,lessonLeng0} = propsbox.detailsData
+    let { lTypeCoop, lTypeIact, lTypeMis, lTypeTst, lTypeDif, lTypeNone,lessonLeng0,learnCoop,learnPeer} = propsbox.detailsData
     let totalNum = [lTypeCoop, lTypeIact, lTypeMis, lTypeTst, lTypeDif].reduce((prev, cur) => { return prev + cur }, 0)
     echartData.value.total = totalNum
     console.log(totalNum)
     classType.value[0].value = lTypeCoop
-    classType.value[0].percent = lTypeCoop === 0 ? 0 : (lTypeCoop / totalNum).toFixed(2) * 100
     classType.value[1].value = lTypeIact
-    classType.value[1].percent = lTypeIact === 0 ? 0 : (lTypeIact / totalNum).toFixed(2) * 100
     classType.value[2].value = lTypeMis
-    classType.value[2].percent = lTypeMis === 0 ? 0 : (lTypeMis / totalNum).toFixed(2) * 100
-    classType.value[3].value = lTypeTst
-    classType.value[3].percent = lTypeTst === 0 ? 0 : (lTypeTst / totalNum).toFixed(2) * 100
-    classType.value[4].value = lTypeDif
-    classType.value[4].percent = lTypeDif === 0 ? 0 : (lTypeDif / totalNum).toFixed(2) * 100
-    classType.value[4].value = lTypeNone
-    classType.value[5].value = lessonLeng0 ? lessonLeng0:0
-  
+    classType.value[3].value = lTypeDif
+    //由测试改为 协作
+    classType.value[4].value = learnCoop
+    //新增互评
+    classType.value[5].value = learnPeer
+    classType.value[6].value = lTypeNone
+    classType.value[7].value = lessonLeng0 ? lessonLeng0:0
+      
     //echarts占比
-    echartData.value.xlines.series[0].data = [lTypeCoop, lTypeIact, lTypeMis, lTypeTst, lTypeDif, lTypeNone, classType.value[5].value]
+    echartData.value.xlines.series[0].data = [lTypeCoop, lTypeIact, lTypeMis, lTypeDif,learnCoop,learnPeer, lTypeNone,lessonLeng0]
     // echartData.value.xlines.series[1].data = [classType.value[1].percent]
     // echartData.value.xlines.series[2].data = [classType.value[2].percent]
     // echartData.value.xlines.series[3].data = [classType.value[3].percent]
@@ -717,13 +739,19 @@
   function backbtn () {
     $myemit('myback', 'default')
   }
+onMounted(() => {
   init()
-  watch(() => props.detailsData, (newValue) => {
+})
+  watch(() => props, (newValue) => {
+    console.log()
     //   propValue.value = newValue;
-    let datas={detailsData:newValue}
+    let datas={detailsData:newValue.detailsData}
     init(datas)
-    console.log(datas,'有数据进来')
-  });
+  },{deep:true});
+  watch(()=>props,(newdata)=>{
+    console.log(newdata,'9999999999999999')
+  })
+
   </script>
   <style  scoped>
   .details-analysis {
@@ -762,7 +790,7 @@
     padding-top: 1%;
   }
   .contentbox {
-    width: 98%;
+    width: 100%;
     /* padding: 1% 1%; */
     /* background: rgb(250, 250, 250); */
     /* height: 85vh; */
@@ -789,6 +817,7 @@
     display: flex;
     flex-wrap: nowrap;
     justify-content: space-between;
+    line-height: 40px;
   }
   .apparatusAndpower {
     width: 100%;
@@ -799,14 +828,14 @@
   }
   .apparatus-box,
   .power-box {
-    width: 32%;
+    width: 50%;
     box-shadow: 0 2px 5px #e9e9e9;
     background: #fff;
     margin: 0.5%;
     border-radius: 5px;
     display: flex;
-    justify-content: space-between;
-    /* align-items: center; */
+    justify-content: space-around;
+    align-items: center;
     flex-wrap: wrap;
   }
   .apparatus-item {
@@ -818,22 +847,23 @@
     margin: 1%;
   }
   .power-item {
-    width: 23%;
-    margin: 0% 1%;
+    width: 18%;
+    height:80px;
     box-shadow: 0 2px 5px #e9e9e9;
     background: #fff;
     border-radius: 5px;
     margin: 1%;
+    line-height: 40px;
   }
   .apparatus-title {
-    font-size: 16px;
-    margin-bottom: 5px;
-    border-bottom: 1px dashed #e9e9e9;
-    line-height: 40px;
     width: 100%;
     background: #dfe6e9;
-    color: #fff;
+    margin-bottom: 5px;
+    line-height: 25px;
+    border-bottom: 1px dashed #e9e9e9;
+    font-size: 16px;
     font-weight: bold;
+    color: #fff;
   }
   .inuse-title {
     width: 100%;
@@ -851,7 +881,7 @@
   }
   .basicadata-item {
     display: flex;
-    width: 20%;
+    width: 18%;
     padding: 5px 5px;
     flex-direction: column;
     /* height: 60px; */
@@ -860,6 +890,7 @@
     box-shadow: 0 2px 5px #e9e9e9;
     background: #fff;
     margin: 0.5%;
+    align-items: center;
   }
   .item-title-images {
     width: 100%;
@@ -896,11 +927,11 @@
   }
   .lessons-box {
     width: 50%;
-    height: 36vh;
+    height: 36.3vh;
     border-radius: 5px;
     background: #fff;
     box-shadow: 0 2px 5px #e9e9e9;
-    margin: 0.5% 1%;
+    margin: 0.5%;
     overflow: hidden;
     overflow-y: auto;
   }
@@ -969,7 +1000,7 @@
     color: #007fff;
   }
   .inuse-left {
-    width: 100%;
+    width: 50%;
     box-shadow: 0 2px 5px #e9e9e9;
     background: #fff;
     margin: 0.5%;
@@ -979,13 +1010,14 @@
     align-items: center;
     flex-wrap: wrap;
   }
+
   .inuse-right {
     width: 49.5%;
     margin-left: 0%;
     border-radius: 5px;
     background: #fff;
     box-shadow: 0 2px 5px #e9e9e9;
-    margin: 0.5% 0%;
+    margin: 0.5%;
     /* margin-left: 1%; */
     position: relative;
   }
@@ -999,7 +1031,7 @@
     border-radius: 5px;
     /* box-shadow: 0 2px 5px #e9e9e9; */
     border: 1px solid #e9e9e9;
-    margin: 0.5%;
+    margin: 1%;
   }
   .inuseicon {
     width: 1.6em;
@@ -1219,6 +1251,9 @@
   .noneclassclass-text {
     color: #95a5a6 !important;
   }
+  .lessons-item:last-child{
+    margin-bottom: 1%;
+  }
   @media screen and (max-width: 1400px) {
     .basicadata-item {
       line-height: 30px !important;

+ 80 - 24
TEAMModelBI/ClientApp/src/view/userInquire/socrates.vue

@@ -30,10 +30,10 @@
         <!-- <div class="socrates-echatrs">
             <bars :barData="ecahrtsdata"></bars>
         </div> -->
-        <div class="tnum-content">
+        <div class="tnum-content"  v-if="sokratesEchart">
                 <div class="selectbox">
                     <div><el-button v-for="item in buttonSelect" :key="item.value" :type="item.click ? 'primary':''" size="small" class="clickbox" @click="selectTime(item.value)">{{item.name}}</el-button></div>
-                    <div class="nowaday-time">时间:<span>{{hiteachDatas.appear.start_date}}~{{hiteachDatas.appear.end_date}}</span></div>
+                    <div class="nowaday-time">时间:<span class="time-values">{{hiteachDatas.appear.start_date}}~{{hiteachDatas.appear.end_date}}</span></div>
                 </div>
                 <div class="contentbox">
                     <!-- <div class="nowaday-time">时间:2023/07/05-2023/07/11</div> -->
@@ -52,7 +52,7 @@
                         <div class="restbox-item" >
                             <div class="restbox-left" v-for="item in tdatas" :key="item.key">
                                 <div class="left-content">{{item.title}}:
-                                    <span>{{item.values}}</span><span v-show="item.key ==='times' ||item.key ==='studentime'" class="time-unit">Min</span>
+                                    <span class="content-num">{{item.values}}</span><span v-show="item.key ==='times' ||item.key ==='studentime'" class="time-unit">Min</span>
                                 </div>
                             </div>
                             <!-- <div class="restbox-right">
@@ -61,7 +61,10 @@
                         </div>
                     </div>
                 </div>
-            </div>
+        </div>
+        <div class="tnum-content" v-else>
+            <div class="not-coupons">暂无数据</div>
+        </div>
     </div>
  </template>
  <script setup>
@@ -265,7 +268,8 @@ let hiteachDatas=ref({
 let buttonSelect = ref([
     { name: '周', value: 'week', click: true },
     { name: '月', value: 'month', click: false },
-    {name:'年',value:'year',click:false}
+    {name:'年',value:'year',click:false},
+    {name:'全部',value:'total',click:false}
 ])
 let proportiondata = ref({
     legend: {
@@ -287,7 +291,7 @@ let proportiondata = ref({
             },
         }, 
         {
-        text: '16%',
+        text: '0%',
         left: '50%',
         top: '30%',
         textAlign: 'center',
@@ -305,7 +309,8 @@ let proportiondata = ref({
             startAngle: 0,
             radius: ['80%', '60%'],
             center: ['50%', '40%'],
-            data: [{
+            data: [
+                {
                     hoverOffset: 1,
                     value: 75,
                     name: '',
@@ -359,6 +364,7 @@ let proportiondata = ref({
         },
     ]
 })
+let sokratesEchart=ref(true)
 let zb = ref()
 onMounted(() => {
     initdatas()
@@ -375,32 +381,42 @@ function initdatas(){
         presupposed.value.data.general_observation=user_channels.general_observation,
         presupposed.value.state=true)
         :presupposed.value.state=false
+    }else{
+        presupposed.value.state=false
     }
     //处理total数据
-    primary.value[0].value=hiteach_data.total.t_data ? hiteach_data.total.t_data:0
-    primary.value[1].value=hiteach_data.total.t_green ? hiteach_data.total.t_green:0
-    primary.value[2].value=hiteach_data.total.double_green_light ? hiteach_data.total.double_green_light:0
-    // primary.value[3].value=hiteach_data.total.
+    primary.value[0].value=hiteach_data && hiteach_data.total.t_data ? hiteach_data.total.t_data:0
+    primary.value[1].value=hiteach_data && hiteach_data.total.t_green ? hiteach_data.total.t_green:0
+    primary.value[2].value=hiteach_data && hiteach_data.total.double_green_light ? hiteach_data.total.double_green_light:0
+    primary.value[3].value=hiteach_data && hiteach_data.total.all_total ?  hiteach_data.total.all_total:0
 
-    auxiliary.value[0].value='XXX'
-    auxiliary.value[1].value='XXX'
-    auxiliary.value[2].value='XXX'
-    auxiliary.value[3].value='XXX'
+    auxiliary.value[0].value=hiteach_data ?.total ?.public_count
+    auxiliary.value[1].value=hiteach_data&& hiteach_data.total.personal_comment ? hiteach_data.total.personal_comment:0
+    auxiliary.value[2].value=hiteach_data && hiteach_data.total.watchHistory ?  hiteach_data.total.watchHistory:0
+    auxiliary.value[3].value=hiteach_data ?.total ?.material_count
+    if(!hiteach_data){
+        sokratesEchart.value=false
+    }
     //处理下方图表
-    hiteachDatas.value.weeks=hiteach_data.this_week
-    hiteachDatas.value.months=hiteach_data.this_month
-    hiteachDatas.value.years=hiteach_data.this_year
-    hiteachDatas.value.appear=hiteach_data.this_week
+    hiteachDatas.value.weeks=hiteach_data && hiteach_data.this_week ? hiteach_data.this_week:0
+    hiteachDatas.value.months= hiteach_data && hiteach_data.this_month ?hiteach_data.this_month:0
+    hiteachDatas.value.years= hiteach_data && hiteach_data.this_year ?hiteach_data.this_year:0
+    hiteachDatas.value.appear=hiteach_data && hiteach_data.this_week ?hiteach_data.this_week:0
     tdatas.value[0].values=hiteachDatas.value.appear.duration
     tdatas.value[1].values=hiteachDatas.value.appear.attendance
     tdatas.value[2].values=hiteachDatas.value.appear.interaction
     tdatas.value[3].values=hiteachDatas.value.appear.learning_duration
+    selectTime('week')
 }
 function selectTime(values) {
     console.log(values)
+    if(!props.sokratesdatas.hiteach_data){
+        sokratesEchart.value=false
+        return
+    }
     let hiteach_data=props.sokratesdatas.hiteach_data
     values === 'week' ?  hiteachDatas.value.appear=hiteach_data.this_week:values === 'month' ? hiteachDatas.value.appear=hiteach_data.this_month:
-    values === 'year' ? hiteachDatas.value.appear=hiteach_data.this_year:''
+    values === 'year' ? hiteachDatas.value.appear=hiteach_data.this_year:values ==='total' ? hiteachDatas.value.appear=hiteach_data.total:''
     tdatas.value[0].values=hiteachDatas.value.appear.duration
     tdatas.value[1].values=hiteachDatas.value.appear.attendance
     tdatas.value[2].values=hiteachDatas.value.appear.interaction
@@ -408,8 +424,35 @@ function selectTime(values) {
     buttonSelect.value.forEach(element => {
         element.value === values ? element.click=true: element.click=false
     });
-
+    if(values ==='week'){
+        console.log(hiteach_data.this_week.t_green,hiteach_data.this_month.t_green)
+        proportiondata.value.title[0].text='占同月T绿灯比例'
+        proportiondata.value.title[1].text= hiteach_data.this_week.t_green !=0 ? Math.round((hiteach_data.this_week.t_green/hiteach_data.this_month.t_green).toFixed(2)*100)+'%':0+'%'
+        proportiondata.value.series[0].data[0].value=Math.round((hiteach_data.this_week.t_green/hiteach_data.this_month.t_green).toFixed(2)*100)
+        proportiondata.value.series[0].data[1].value=100-(Math.round((hiteach_data.this_week.t_green/hiteach_data.this_month.t_green).toFixed(2)*100))
+    }else if(values ==='month'){
+        console.log(hiteach_data.this_month.t_green,hiteach_data.this_year.t_green)
+        proportiondata.value.title[0].text='占同年T绿灯比例'
+        proportiondata.value.title[1].text=hiteach_data.this_month.t_green !=0 ? Math.round((hiteach_data.this_month.t_green/hiteach_data.this_year.t_green).toFixed(2)*100)+'%':0+'%'
+        proportiondata.value.series[0].data[0].value=Math.round((hiteach_data.this_month.t_green/hiteach_data.this_year.t_green).toFixed(2)*100)
+        proportiondata.value.series[0].data[1].value=100-(Math.round((hiteach_data.this_month.t_green/hiteach_data.this_year.t_green).toFixed(2)*100))
+    }else if(values ==='year'){
+        console.log(hiteach_data.this_year.t_green,hiteach_data.total.t_green)
+        proportiondata.value.title[0].text='占全部T绿灯比例'
+        proportiondata.value.title[1].text=hiteach_data.this_year.t_green && hiteach_data.total.t_green ? Math.round((hiteach_data.this_year.t_green/hiteach_data.total.t_green).toFixed(2)*100)+'%':0+'%'
+        proportiondata.value.series[0].data[0].value=Math.round((hiteach_data.this_year.t_green/hiteach_data.total.t_green).toFixed(2)*100)
+        proportiondata.value.series[0].data[1].value=100-(Math.round((hiteach_data.this_year.t_green/hiteach_data.total.t_green).toFixed(2)*100))
+    }else if(values ==='total'){
+        proportiondata.value.title[0].text='占全部T绿灯比例'
+        proportiondata.value.title[1].text='100%'
+        proportiondata.value.series[0].data[0].value=100
+        proportiondata.value.series[0].data[1].value=100-100
+    }
 }
+watch(()=>props,(newvalue)=>{
+    console.log(newvalue,'有新值进入苏格拉底')
+    newvalue.sokratesdatas ? (initdatas(),zb.value = proportiondata.value):''
+},{deep:true})
  </script>
  <style scoped>
  .socrates-header,.socrates-auxiliary{
@@ -472,7 +515,7 @@ function selectTime(values) {
 }
 .nowaday-time{
     font-size:14px;
-    color:#bbbecd;
+    color:#303133;
     text-align: left;
 }
 .nowaday{
@@ -523,11 +566,11 @@ function selectTime(values) {
 }
 .left-content{
     font-size:14px;
-    color:#bbbecd;
+    color:#303133;
 }
 .left-content span{
     font-size:16px;
-    color: #8a90a8;
+    color: #909399;
     font-weight: bold;
 }
 .hiteachbox-content{
@@ -536,4 +579,17 @@ function selectTime(values) {
 .time-unit{
     margin:0px 5px;
 }
+.time-values,.content-num{
+    color:#409EFF !important;
+}
+.not-coupons{
+    display: flex;
+    height:90%;
+    align-items: center;
+    justify-content: center;
+    font-size:22px;
+    font-weight: 700;
+    color: #73767a;
+    /* line-height: 160px; */
+}
 </style>

+ 7 - 2
TEAMModelBI/ClientApp/src/view/userInquire/ticket.vue

@@ -142,6 +142,10 @@ let gaindata = computed(() => {
  onMounted(() => {
     inidatas()
 })
+watch(()=>props,(newdata)=>{
+    console.log(newdata,'有新值进入票卷')
+    newdata.pointsandcoupons ? (ticketlist.value=[],inidatas()):''
+},{deep:true})
 </script>
 <style scoped>
 .ticket-header{
@@ -285,9 +289,10 @@ let gaindata = computed(() => {
     padding-top:25px;
 }
 .not-coupons{
-    font-size:16px;
+    font-size:18px;
     color: #73767a;
-    line-height: 120px;
+    line-height: 160px;
+    font-weight: 700;
 }
 /* .usebox{
     color:rgba(255,255,255,.9) !important;

+ 304 - 0
TEAMModelBI/ClientApp/src/view/userInquire/updCodeW.vue

@@ -0,0 +1,304 @@
+<template>
+    <div class="updCodeWBox" v-loading="loading" :element-loading-text="loadingStr">
+        <!-- <div class="updCodeWBox-title">
+            <p>弱歸戶</p>
+        </div>
+        <el-divider border-style="dashed" /> -->
+        <div style="line-height: 1px;height: 100%;overflow: auto;">
+            <div style="margin-bottom: 10px;">
+                <h3>區域</h3>
+                <el-radio-group class="radioSty" v-model="countryId" @change="cIdChange">
+                    <el-radio label="CN" size="large"  border>大陆地区</el-radio>
+                    <el-radio label="TW" size="large" border>臺灣地區</el-radio>
+                </el-radio-group>
+            </div>
+            
+            <div style="margin-bottom: 10px;" v-if="provinceIdData != null">
+                <h3>省/直轄市</h3>
+                <el-radio-group class="radioSty" v-model="provinceId" @change="pIdChange">
+                    <el-radio size="large" :label="p.provinceId"  border v-for="p in provinceIdData">{{ p.provinceName }}</el-radio>
+                </el-radio-group>
+            </div>
+
+            <div style="margin-bottom: 10px;" v-if="cityIdData != null">
+                <h3>市/界</h3>
+                <el-radio-group class="radioSty" v-model="cityId">
+                    <el-radio size="large" :label="c.cityId"  border v-for="c in cityIdData" @click="searchSchool(c.cityId)">{{ c.cityName }}</el-radio>
+                </el-radio-group>
+            </div>
+
+            <div style="margin-bottom: 10px;margin-top: 70px;">
+                <div style="display: flex;justify-content: center;align-items: center;">
+                    <span style="font-weight: bold;font-size: 23px;margin-right: 5px;">搜尋</span>
+                    <el-input v-model="wordFilter" placeholder="請填入簡碼或學校名稱" style="width: 500px;"/>
+                </div>
+                <el-table :data="showData" stripe style="width: 100%" >
+                    <el-table-column prop="code" label="代碼"  />
+                    <el-table-column prop="shortCode" label="簡碼"  />
+                    <el-table-column prop="name" label="學校名稱"  />
+                    <el-table-column label="">
+                        <template #default="scope">
+                            <el-button type="primary" size="small" @click="handleUpdSchoolW(scope.row.id, scope.row.name, scope.row.shortCode)">歸戶</el-button>
+                        </template>
+                    </el-table-column>
+                </el-table>
+            </div>
+        </div>
+    </div>
+</template>
+<script setup>
+import country from '@/static/country.json'
+import { h, reactive, ref, computed, getCurrentInstance, markRaw } from 'vue'
+import { SuccessFilled, Warning } from '@element-plus/icons'
+import { ElMessageBox, ElMessage, ElInput, ElForm, ElFormItem } from 'element-plus'
+let { proxy } = getCurrentInstance()
+
+const loading = ref(false)
+const countryId = ref(null)
+const provinceId = ref(null)
+const provinceIdData = ref(null)
+const cityId = ref(null)
+const cityIdData = ref(null)
+const tableData = ref([])
+const wordFilter = ref('')
+const loadingStr = ref('')
+
+const cIdChange = (cId) => {
+    cityId.value = null
+    provinceId.value = null
+    provinceIdData.value = null
+    cityIdData.value = null
+    switch(cId){
+        case 'TW':
+            cityIdData.value = country.filter(function(c){
+                return c.countryId == cId && c.lang == 'zh-tw' && c.areaType == 'y'
+            })
+        break;
+        case 'CN':
+            provinceIdData.value = country.filter(function(c){
+                return c.countryId == cId && c.lang == 'zh-cn' && c.areaType == 'p'
+            })
+        break;
+    }
+}
+
+const pIdChange = (provinceId) =>{
+    cityId.value = null
+    cityIdData.value = null
+    let lang = ''
+    switch(countryId.value){
+        case 'TW':
+            lang = 'zh-tw'
+        break;
+        case 'CN':
+            lang = 'zh-cn'
+        break;
+    }
+
+    cityIdData.value = country.filter(function(c){
+        return c.provinceId == provinceId && c.lang == lang && c.areaType == 'y'
+    })
+}
+
+const searchSchool = async (cityId) =>{
+    let data = {
+        countryId: countryId.value,
+        cityId: cityId,
+        fullData: true
+    }
+
+    if(provinceId.value != null) {
+        data.provinceId = provinceId.value
+    }
+    wordFilter.value = ''
+    loadingStr.value = '搜索學校中...'
+    loading.value = true
+
+    await proxy.$api.getSchooBasicInfo(data).then((res) => {
+        tableData.value = res
+    }).catch(e=>{
+        ElMessage.error('搜尋失敗')
+    }).finally(() => {
+        loading.value = false
+    })
+}
+
+const showData = computed({
+    get(){
+        if(wordFilter.value != ''){
+            let result = []
+            console.log(wordFilter.value, 'wordFilter.value')
+            tableData.value.forEach((f)=>{
+                if(f.name.indexOf(wordFilter.value) >= 0){
+                    result.push(f)
+                } else if(f.shortCode && f.shortCode.indexOf(wordFilter.value) >= 0){
+                    result.push(f)
+                }
+            })
+            return result
+        } else {
+            return tableData.value
+        }
+    }
+})
+
+const handleUpdSchoolW = async (schDocId, schName, shortCode) =>{
+    const iDsCount = ref(0)
+    // 檢查array 內容是否重複
+    function isArrayRep(array){
+        var result = new Set();
+        var repeat = new Set();
+        array.forEach(item => {
+            result.has(item) ? repeat.add(item) : result.add(item);
+        })
+        // console.log(result); // {1, 2, "a", 3, "b"}
+        // console.log(repeat); // {1, "a"}
+        // console.log(repeat.size)
+        if(repeat.size != 0){
+            return true
+        } else {
+            return false
+        }
+    }
+    // 規則檢查: iDs
+    const checkIds = (value) => {
+        let isErr = false
+        if(!value) {
+            isErr = true
+            return "請填入要歸戶的醍摩豆ID"
+        } else if(value && !/^[0-9\n]+$/.test(value)){
+            isErr = true
+            return "只能輸入醍摩豆ID與換行"
+        } else if(value && isArrayRep(value.split('\n'))){
+            isErr = true
+            return "醍摩豆ID有重複"
+        } else if(value){
+            let errIds = []
+            let tmp = value.split('\n')
+            tmp.forEach(e=> {
+                if(e.length != 10) {
+                    errIds.push(e)
+                } else {
+                    let now = Math.floor(new Date().getTime() / 1000)
+                    let orgId = parseInt(e)
+                    if(parseInt(e.substring(0, 1)) >= 6){
+                        orgId -= 5000000000
+                    }
+
+                    if(orgId > now){
+                        errIds.push(e)
+                    }
+                }
+            })
+
+            if(errIds.length > 0){
+                // console.log(errIds, 'errIds')
+                isErr = true
+                return "請檢查醍摩豆ID是否符合格式或有空格"
+            }
+        }
+
+        if(!isErr && value != ''){
+            let tArray = value.split('\n')
+            iDsCount.value = tArray.length
+        } else {
+            iDsCount.value = 0
+        }
+
+        return true
+    }
+
+    if(!shortCode){
+        ElMessageBox.alert('此學校目前沒有簡碼', `***${schName}***`,
+            {
+                type: 'warning',
+                icon: markRaw(Warning),
+            }
+        )
+        // 中斷
+        return 
+    }
+
+    ElMessageBox.prompt(
+        '請填入要歸戶的醍摩豆ID', `歸戶至 ${schName} - ${shortCode}`, {
+            confirmButtonText: '歸戶',
+            cancelButtonText: '取消',
+            inputType: 'textarea',
+            inputValidator: checkIds,
+            customClass: 'prompClass',
+            roundButton: true,
+            closeOnClickModal: false
+        }
+    ).then(({value})=>{
+        let showStr = value.replaceAll('\n', ', ')
+        ElMessageBox.confirm(
+            `確認要歸戶以下的醍摩豆ID嗎?\n${showStr} \n\n 總共 ${iDsCount.value} 位`,
+            `歸戶至 ${schName}  - ${shortCode}`,
+            {
+                confirmButtonText: '確認',
+                cancelButtonText: '先不要',
+                type: 'info',
+                customClass: 'confirmClass'
+            }
+        ).then(async ()=>{
+            let reqData = {
+                schoolDocId: schDocId,
+                ids: value.split('\n')
+            }
+            
+            loadingStr.value = '弱歸戶...'
+            loading.value = true
+
+            await proxy.$api.updUserSchoolW(reqData).then((res) => {
+                ElMessageBox.alert('成功', '弱歸戶成功',
+                    {
+                        type: 'info',
+                        icon: markRaw(SuccessFilled),
+                    }
+                )
+            }).catch(e=>{
+                ElMessage.error('搜尋失敗')
+            }).finally(() => {
+                loading.value = false
+            })
+        })
+    })
+}
+</script>
+<style>
+.prompClass textarea{
+    min-height: 220px!important;
+}
+.confirmClass p{
+    white-space: pre-line;
+}
+.radioSty .el-radio__input{
+    display: none;
+}
+.radioSty .el-radio__label{
+    font-weight: bold;
+    font-size: 15px!important;
+}
+.radioSty .el-radio{
+    margin-right: 10px;
+}
+</style>
+<style scoped>
+.updCodeWBox{
+    width: 100%;
+    height: 82vh;
+    background-color: #fff;
+    z-index:999;
+    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3);
+    border-radius: 10px;
+    padding: 1%;
+    text-align: left;
+}
+.updCodeWBox-title{
+    line-height: 40px;
+    font-size:24px;
+    font-weight: bold;
+    color:#7b84a9;
+    text-align: center;
+}
+</style>

+ 67 - 15
TEAMModelBI/ClientApp/src/view/userInquire/userdetail.vue

@@ -10,23 +10,26 @@
                                 <use :xlink:href="[item.state ? item.icon+'1':item.icon]"></use>
                             </svg>
                         </div>
+                        <div class="third-party-item" title="教育云">
+                            <img :src="specialBind" class="third-party-itemicon">
+                        </div>
                      </div>
                 </el-form-item>
                 <el-form-item label="用户积分">
                     <div class="user-from-integral">
-                        <span>58</span><span>/</span><span>78</span>
+                        <span>{{integralAndticket.integral.used}}</span><span>/</span><span>{{integralAndticket.integral.total}}</span>
                     </div>
                 </el-form-item>
                 <el-form-item label="用户票卷">
                     <div class="user-from-integral">
-                        <span>8</span><span>/</span><span>8</span>
+                        <span>{{integralAndticket.ticket.used}}</span><span>/</span><span>{{integralAndticket.ticket.total}}</span>
                     </div>
                 </el-form-item>
-                <el-form-item label="注册时间">
+                <!-- <el-form-item label="注册时间">
                     <div class="user-from-integral">
                         <span>2019-05-28</span>
                     </div>
-                </el-form-item>
+                </el-form-item> -->
                 <el-form-item label="账户语系">
                     <div class="user-from-integral">
                         <div v-show="!userdata.countrystate">
@@ -43,9 +46,9 @@
                               />
                             </el-select>
                         </div>
-                        <div class="redacticon">
+                        <!-- <div class="redacticon">
                             <el-icon size="20" @click="userdata.countrystate=true"><EditPen /></el-icon>
-                        </div>
+                        </div> -->
                     </div>
                 </el-form-item>
                 <el-form-item label="单位名称">
@@ -56,9 +59,9 @@
                         <div v-show="userdata.companystate">
                             <el-input v-model="userdata.company"  placeholder="公司/单位 名称" />
                         </div>
-                        <div class="redacticon">
+                        <!-- <div class="redacticon">
                             <el-icon size="20" @click="userdata.companystate=true"><EditPen /></el-icon>
-                        </div>
+                        </div> -->
                     </div>
                 </el-form-item>
                 <el-form-item label="单位类别">
@@ -76,9 +79,9 @@
                                 />
                             </el-select>
                         </div>
-                        <div class="redacticon">
+                        <!-- <div class="redacticon">
                             <el-icon size="20" @click="userdata.typestate=true"><EditPen /></el-icon>
-                        </div>
+                        </div> -->
                     </div>
                 </el-form-item>
                 <el-form-item label="职称">
@@ -89,9 +92,9 @@
                         <div v-show="userdata.professionalstate">
                             <el-input v-model="userdata.professional"  placeholder="职称" />
                         </div>
-                        <div class="redacticon">
+                        <!-- <div class="redacticon">
                             <el-icon size="20" @click="userdata.professionalstate=true"><EditPen /></el-icon>
-                        </div>
+                        </div> -->
                     </div>
                 </el-form-item>
                 <el-form-item class="submitbtn" v-show="userdata.countrystate || userdata.companystate || userdata.typestate || userdata.professionalstate">
@@ -108,6 +111,9 @@
  import { ref, getCurrentInstance, watch, h, nextTick, onMounted,defineEmits } from 'vue'
  import { EditPen, Back } from '@element-plus/icons-vue'
  const emits = defineEmits(['updateView'])
+ let props = defineProps({
+    detailsData: Object,
+})
  let userdata = ref({
       name: '',
       country: '',
@@ -120,9 +126,13 @@
       professionalstate:false,
  })
  let thridPartydata = ref([
-      { name: '微信', icon: '#icon-weixin', state: true, key: 'wechart' },
-      { name: '钉钉', icon: '#icon-dingding', state: true, key: 'dingding' },
+      { name: '微信', icon: '#icon-weixin', state: false, key:'wechart' },
+      { name: '钉钉', icon: '#icon-dingding', state: false, key:'ding' },
+      { name: 'Facebook', icon:'#icon-facebook', state: false, key:'facebook' },
+      { name: 'Google', icon:'#icon-google', state: false, key:'google' },
+      { name: 'Apple', icon:'#icon-logo_apple', state: false, key:'apple' },
  ])
+ let specialBind=ref(require('@/assets/img/notspecial-icon.png'))
  let options=ref( [
     {
       value: 'zh-cn',
@@ -137,6 +147,16 @@
       label: '简体',
     },
   ])
+ let integralAndticket=ref({
+    integral:{
+        used:0,
+        total:0,
+    },
+    ticket:{
+        used:0,
+        total:0,
+    }
+ })
 const optionsT = ref([
   {
     value: 'Option1',
@@ -165,7 +185,38 @@ function handleChange(value) {
  function backs() {
     console.log('123')
     emits('updateView',true);
- }
+}
+function inidatas(){
+    console.log(props,'用户详情')
+    let originalData=props?.detailsData
+    //处理绑定第三方
+    let {wechat,ding,facebook,google,apple,educloudtw,points,coupons,lang,unitName,jobTitle,unitType}=originalData
+    wechat ? thridPartydata.value[0].state=true:thridPartydata.value[0].state=false
+    ding ? thridPartydata.value[1].state=true:thridPartydata.value[1].state=false
+    facebook ? thridPartydata.value[2].state=true:thridPartydata.value[2].state=false
+    google ? thridPartydata.value[3].state=true:thridPartydata.value[3].state=false
+    apple ? thridPartydata.value[4].state=true:thridPartydata.value[4].state=false
+    educloudtw ? specialBind.value=require('@/assets/img/special-icon.png'):specialBind.value=require('@/assets/img/notspecial-icon.png')
+    //积分票卷
+    integralAndticket.value.integral.used=points.balance
+    integralAndticket.value.integral.total=points.points
+    integralAndticket.value.ticket.used=coupons.length
+    integralAndticket.value.ticket.total=coupons.length
+    //语系 公司 职称
+    userdata.value.country=lang ==='zh-cn' ? '中文简体':lang ==='zh-tw' ?'中文繁体':'英语'
+    userdata.value.company=unitName
+    userdata.value.type =unitType == '1'? '基礎教育機構':
+    unitType =='2' ? '中等教育機構':unitType=='3' ? '高等教育機構':unitType=='4' ? '政府單位機構':unitType=='5' ? 'NGO機構':
+    unitType =='6' ? '企業機構':unitType=='7' ? '其他':unitType=='8' ? '學前教育':unitType=='9' ? '特殊教育':''
+    userdata.value.professional=jobTitle
+}
+onMounted(() => {
+    inidatas()
+})
+watch(()=>props,(newdata)=>{
+    console.log(newdata,'新值-进阶数据')
+    newdata.detailsData ? inidatas():''
+},{deep:true})
  </script>
  <style scoped>
  .user-forward{
@@ -186,6 +237,7 @@ function handleChange(value) {
     overflow: hidden;
     margin-right: 25px;
     margin-left: 0px;
+    cursor: pointer;
  }
  .third-party{
     display: flex;

+ 2 - 2
TEAMModelBI/Controllers/BIBlob/AnalyseFileController.cs

@@ -206,7 +206,7 @@ namespace TEAMModelBI.Controllers.BIBlob
             RecCnt saveCnts = new();
             //var ipGroup = aGInfos.GroupBy(g => g.properties.clientIp).ToDictionary(k => k.Key, k => k.Count()).ToList();
 
-            List<RecAppGWInfo> recInfo = aGInfos.Select(s => new RecAppGWInfo { hour = cHour, ip = s.properties.clientIp, api = s.properties.requestUri.Split("?").ToList().Count() > 1 ? s.properties.requestUri.Split("?").ToList()[0] : s.properties.requestUri, hostName = s.properties.hostname }).ToList();
+            List<RecAppGWInfo> recInfo = aGInfos.Select(s => new RecAppGWInfo { hour = cHour, ip = s.properties.CIp, api = s.properties.CsUriStem.Split("?").ToList().Count() > 1 ? s.properties.CsUriStem.Split("?").ToList()[0] : s.properties.CsUriStem, hostName = s.properties.CsHost }).ToList();
 
             List<RecApiCnt> apiCnt = recInfo.GroupBy(a => a.api).Select(g => new RecApiCnt { api = g.Key, count = g.Count(), hour = cHour, hostName = g.Select(h => h.hostName).Distinct().ToList(), ip = g.Select(i => i.ip).Distinct().ToList() }).ToList();
             saveCnts.apiCnt= apiCnt;
@@ -296,7 +296,7 @@ namespace TEAMModelBI.Controllers.BIBlob
 
                 RecCnt saveCnts = new();
 
-                List<RecAppGWInfo> recInfo = aGInfos.Select(s => new RecAppGWInfo { hour = cHour, ip = s.properties.clientIp, api = s.properties.requestUri.Split("?").ToList().Count() > 1 ? s.properties.requestUri.Split("?").ToList()[0] : s.properties.requestUri, hostName = s.properties.hostname }).ToList();
+                List<RecAppGWInfo> recInfo = aGInfos.Select(s => new RecAppGWInfo { hour = cHour, ip = s.properties.CIp, api = s.properties.CsUriStem.Split("?").ToList().Count() > 1 ? s.properties.CsUriStem.Split("?").ToList()[0] : s.properties.CsUriStem, hostName = s.properties.CsHost }).ToList();
 
                 List<RecApiCnt> apiCnt = recInfo.GroupBy(a => a.api).Select(g => new RecApiCnt { api = g.Key, count = g.Count(), hour = cHour, hostName = g.Select(h => h.hostName).Distinct().ToList(), ip = g.Select(i => i.ip).Distinct().ToList() }).ToList();
                 saveCnts.apiCnt = apiCnt;

+ 205 - 0
TEAMModelBI/Controllers/BICommon/BICouponController.cs

@@ -0,0 +1,205 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Options;
+using System.Net.Http;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK;
+using TEAMModelOS.Models;
+using System.Text.Json;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Text;
+using TEAMModelOS.SDK.Extension;
+using System;
+using System.Net.Http.Json;
+using System.ComponentModel.DataAnnotations;
+using System.Net;
+using System.Net.Http.Headers;
+using Newtonsoft.Json;
+using System.Text.Encodings.Web;
+
+namespace TEAMModelBI.Controllers.BICommon
+{
+    [Route("coupon")]
+    [ApiController]
+    public class BICouponController : ControllerBase
+    {
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly IConfiguration _configuration;
+        private readonly AzureServiceBusFactory _serviceBus;
+        private readonly IHttpClientFactory _http;
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly IWebHostEnvironment _environment; //读取文件
+        private readonly HttpClient _httpClient;
+
+        public BICouponController(DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration, AzureServiceBusFactory serviceBus, IHttpClientFactory http, CoreAPIHttpService coreAPIHttpService, IWebHostEnvironment hostingEnvironment, HttpClient httpClient)
+        {
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _configuration = configuration;
+            _serviceBus = serviceBus;
+            _http = http;
+            _coreAPIHttpService = coreAPIHttpService;
+            _environment = hostingEnvironment;
+            _httpClient = httpClient;
+        }
+
+        /// <summary>
+        /// 建立優惠券
+        /// </summary>
+        /// <param name="GenerateCouponRequest"></param>
+        /// <returns></returns>
+        //[AuthToken(Roles = "admin,rdc,assist,sales")]
+        [HttpPost("create-coupon")]
+        public async Task<IActionResult> CreateCoupon(GenerateCouponRequest request)
+        {
+            try
+            {
+                //string url = _configuration.GetValue<string>("HaBookAuth:CoreAPI");
+                string url = "https://api2.teammodel.net";
+                if (request.srvAdr == "China") url = "https://api2.teammodel.cn";
+                
+                string AccessToken = await getCoreAccessToken();
+                var client = _http.CreateClient();
+                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
+                HttpResponseMessage response = await client.PostAsJsonAsync($"{url}/Service/GenerateCoupon", request);
+                if (response.StatusCode == HttpStatusCode.OK)
+                {
+                    string jsonStr = await response.Content.ReadAsStringAsync();
+                    var options1 = new JsonSerializerOptions
+                    {
+                        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
+                    };
+
+                    await _dingDing.SendBotMsg(System.Text.Json.JsonSerializer.Serialize(request, options1), GroupNames.高飛);
+                    return Ok(jsonStr.ToObject<JsonElement>());
+                }
+                else {
+                    return BadRequest();
+                }
+            }
+            catch (Exception ex) {
+                return BadRequest();
+            }
+        }
+
+        /// <summary>
+        /// 歸戶
+        /// </summary>
+        /// <param name="GenerateCouponRequest"></param>
+        /// <returns></returns>
+        //[AuthToken(Roles = "admin,rdc,assist,sales")]
+        [HttpPost("consolidation-coupon")]
+        public async Task<IActionResult> ConsolidationCoupon(ConsolidationCouponRequest request)
+        {
+            try
+            {
+                //string url = _configuration.GetValue<string>("HaBookAuth:CoreAPI");
+                string url = "https://api2.teammodel.net";
+                if (request.srvAdr == "China") url = "https://api2.teammodel.cn";
+                string AccessToken = await getCoreAccessToken();
+                var client = _http.CreateClient();
+                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
+                HttpResponseMessage response = await client.PostAsJsonAsync($"{url}/Service/CouponConsolidation", request);
+                if (response.StatusCode == HttpStatusCode.OK)
+                {
+                    return Ok(new { state = 0, msg = "歸戶成功" });
+                }
+                else
+                {
+                    return BadRequest();
+                }
+            }
+            catch (Exception ex)
+            {
+                return BadRequest();
+            }
+        }
+
+        /// <summary>
+        /// 通知
+        /// </summary>
+        /// <param name="GenerateCouponRequest"></param>
+        /// <returns></returns>
+        //[AuthToken(Roles = "admin,rdc,assist,sales")]
+        [HttpPost("push-notify")]
+        public async Task<IActionResult> PushNotify(PushNotifyRequest request)
+        {
+            try
+            {
+                //string url = _configuration.GetValue<string>("HaBookAuth:CoreAPI");
+                string url = "https://api2.teammodel.net";
+                if (request.srvAdr == "China") url = "https://api2.teammodel.cn";
+                string AccessToken = await getCoreAccessToken();
+                var client = _http.CreateClient();
+                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
+                HttpResponseMessage response = await client.PostAsJsonAsync($"{url}/Service/PushNotify", request);
+                if (response.StatusCode == HttpStatusCode.OK)
+                {
+                    return Ok(new { state = 0, msg = "發送成功" });
+                }
+                else
+                {
+                    return BadRequest();
+                }
+            }
+            catch (Exception ex)
+            {
+                return BadRequest();
+            }
+        }
+
+        private async Task<string> getCoreAccessToken()
+        {
+            string AccessToken = "";
+            try
+            {
+                string Url = _configuration.GetValue<string>("HaBookAuth:CoreAPI") + "/oauth2/token";
+                string GrantType = "device";
+                string ClientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                string Secret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
+                var content = new { grant_type = GrantType, client_id = ClientID, client_secret = Secret };
+                var response = await _http.CreateClient().PostAsJsonAsync($"{Url}", content);
+                if (response.IsSuccessStatusCode)
+                {
+                    string responseBody = response.Content.ReadAsStringAsync().Result;
+                    using (JsonDocument document = JsonDocument.Parse(responseBody.ToString()))
+                    {
+                        if (document.RootElement.TryGetProperty("access_token", out JsonElement AccessTokenObj))
+                        {
+                            AccessToken = AccessTokenObj.ToString();
+                        }
+                    }
+                }
+                return AccessToken;
+            }
+            catch (Exception ex)
+            {
+                return AccessToken;
+            }
+        }
+
+
+    }
+
+    public class info
+    {
+        public string l { get; set; }
+        public string n { get; set; }
+        public string u { get; set; }
+    }
+    public class CouponRule
+    {
+        public string q { get; set; }
+        //可獲得的權益
+        public string b { get; set; }
+        //若已有權益 則給積分
+        public int p { get; set; } = 0;
+    }
+
+    public record GenerateCouponRequest([Required] string srvAdr, [Required] string CouponType, List<string> targets, string couponName, int quantity, [Required] long expire, [Required] List<CouponRule> rule, string eventName, List<info> info, int maxTaker = -1);
+    public record ConsolidationCouponRequest([Required] string srvAdr, [Required] string coupon, [Required] List<string> ids);
+    public record PushNotifyRequest([Required] string srvAdr, [Required] string title, [Required] string body, [Required] List<string> tags, [Required] string sender, [Required] string hubName);
+}

+ 8 - 2
TEAMModelBI/Controllers/BICommon/BINoticeController.cs

@@ -138,6 +138,7 @@ namespace TEAMModelBI.Controllers.BICommon
                 if (!jsonElement.TryGetProperty("crowdType", out JsonElement _crowdType)) return BadRequest();
                 if (!jsonElement.TryGetProperty("sendTime", out JsonElement sendTime)) return BadRequest();
                 jsonElement.TryGetProperty("source", out JsonElement source);
+                jsonElement.TryGetProperty("isOnlySave", out JsonElement isOnlySave);
 
                 var cosmosClient = _azureCosmos.GetCosmosClient();
                 //DateTimeOffset dateTime = DateTimeOffset.UtcNow;
@@ -234,8 +235,11 @@ namespace TEAMModelBI.Controllers.BICommon
                 };
 
                 bINotice = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync<BINotice>(bINotice, new PartitionKey("BINotice"));
-                //BI发送端外通知
-                _coreAPIHttpService.BIPushNotify(bINotice, new Dictionary<string, object> { { "tmdid", _tmdIds }, { "sendId", bINotice.crowdIds} }, _option.Location, _configuration, _dingDing);
+                if (isOnlySave.GetBoolean()) 
+                {
+                    //BI发送端外通知
+                    _coreAPIHttpService.BIPushNotify(bINotice, new Dictionary<string, object> { { "tmdid", _tmdIds }, { "sendId", bINotice.crowdIds } }, _option.Location, _configuration, _dingDing);
+                }
 
                 return Ok(new { state = RespondCode.Ok, bINotice });
             }
@@ -262,6 +266,8 @@ namespace TEAMModelBI.Controllers.BICommon
             StringBuilder sql = new("select value(c) from c");
             if (!string.IsNullOrEmpty($"{id}"))
                 sql.Append($" where c.id='{id}'");
+
+            sql.Append($" order by c.sendTime desc ");
             await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<BINotice>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("BINotice") }))
             {
                 bINotices.Add(item);

+ 109 - 3
TEAMModelBI/Controllers/BIHome/OnLineController.cs

@@ -96,9 +96,115 @@ namespace TEAMModelBI.Controllers.BIHome
             todayTchCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Teacher", addSql, "Base");
             todayStuCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Student", addSql, "Base");
 
-            string onStuSql = $"select value(count(c.id)) from c join t in c.loginInfos where array_length(c.loginInfos) > 0 and t.expire > {hour1} and c.pk='Base'";
-            onTchCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Teacher", onStuSql);
-            onStuCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Student", onStuSql);
+            //string onStuSql = $"select value(count(c.id)) from c join t in c.loginInfos where array_length(c.loginInfos) > 0 and t.expire > {hour1} and c.pk='Base'";
+            //onTchCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Teacher", onStuSql);
+            //onStuCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Student", onStuSql);
+
+            #region 取得在線人數
+            var dateDay = dateTime.ToString("yyyyMMdd"); //获取当天的日期
+            var redisClinet = _azureRedis.GetRedisClient(8);
+            var (strDaySt, strDayEt) = TimeHelper.GetUnixToDate(daySt, dayEt, "yyyyMMddHH");
+            Dictionary<long, int> allDays = new();  //所有在线人数
+            Dictionary<long, int> tchDays = new();  //教师在线人数
+            Dictionary<long, int> stuDays = new();  //学生在线人数
+            Dictionary<long, int> tmdDays = new();  //醍摩豆账户学生
+            int tchkey = 0;// 最近時間的key
+
+            // 撈redis記錄的教師在線人數
+            SortedSetEntry[] tchDay = redisClinet.SortedSetRangeByScoreWithScores($"Login:IES:teacher:{dateDay}");
+            if (tchDay.Length > 0)// 如果redis有資料就直接使用
+            {
+                foreach (var item in tchDay)
+                {
+                    int val = ((int)item.Score);
+                    int key = ((int)item.Element);
+                    tchDays.Add(key, val);                   
+                }
+                
+                var tchDaysOrderBy = tchDays.OrderBy(o => o.Key).ToList();
+                tchkey = (int)tchDaysOrderBy[tchDaysOrderBy.Count - 1].Key;
+                onTchCnt = (int)tchDaysOrderBy[tchDaysOrderBy.Count - 1].Value;              
+            }
+            else
+            {// 如果redis沒資料去Azure Storage取
+                string tableSqlTch = $"PartitionKey eq 'HourLogin' and RowKey ge '{strDaySt}' and RowKey le '{strDayEt}'";
+                List<HourLogin> hourLoginsTch = await table.QueryWhereString<HourLogin>(tableSqlTch);
+
+                if (hourLoginsTch.Count > 0)
+                {
+                    foreach (var item in hourLoginsTch)
+                    {                       
+                        tchDays.Add(item.Hour, item.Teacher);                       
+                    }
+                    var tchDaysOrderBy = tchDays.OrderBy(o => o.Key).ToList();
+                    tchkey = (int)tchDaysOrderBy[tchDaysOrderBy.Count - 1].Key;
+                    onTchCnt = (int)tchDaysOrderBy[tchDaysOrderBy.Count - 1].Value;
+                }
+            }
+            // 撈redis記錄的學生在線人數
+            SortedSetEntry[] stuDay = redisClinet.SortedSetRangeByScoreWithScores($"Login:IES:student:{dateDay}");
+            if (stuDay.Length > 0)// 如果redis有資料就直接使用
+            {
+                foreach (var item in stuDay)
+                {
+                    int val = ((int)item.Score);
+                    int key = ((int)item.Element);
+                    stuDays.Add(key, val);
+                }
+
+                var stuDaysOrderBy = stuDays.OrderBy(o => o.Key).ToList();
+                onStuCnt = (int)stuDaysOrderBy[stuDaysOrderBy.Count - 2].Value;
+            }
+            else
+            {// 如果redis沒資料去Azure Storage取
+                string tableSqlStu = $"PartitionKey eq 'HourLogin' and RowKey ge '{strDaySt}' and RowKey le '{strDayEt}'";
+                List<HourLogin> hourLoginsStu = await table.QueryWhereString<HourLogin>(tableSqlStu);                
+                if (hourLoginsStu.Count > 0)
+                {
+                    foreach (var item in hourLoginsStu)
+                    {
+                        stuDays.Add(item.Hour, item.Student);
+                    }
+                    var stuDaysOrderBy = stuDays.OrderBy(o => o.Key).ToList();
+                    onStuCnt = (int)stuDaysOrderBy[stuDaysOrderBy.Count - 2].Value;             
+                }
+            }
+
+            SortedSetEntry[] tmdDay = redisClinet.SortedSetRangeByScoreWithScores($"Login:IES:tmduser:{dateDay}");
+            if (tmdDay.Length > 0)
+            {
+                foreach (var item in tmdDay)
+                {
+                    int val = (int)item.Score;
+                    int key = (int)item.Element;
+                    tmdDays.Add(key, val);                   
+                }
+                int iValue = 0;
+                if (tmdDays.TryGetValue(tchkey, out iValue)) 
+                {
+                    onStuCnt = onStuCnt + tmdDays[tchkey]; // 用最近時間的key取在線醍摩豆账户学生數
+                }                
+            }
+            else
+            {
+                string tableSqlTmd = $"PartitionKey eq 'HourLogin' and RowKey ge '{strDaySt}' and RowKey le '{strDayEt}'";
+                List<HourLogin> hourLoginsTmd = await table.QueryWhereString<HourLogin>(tableSqlTmd);
+                if (hourLoginsTmd.Count > 0)
+                {
+                    foreach (var item in hourLoginsTmd)
+                    {                        
+                        var utcTo = new DateTimeOffset(new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, item.Hour, 00, 00)).Hour;
+                        tmdDays.Add(utcTo, item.TmdUser);                       
+                    }
+                    int iValue = 0;
+                    if (tmdDays.TryGetValue(tchkey, out iValue))
+                    {
+                        onStuCnt = onStuCnt + tmdDays[tchkey]; // 用最近時間的key取在線醍摩豆账户学生數
+                    }                    
+                }
+            }
+
+            #endregion
 
             //接口访问量
             List<RecCnt> recCnts = new();

+ 83 - 73
TEAMModelBI/Controllers/BINormal/BatchAreaController.cs

@@ -598,31 +598,27 @@ namespace TEAMModelBI.Controllers.BINormal
                 #endregion
 
                 //执行复制操作
-                BatchCopyFile batchCopyFile = new BatchCopyFile();
-                batchCopyFile.blobCntr = "teammodelos";
-                batchCopyFile.oldFileName = $"{oldStandard}";
-                batchCopyFile.newFileName = $"{standard}";
-                batchCopyFile.tmdid = $"{_tmdId}";
-                batchCopyFile.tmdIds = new List<string> { $"{ _tmdId}" };
-                batchCopyFile.codeKey = partitionCode;
-                batchCopyFile.tmdName = $"{_tmdName}";
-                var messageBatchCopyFile = new ServiceBusMessage(batchCopyFile.ToJsonString());
-                messageBatchCopyFile.ApplicationProperties.Add("name", "CopyStandardFile");
-                //var activeTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
-
-                try
-                {
-                    //await  _serviceBus.GetServiceBusClient().SendMessageAsync(activeTask, messageBatchCopyFile);
-                    await serBusClient.SendMessageAsync(activeTask, messageBatchCopyFile);
-                }
-                catch (Exception)
-                {
-                    return Ok(new { state = 201, msg = "能力点复制成功,复制能力点的文件失败," });
-                }
- 
-
-            
-              
+                //去除新建区,复制能力点文件
+                //BatchCopyFile batchCopyFile = new BatchCopyFile();
+                //batchCopyFile.blobCntr = "teammodelos";
+                //batchCopyFile.oldFileName = $"{oldStandard}";
+                //batchCopyFile.newFileName = $"{standard}";
+                //batchCopyFile.tmdid = $"{_tmdId}";
+                //batchCopyFile.tmdIds = new List<string> { $"{ _tmdId}" };
+                //batchCopyFile.codeKey = partitionCode;
+                //batchCopyFile.tmdName = $"{_tmdName}";
+                //var messageBatchCopyFile = new ServiceBusMessage(batchCopyFile.ToJsonString());
+
+                //messageBatchCopyFile.ApplicationProperties.Add("name", "CopyStandardFile");
+
+                //try
+                //{
+                //    await serBusClient.SendMessageAsync(activeTask, messageBatchCopyFile);
+                //}
+                //catch (Exception)
+                //{
+                //    return Ok(new { state = 201, msg = "能力点复制成功,复制能力点的文件失败," });
+                //}
                 //保存操作记录
                 //await _azureStorage.SaveBILog("area-add", $"{_tmdName}【{_tmdId}】已操作创区功能模块:{name},当前标准【{standard}】,复制的微能力点:{tempStandard}", _dingDing, httpContext: HttpContext);
                 await AzureStorageBlobExtensions.SaveBILog(blobClient, tableClient, "area-add", $"{_tmdName}【{_tmdId}】已操作创区功能模块:{name},当前标准【{standard}】,复制的微能力点:{tempStandard}", _dingDing, httpContext: HttpContext);
@@ -686,20 +682,31 @@ namespace TEAMModelBI.Controllers.BINormal
                 // 檢查是否有大寫或是中文字
                 if ( Regex.IsMatch(shortCode, @"[^a-z0-9]") )
                 {
-                    return Ok(new { state = 1, message = "此區級簡碼必須為小寫字母!" });
+                    return Ok(new { state = 1, message = "此区级简码必须为小写字母!" });
                 }             
 
                 string sqlCheckRep =  $"SELECT c.id FROM c WHERE c.shortCode = '{shortCode}'";
                 var _azureCosmosClientCsv2Read = _azureCosmos.GetCosmosClient(name: "CoreServiceV2CnRead");
-                await foreach (var item in _azureCosmosClientCsv2Read.GetContainer("Core", "School").GetItemQueryStreamIterator(queryText: sqlCheckRep, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("district") })) 
-                {
-                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetInt16() > 0)
-                    {
-                        return Ok(new { state = 1, message = "区级名称相同,请检测区级名称!" });
-                    }                    
-                }
-                
+                //學校資料庫驗證 [式樣待確認,先封印]
+                ///學區簡碼重複驗證
+                //await foreach (var item in _azureCosmosClientCsv2Read.GetContainer("Core", "School").GetItemQueryStreamIterator(queryText: sqlCheckRep, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("district") })) 
+                //{
+                //    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                //    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetInt16() > 0)
+                //    {
+                //        return Ok(new { state = 1, message = "此学区简码与其他 [学区] 简码相同请检查!" });
+                //    }                    
+                //}
+                ///學校簡碼重複驗證
+                //await foreach (var item in _azureCosmosClientCsv2Read.GetContainer("Core", "School").GetItemQueryStreamIterator(queryText: sqlCheckRep, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("base") }))
+                //{
+                //    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                //    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetInt16() > 0)
+                //    {
+                //        return Ok(new { state = 1, message = "此学区简码与其他 [学校] 简码相同请检查!" });
+                //    }
+                //}
+
                 //DB值更新
                 if (!string.IsNullOrWhiteSpace(name)) area.name = name;
                 if (!string.IsNullOrWhiteSpace(shortCode)) area.shortCode = shortCode;
@@ -942,25 +949,27 @@ namespace TEAMModelBI.Controllers.BINormal
                 _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = targetTeacher.id, name = targetTeacher.name, code = targetTeacher.lang } }, "copy-file_area", Constant.NotifyType_IES5_Management, new Dictionary<string, object> { { "tmdname", $"{_tmdName}" } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
 
                 //执行复制操作
-                BatchCopyFile batchCopyFile = new();
-                batchCopyFile.blobCntr = "teammodelos";
-                batchCopyFile.oldFileName = $"{_newStandard}";
-                batchCopyFile.newFileName = $"{_oldStandard}";
-                batchCopyFile.tmdid = $"{_tmdId}";
-                batchCopyFile.tmdIds = new List<string> { $"{ _tmdId}" };
-                batchCopyFile.codeKey = partitionCode;
-                batchCopyFile.tmdName = $"{_tmdName}";
-                var messageBatchCopyFile = new ServiceBusMessage(batchCopyFile.ToJsonString());
-                messageBatchCopyFile.ApplicationProperties.Add("name", "CopyStandardFile");  
-                try
-                {
-                    //await _serviceBus.GetServiceBusClient().SendMessageAsync(activeTask, messageBatchCopyFile);  //先执行删除操作,在执行复制  单一
-                    await serBusClient.SendMessageAsync(activeTask, messageBatchCopyFile);  //先执行删除操作,在执行复制
-                }
-                catch (Exception)
-                {
-                    return Ok(new { state = 201 ,msg = "能力点复制成功,复制能力点的文件失败," });
-                }
+
+                //去除新建区,复制能力点文件
+                //BatchCopyFile batchCopyFile = new();
+                //batchCopyFile.blobCntr = "teammodelos";
+                //batchCopyFile.oldFileName = $"{_newStandard}";
+                //batchCopyFile.newFileName = $"{_oldStandard}";
+                //batchCopyFile.tmdid = $"{_tmdId}";
+                //batchCopyFile.tmdIds = new List<string> { $"{ _tmdId}" };
+                //batchCopyFile.codeKey = partitionCode;
+                //batchCopyFile.tmdName = $"{_tmdName}";
+                //var messageBatchCopyFile = new ServiceBusMessage(batchCopyFile.ToJsonString());
+                //messageBatchCopyFile.ApplicationProperties.Add("name", "CopyStandardFile");  
+                //try
+                //{
+                     
+                //    await serBusClient.SendMessageAsync(activeTask, messageBatchCopyFile);  //先执行删除操作,在执行复制
+                //}
+                //catch (Exception)
+                //{
+                //    return Ok(new { state = 201 ,msg = "能力点复制成功,复制能力点的文件失败," });
+                //}
 
               
                 //保存操作记录
@@ -1276,25 +1285,26 @@ namespace TEAMModelBI.Controllers.BINormal
                         string partitionCode = "DelBeforeCopyAbility-mark";
 
                         //执行复制操作
-                        BatchCopyFile batchCopyFile = new();
-                        batchCopyFile.blobCntr = "teammodelos";
-                        batchCopyFile.oldFileName = $"{newstand.standard}";
-                        batchCopyFile.newFileName = $"{area.standard}";
-                        batchCopyFile.tmdid = $"{_tmdId}";
-                        batchCopyFile.tmdIds = new List<string> { $"{_tmdId}" };
-                        batchCopyFile.codeKey = partitionCode;
-                        batchCopyFile.tmdName = $"{_tmdName}";
-                        var messageBatchCopyFile = new ServiceBusMessage(batchCopyFile.ToJsonString());
-                        messageBatchCopyFile.ApplicationProperties.Add("name", "CopyStandardFile");
-                        try
-                        {
-                            //await _serviceBus.GetServiceBusClient().SendMessageAsync(activeTask, messageBatchCopyFile);  //先执行删除操作,在执行复制  单一
-                            await serBusClient.SendMessageAsync(activeTask, messageBatchCopyFile);  //先执行删除操作,在执行复制
-                        }
-                        catch (Exception)
-                        {
-                            return Ok(new { state = 201, msg = "能力点复制成功,复制能力点的文件失败," });
-                        }
+                        //去除新建区,复制能力点文件
+                        //BatchCopyFile batchCopyFile = new();
+                        //batchCopyFile.blobCntr = "teammodelos";
+                        //batchCopyFile.oldFileName = $"{newstand.standard}";
+                        //batchCopyFile.newFileName = $"{area.standard}";
+                        //batchCopyFile.tmdid = $"{_tmdId}";
+                        //batchCopyFile.tmdIds = new List<string> { $"{_tmdId}" };
+                        //batchCopyFile.codeKey = partitionCode;
+                        //batchCopyFile.tmdName = $"{_tmdName}";
+                        //var messageBatchCopyFile = new ServiceBusMessage(batchCopyFile.ToJsonString());
+                        //messageBatchCopyFile.ApplicationProperties.Add("name", "CopyStandardFile");
+                        //try
+                        //{
+                        //    //await _serviceBus.GetServiceBusClient().SendMessageAsync(activeTask, messageBatchCopyFile);  //先执行删除操作,在执行复制  单一
+                        //    await serBusClient.SendMessageAsync(activeTask, messageBatchCopyFile);  //先执行删除操作,在执行复制
+                        //}
+                        //catch (Exception)
+                        //{
+                        //    return Ok(new { state = 201, msg = "能力点复制成功,复制能力点的文件失败," });
+                        //}
                     }
 
                     StandardFile saveFile = new();

+ 18 - 3
TEAMModelBI/Controllers/BIProductAnalysis/ProductAnalysisController.cs

@@ -64,7 +64,7 @@ namespace TEAMModelBI.Controllers.ProductAnalysis
                 var cosmosClient = _azureCosmos.GetCosmosClient();
                 var redisClinet8 = _azureRedis.GetRedisClient(8);
                 if (!jsonElement.TryGetProperty("dateFrom", out JsonElement dateFromJobj)) return BadRequest();//查詢日期:起始(string)[例]2023-03-05
-                if(!jsonElement.TryGetProperty("dateTo", out JsonElement dateToJobj)) return BadRequest();//查詢日期:結束(string)[例]2023-03-27
+                if (!jsonElement.TryGetProperty("dateTo", out JsonElement dateToJobj)) return BadRequest();//查詢日期:結束(string)[例]2023-03-27
                 if (!jsonElement.TryGetProperty("prod", out JsonElement prodJobj)) return BadRequest();//產品 HiTeach, HiTeachCC, HiTA
                 string prod = (prodJobj.ToString().Equals("HiTeach") || prodJobj.ToString().Equals("HiTeachCC") || prodJobj.ToString().Equals("HiTA")) ? prodJobj.ToString() : string.Empty;
                 if(string.IsNullOrWhiteSpace(prod)) return BadRequest();
@@ -116,7 +116,7 @@ namespace TEAMModelBI.Controllers.ProductAnalysis
                     }
                 }
 
-                ////取得產品分析資訊
+                ////取得IOT產品分析資訊
                 List<ProdAnalysisApiResult> result = new List<ProdAnalysisApiResult>();
                 string Sql = $"SELECT * FROM c WHERE c.toolType = '{prod}' AND c.dateUnit = '{dateUnit}' AND c.dateTime >= {dateTimeFromSec} AND c.dateTime <= {dateTimeToSec}";
                 if(schoolIds.Count > 0)
@@ -175,6 +175,16 @@ namespace TEAMModelBI.Controllers.ProductAnalysis
                 string dist = (jsonElement.TryGetProperty("dist", out JsonElement distJobj)) ? distJobj.GetString() : string.Empty; //區
                 List<string> areaIds = (jsonElement.TryGetProperty("areaIds", out JsonElement areaIdsJobj)) ? areaIdsJobj.ToObject<List<string>>() : new List<string>(); //學區ID(array)
                 bool hasVirtual = (jsonElement.TryGetProperty("virtual", out JsonElement virtualJobj)) ? virtualJobj.GetBoolean() : true; //是否取得虛擬學校
+                //國際站欄位調整
+                if(_option.Location.Contains("Global"))
+                {
+                    if(string.IsNullOrWhiteSpace(region) && !string.IsNullOrWhiteSpace(province))
+                    {
+                        region = province;
+                        province = string.Empty;
+                        dist = string.Empty;
+                    }
+                }
                 //地區特殊字去除
                 comeRemoveStr.ForEach(c => { region = region.Replace(c, ""); });
                 comeRemoveStr.ForEach(c => { province = province.Replace(c, ""); });
@@ -183,6 +193,11 @@ namespace TEAMModelBI.Controllers.ProductAnalysis
 
                 //CosmosDB資料取得
                 List<SimpleSchoolInfo> result = new List<SimpleSchoolInfo>();
+                ///檢索條件全無對策
+                if(schoolIds.Count.Equals(0) && string.IsNullOrWhiteSpace(region) && string.IsNullOrWhiteSpace(province) && string.IsNullOrWhiteSpace(city) && string.IsNullOrWhiteSpace(dist) && areaIds.Count.Equals(0))
+                {
+                    return Ok(new { state = 200, data = result });
+                }
                 string schIdListStr = JsonSerializer.Serialize(schoolIds);
                 string areaIdsListStr = JsonSerializer.Serialize(areaIds);
                 string Sql = $"SELECT c.id, c.name, c.region, c.province, c.city, c.dist, c.areaId FROM c WHERE (c.pk = 'Base' OR c.pk = 'School')";
@@ -232,7 +247,7 @@ namespace TEAMModelBI.Controllers.ProductAnalysis
             }
         }
 
-        public List<string> comeRemoveStr = new List<string>() { "省", "市", "区", "州", "县", "旗", "盟", "自治", "區", "縣" };
+        public List<string> comeRemoveStr = new List<string>() { "省", "市", "区", "州", "县", "旗", "盟", "自治", "地區", "區", "縣" };
         private class SimpleSchoolInfo
         {
             public string id { get; set; }

+ 124 - 0
TEAMModelBI/Controllers/BISchool/BatchSchoolController.cs

@@ -39,6 +39,9 @@ using HTEXLib;
 using TEAMModelOS.SDK.Models.Service.BI;
 using TEAMModelOS.SDK.Models.Cosmos.BI.BISchool;
 using DocumentFormat.OpenXml.Vml.Office;
+using System.Net.Http.Headers;
+using System.Text.Encodings.Web;
+using System.ComponentModel.DataAnnotations;
 
 namespace TEAMModelBI.Controllers.BISchool
 {
@@ -1779,6 +1782,112 @@ namespace TEAMModelBI.Controllers.BISchool
             return Ok(new { state = RespondCode.Ok, error });
         }
 
+        /// <summary>
+        /// 根據地理位置搜尋學校基本訊息
+        /// </summary>
+        /// <param name="GenerateCouponRequest"></param>
+        /// <returns></returns>
+        //[AuthToken(Roles = "admin,rdc,assist,sales")]
+        [HttpPost("get-school-basic-info")]
+        public async Task<IActionResult> GetSchoolBasicInfo(SchoolDataRequest request)
+        {
+            try
+            {
+                string url = _configuration.GetValue<string>("HaBookAuth:CoreAPI");
+                string AccessToken = await getCoreAccessToken();
+                var client = _http.CreateClient();
+                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
+                HttpResponseMessage response = await client.PostAsJsonAsync($"{url}/Service/SchoolData", request);
+                if (response.StatusCode == HttpStatusCode.OK)
+                {
+                    string jsonStr = await response.Content.ReadAsStringAsync();
+                    var options1 = new JsonSerializerOptions
+                    {
+                        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
+                    };
+
+                    
+                    return Ok(jsonStr.ToObject<JsonElement>());
+                }
+                else
+                {
+                    return BadRequest();
+                }
+            }
+            catch (Exception ex)
+            {
+                return BadRequest();
+            }
+        }
+
+        /// <summary>
+        /// 弱歸戶
+        /// </summary>
+        /// <param name="GenerateCouponRequest"></param>
+        /// <returns></returns>
+        //[AuthToken(Roles = "admin,rdc,assist,sales")]
+        [HttpPost("upd-user-schoolw")]
+        public async Task<IActionResult> UpdUserSchoolW(UpdateUserSchoolCodeWRequest request)
+        {
+            try
+            {
+                string url = _configuration.GetValue<string>("HaBookAuth:CoreAPI");
+                string AccessToken = await getCoreAccessToken();
+                var client = _http.CreateClient();
+                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
+                HttpResponseMessage response = await client.PostAsJsonAsync($"{url}/Service/UpdateUserSchoolCodeW", request);
+                if (response.StatusCode == HttpStatusCode.OK)
+                {
+                    string jsonStr = await response.Content.ReadAsStringAsync();
+                    var options1 = new JsonSerializerOptions
+                    {
+                        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
+                    };
+
+
+                    return Ok(jsonStr.ToObject<JsonElement>());
+                }
+                else
+                {
+                    return BadRequest();
+                }
+            }
+            catch (Exception ex)
+            {
+                return BadRequest();
+            }
+        }
+
+        private async Task<string> getCoreAccessToken()
+        {
+            string AccessToken = "";
+            try
+            {
+                string Url = _configuration.GetValue<string>("HaBookAuth:CoreAPI") + "/oauth2/token";
+                string GrantType = "device";
+                string ClientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                string Secret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
+                var content = new { grant_type = GrantType, client_id = ClientID, client_secret = Secret };
+                var response = await _http.CreateClient().PostAsJsonAsync($"{Url}", content);
+                if (response.IsSuccessStatusCode)
+                {
+                    string responseBody = response.Content.ReadAsStringAsync().Result;
+                    using (JsonDocument document = JsonDocument.Parse(responseBody.ToString()))
+                    {
+                        if (document.RootElement.TryGetProperty("access_token", out JsonElement AccessTokenObj))
+                        {
+                            AccessToken = AccessTokenObj.ToString();
+                        }
+                    }
+                }
+                return AccessToken;
+            }
+            catch (Exception ex)
+            {
+                return AccessToken;
+            }
+        }
+
         #region   预设学校基础信息 多语言
 
         /// <summary>
@@ -2017,5 +2126,20 @@ namespace TEAMModelBI.Controllers.BISchool
             public string name { get; set; }
             public List<string> mobiles { get; set; }
         }
+
+        public record SchoolDataRequest
+        (
+            string countryId,
+            string provinceId,
+            string cityId,
+            string shortCode,
+            bool fullData = false
+        );
+
+        public record UpdateUserSchoolCodeWRequest
+        (
+            [Required] List<string> ids,
+            [Required] string schoolDocId
+        );
     }
 }

+ 170 - 0
TEAMModelBI/Controllers/BISchool/SchoolController.cs

@@ -10,6 +10,7 @@ using Newtonsoft.Json;
 using StackExchange.Redis;
 using System;
 using System.Collections.Generic;
+using System.Dynamic;
 using System.IO;
 using System.Linq;
 using System.Net;
@@ -821,6 +822,12 @@ namespace TEAMModelBI.Controllers.BISchool
                             schoolTeacher.roles.Add("admin");
                             schoolTeacher.status = "join";
                             schoolTeacher = await cosmosClient.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<SchoolTeacher>(schoolTeacher, schoolTeacher.id, new PartitionKey($"Teacher-{schoolId}"));
+
+                            #region 同時更新teacher的school.status
+                            var school = teacher.schools.Find(f => f.schoolId.Equals($"{schoolId}"));
+                            school.status = "join";
+                            await cosmosClient.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey("Base"));                            
+                            #endregion
                             strMsg.Append($"并设置管理员,学校信息{schoolName}【{schoolId}】");
                         }
                         else
@@ -2384,6 +2391,154 @@ namespace TEAMModelBI.Controllers.BISchool
             }
         }
 
+        /// <summary>
+        /// 取得某學校產品購買紀錄
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-school-product")]
+        public async Task<IActionResult> GetSchoolProductInfo(JsonElement request)
+        {
+            try
+            {
+                if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
+                var db = _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School");
+                var r8 = _azureRedis.GetRedisClient(8);
+
+                List<SchoolProductSerial> serial = new(); //承接DB資料用:序號
+                List<SerialInfoBaseWithdeviceBoundExt> serialResult = new(); //最後要輸出的序號結果
+                List<SchoolProductService> serviceProduct = new(); //承接DB資料用:服務
+                List<SchoolProductOrder> serviceOrder = new(); //服務各產品購買紀錄
+                List<SchoolProductSumDataService> serviceSum = new(); //服務各產品購買紀錄
+                List<SchoolProductHard> hard = new(); //承接DB資料用:硬體
+                SchoolProductSum productSum = new(); //承接DB資料用:產品目前狀態 
+                List<SchoolProductSumProdInfo> prodinfo = new(); //產品資訊列表(名稱、八碼)
+                long UTCNow = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
+
+                ////取得各產品目前可得數量
+                var response = await db.ReadItemStreamAsync(school_code.ToString(), new PartitionKey($"ProductSum"));
+                if (response.Status == 200)
+                {
+                    using var json = await JsonDocument.ParseAsync(response.ContentStream);
+                    productSum = json.ToObject<SchoolProductSum>();
+                    prodinfo = productSum.prodinfo;
+                    serviceSum = productSum.service;
+                }
+
+                //軟體
+                List<string> serialPermitList = getSerialPermitProdcodeList();
+                string serialPermitJsonStr = JsonConvert.SerializeObject(serialPermitList);
+                string serialQueryText = $"SELECT * FROM c WHERE c.dataType = 'serial' AND ARRAY_CONTAINS({serialPermitJsonStr}, c.prodCode)";
+                await foreach (var itemsr in db.GetItemQueryStreamIterator(queryText: serialQueryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Product-{school_code}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(itemsr.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        deviceForCoreService uuidForCore;
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            serial.Add(obj.ToObject<SchoolProductSerial>());
+                        }
+                    }
+                }
+
+                //服務
+                List<SchoolProductSumDataService> service = new List<SchoolProductSumDataService>();
+                SchoolProductSum schoolProductSum;
+                await foreach (var items in db.GetItemQueryStreamIterator(queryText: $"SELECT * FROM c WHERE c.id = '{school_code}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ProductSum") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(items.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            schoolProductSum = obj.ToObject<SchoolProductSum>();
+                            service = schoolProductSum.service;
+                        }
+                    }
+                }
+                if (service.Count > 0)
+                {
+                    SchoolProductOrder spOrderRow;
+                    foreach (SchoolProductSumDataService serviceRow in service)
+                    {
+                        spOrderRow = new SchoolProductOrder();
+                        spOrderRow.prodCode = serviceRow.prodCode;
+                        spOrderRow.avaliable = UTCNow>serviceRow.endDate ? 0 : serviceRow.avaliable;
+                        spOrderRow.avaliableStartDate = serviceRow.startDate;
+                        spOrderRow.avaliableEndDate = serviceRow.endDate;
+                        serviceOrder.Add(spOrderRow);
+                    }
+                }
+
+                //硬體
+                await foreach (var itemhd in db.GetItemQueryStreamIterator(queryText: $"SELECT * FROM c WHERE c.dataType = 'hard'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Product-{school_code}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(itemhd.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            hard.Add(obj.ToObject<SchoolProductHard>());
+                        }
+                    }
+                }
+
+                //空間計算
+                ////取得教師分配空間
+                long teach = 0;
+                var querysp = $"SELECT SUM(c.size) as size FROM c";
+                await foreach (var item in db.GetItemQueryStreamIterator(queryText: querysp, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
+                {
+                    var jsonts = await JsonDocument.ParseAsync(item.ContentStream);
+                    foreach (var obj in jsonts.RootElement.GetProperty("Documents").EnumerateArray())
+                    {
+                        teach = obj.GetProperty("size").GetInt64() * 1073741824; //G換算
+                    }
+                }
+                ////學校已使用空間
+                long blobsize = 0;
+                RedisValue value = default;
+                value = r8.HashGet($"Blob:Record", $"{school_code}");
+                if (value != default && !value.IsNullOrEmpty)
+                {
+                    JsonElement record = value.ToString().ToObject<JsonElement>();
+                    if (record.TryGetInt64(out blobsize))
+                    {
+                    }
+                }
+                ////各項空間數值取得
+                Dictionary<string, double> catalog = new();
+                SortedSetEntry[] Scores = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Blob:Catalog:{school_code}");
+                if (Scores != null)
+                {
+                    foreach (var score in Scores)
+                    {
+                        double val = score.Score;
+                        string key = score.Element.ToString();
+                        catalog.Add(key, val);
+                    }
+                }
+                dynamic space = new ExpandoObject();
+                space.size = blobsize;
+                space.teach = teach;
+                space.catalog = catalog;
+
+                //取得購買紀錄
+                List<object> order = await GetOrderHisFromCoreBBAsync(school_code.GetString());
+
+                //取得CC授權使用狀態
+                var hashs = await r8.HashGetAllAsync($"CC:License:{school_code.GetString()}");
+                var ccuser = hashs.Select(x => JsonDocument.Parse(x.Value.ToString())).ToList();
+
+                return Ok(new { serial = serial, service = serviceOrder, hard, space, order, ccuser });
+            }
+            catch (Exception ex)
+            {
+                return BadRequest();
+            }
+        }
         private async Task<string> getCoreAccessToken()
         {
             string AccessToken = "";
@@ -2414,6 +2569,21 @@ namespace TEAMModelBI.Controllers.BISchool
             }
         }
 
+        //取得序號產品准許使用產品代碼列表
+        public static List<string> getSerialPermitProdcodeList()
+        {
+            List<string> allowProdCode = new List<string>(); //軟體許可產品列:HiTeach STD、TBL、PRO、HiTeach5;
+            allowProdCode.Add("J223IZ6M"); //HiTeach STD
+            allowProdCode.Add("3222C6D2"); //HiTeach TBL
+            allowProdCode.Add("J223IZAM"); //HiTeach PRO
+            allowProdCode.Add("J2236ZCX"); //HiTeach Lite
+            allowProdCode.Add("3222DNG2"); //HiTeach Mobile
+            allowProdCode.Add("3222IAVN"); //HiTeach Premium
+            allowProdCode.Add("BYJ6LZ6Z"); //HiTeach5
+            allowProdCode.Add("LZLL6ZEI"); //HiTeachCC
+            return allowProdCode;
+        }
+
         #endregion
 
         #region  顾问学校统计返回值

+ 1 - 1
TEAMModelBI/Controllers/BITest/Ies5TestController.cs

@@ -74,7 +74,7 @@ namespace TEAMModelBI.Controllers.BITest
             var messageBatchCopyFile = new ServiceBusMessage(olrec.ToJsonString());
             messageBatchCopyFile.ApplicationProperties.Add("name", "OnLinRecord");   //Function名称
             var onlinRecTask = _configuration.GetValue<string>("Azue:ServiceBus:OnlinRecord");
-            await _serviceBus.GetServiceBusClient().SendMessageAsync(onlinRecTask, messageBatchCopyFile);
+           // await _serviceBus.GetServiceBusClient().SendMessageAsync(onlinRecTask, messageBatchCopyFile);
             return Ok(new { state = 200, dateHours, dateHours1, dateHours2, dateDay, dateDays, dateMonth, });
         }
 

File diff suppressed because it is too large
+ 832 - 197
TEAMModelBI/Controllers/BITmid/TmidController.cs


+ 35 - 7
TEAMModelBI/Controllers/Census/SchoolController.cs

@@ -900,7 +900,7 @@ namespace TEAMModelBI.Controllers.Census
                 areaScStats.size = statsInfo.size;
                 areaScStats.scCreateTime = statsInfo.scCreateTime;
                 areaScStats.upTime = statsInfo.upTime;
-                areaScStats.lessStats.open = statsInfo.lesson.all;
+                areaScStats.lessStats.all = statsInfo.lesson.all;
                 areaScStats.lessStats.open = statsInfo.lesson.open;
                 areaScStats.lessStats.less = statsInfo.lesson.less;
                 areaScStats.lessStats.lastDay = statsInfo.lesson.lastDay;
@@ -1413,9 +1413,31 @@ namespace TEAMModelBI.Controllers.Census
             jsonElement.TryGetProperty("tmdId", out JsonElement tmdId);
             jsonElement.TryGetProperty("areaId", out JsonElement areaId);
 
+            ////IES5實體學校學區名稱
+            List<string> AreaIdList = new List<string>();
+            StringBuilder sqlBiArea = new($"SELECT DISTINCT VALUE c.areaId FROM c WHERE IS_DEFINED(c.areaId) AND NOT IS_NULL(c.areaId) AND c.areaId != ''");
+            await foreach (string item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<string>(queryText: sqlBiArea.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("BIRel") }))
+            {
+                AreaIdList.Add(item);
+            }
+            Dictionary<string, string> areaDic = new Dictionary<string, string>();
+            string AreaListStr = JsonSerializer.Serialize(AreaIdList);
+            StringBuilder sqlArea = new($"SELECT c.id, c.name FROM c WHERE ARRAY_CONTAINS({AreaListStr}, c.id, true)");
+            await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryStreamIterator(queryText: sqlArea.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base-Area") }))
+            {
+                var json = await JsonDocument.ParseAsync(item.ContentStream);
+                foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                {
+                    string arId = obj.GetProperty("id").GetString();
+                    string arName = obj.GetProperty("name").GetString();
+                    if(!areaDic.ContainsKey(arId))
+                    {
+                        areaDic.Add(arId, arName);
+                    }
+                }
+            }
             //IES5實體學校
             StringBuilder sql = new($"select value(c) from c");
-
             if (!string.IsNullOrEmpty($"{role}") && !string.IsNullOrEmpty($"{tmdId}") && string.IsNullOrEmpty($"{areaId}"))
             {
                 switch ($"{role}")
@@ -1434,12 +1456,15 @@ namespace TEAMModelBI.Controllers.Census
                 sql.Append($" where c.areaId ='{areaId}'");
             }
 
-            //List<string> scId = await CommonFind.FindScIds(cosmosClient, "select value(c.id) from c ", "Base");
             //取得學校BI統計中間件
             List<BIRelation> scInfos = new();
             List<string> schIds = new();
             await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<BIRelation>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("BIRel") }))
             {
+                if (!string.IsNullOrWhiteSpace(item.areaId) && areaDic.ContainsKey(item.areaId))
+                {
+                    item.areaName = areaDic[item.areaId];
+                }
                 scInfos.Add(item);
                 schIds.Add(item.id);
             }
@@ -1471,17 +1496,20 @@ namespace TEAMModelBI.Controllers.Census
             {
                 vrAreaIdList.Add(item);
             }
-            Dictionary<string, string> areaDic = new Dictionary<string, string>();
+            //Dictionary<string, string> areaDic = new Dictionary<string, string>();
             string vrAreaListStr = JsonSerializer.Serialize(vrAreaIdList);
-            StringBuilder sqlArea = new($"SELECT c.id, c.name FROM c WHERE ARRAY_CONTAINS({vrAreaListStr}, c.id, true)");
-            await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryStreamIterator(queryText: sqlArea.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base-Area") }))
+            StringBuilder vrSqlArea = new($"SELECT c.id, c.name FROM c WHERE ARRAY_CONTAINS({vrAreaListStr}, c.id, true)");
+            await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryStreamIterator(queryText: vrSqlArea.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base-Area") }))
             {
                 var json = await JsonDocument.ParseAsync(item.ContentStream);
                 foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
                 {
                     string arId = obj.GetProperty("id").GetString();
                     string arName = obj.GetProperty("name").GetString();
-                    areaDic.Add(arId, arName);
+                    if (!areaDic.ContainsKey(arId))
+                    {
+                        areaDic.Add(arId, arName);
+                    }  
                 }
             }
             //取得虛擬學校資料

+ 20 - 21
TEAMModelBI/Controllers/RepairApi/InitialAreaController.cs

@@ -262,27 +262,26 @@ namespace TEAMModelBI.Controllers.RepairApi
                 }
 
                 //执行复制操作
-                BatchCopyFile batchCopyFile = new();
-                batchCopyFile.blobCntr = "teammodelos";
-                batchCopyFile.oldFileName = $"{area.standard}";
-                batchCopyFile.newFileName = $"{standard}";
-                batchCopyFile.tmdid = $"{_tmdId}";
-                batchCopyFile.tmdIds = new List<string> { $"{_tmdId}" };
-                batchCopyFile.codeKey = partitionCode;
-                batchCopyFile.tmdName = $"{_tmdName}";
-                var messageBatchCopyFile = new ServiceBusMessage(batchCopyFile.ToJsonString());
-                messageBatchCopyFile.ApplicationProperties.Add("name", "CopyStandardFile");
-                //var activeTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
-
-                try
-                {
-                    await _serviceBus.GetServiceBusClient().SendMessageAsync(activeTask, messageBatchCopyFile);
-                    await serBusClient.SendMessageAsync(activeTask, messageBatchCopyFile);
-                }
-                catch (Exception)
-                {
-                    return Ok(new { state = 201, msg = "能力点复制成功,复制能力点的文件失败," });
-                }
+                //BatchCopyFile batchCopyFile = new();
+                //batchCopyFile.blobCntr = "teammodelos";
+                //batchCopyFile.oldFileName = $"{area.standard}";
+                //batchCopyFile.newFileName = $"{standard}";
+                //batchCopyFile.tmdid = $"{_tmdId}";
+                //batchCopyFile.tmdIds = new List<string> { $"{_tmdId}" };
+                //batchCopyFile.codeKey = partitionCode;
+                //batchCopyFile.tmdName = $"{_tmdName}";
+                //去除新建区,复制能力点文件
+                //var messageBatchCopyFile = new ServiceBusMessage(batchCopyFile.ToJsonString());
+                //messageBatchCopyFile.ApplicationProperties.Add("name", "CopyStandardFile");
+                //try
+                //{
+                //    await _serviceBus.GetServiceBusClient().SendMessageAsync(activeTask, messageBatchCopyFile);
+                //    await serBusClient.SendMessageAsync(activeTask, messageBatchCopyFile);
+                //}
+                //catch (Exception)
+                //{
+                //    return Ok(new { state = 201, msg = "能力点复制成功,复制能力点的文件失败," });
+                //}
  
             }
 

+ 2 - 1
TEAMModelBI/Controllers/RepairApi/SchoolRepController.cs

@@ -581,6 +581,7 @@ namespace TEAMModelBI.Controllers.RepairApi
         public async Task<IActionResult> SetAllProdAnalysis()
         {
             var _azureCosmosClient = _azureCosmos.GetCosmosClient();
+            var _azureCosmosClientCsv2 = _azureCosmos.GetCosmosClient(name: "CoreServiceV2");
             var _azureCosmosClientCsv2Read = _azureCosmos.GetCosmosClient(name: "CoreServiceV2CnRead");
             var datetime = DateTimeOffset.UtcNow;
             var y = $"{datetime.Year}";
@@ -608,7 +609,7 @@ namespace TEAMModelBI.Controllers.RepairApi
                     {
                         string m = date.Substring(0, 2);
                         string d = date.Substring(2, 2);
-                        await BIProdAnalysis.BICreatDailyAnalData(_azureRedis, _azureCosmosClient, _azureCosmosClientCsv2Read, _dingDing, y, m, d);
+                        await BIProdAnalysis.BICreatDailyAnalData(_azureRedis, _azureCosmosClient, _azureCosmosClientCsv2, _azureCosmosClientCsv2Read, _dingDing, y, m, d);
                         resultKeys.Add($"{key}");
                     }
                 }

+ 0 - 113
TEAMModelBI/Properties/ServiceDependencies/teammodelbi-rc - Web Deploy/profile.arm.json

@@ -1,113 +0,0 @@
-{
-  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
-  "contentVersion": "1.0.0.0",
-  "metadata": {
-    "_dependencyType": "compute.appService.windows"
-  },
-  "parameters": {
-    "resourceGroupName": {
-      "type": "string",
-      "defaultValue": "TEAMModelChengdu",
-      "metadata": {
-        "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
-      }
-    },
-    "resourceGroupLocation": {
-      "type": "string",
-      "defaultValue": "",
-      "metadata": {
-        "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
-      }
-    },
-    "resourceName": {
-      "type": "string",
-      "defaultValue": "rc",
-      "metadata": {
-        "description": "Name of the main resource to be created by this template."
-      }
-    },
-    "resourceLocation": {
-      "type": "string",
-      "defaultValue": "[parameters('resourceGroupLocation')]",
-      "metadata": {
-        "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
-      }
-    }
-  },
-  "variables": {
-    "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-    "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]"
-  },
-  "resources": [
-    {
-      "type": "Microsoft.Resources/resourceGroups",
-      "name": "[parameters('resourceGroupName')]",
-      "location": "[parameters('resourceGroupLocation')]",
-      "apiVersion": "2019-10-01"
-    },
-    {
-      "type": "Microsoft.Resources/deployments",
-      "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-      "resourceGroup": "[parameters('resourceGroupName')]",
-      "apiVersion": "2019-10-01",
-      "dependsOn": [
-        "[parameters('resourceGroupName')]"
-      ],
-      "properties": {
-        "mode": "Incremental",
-        "template": {
-          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
-          "contentVersion": "1.0.0.0",
-          "resources": [
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[parameters('resourceName')]",
-              "type": "Microsoft.Web/sites",
-              "apiVersion": "2015-08-01",
-              "tags": {
-                "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
-              },
-              "dependsOn": [
-                "[variables('appServicePlan_ResourceId')]"
-              ],
-              "kind": "app",
-              "properties": {
-                "name": "[parameters('resourceName')]",
-                "kind": "app",
-                "httpsOnly": true,
-                "reserved": false,
-                "serverFarmId": "[variables('appServicePlan_ResourceId')]",
-                "siteConfig": {
-                  "metadata": [
-                    {
-                      "name": "CURRENT_STACK",
-                      "value": "dotnetcore"
-                    }
-                  ]
-                }
-              },
-              "identity": {
-                "type": "SystemAssigned"
-              }
-            },
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[variables('appServicePlan_name')]",
-              "type": "Microsoft.Web/serverFarms",
-              "apiVersion": "2015-08-01",
-              "sku": {
-                "name": "S1",
-                "tier": "Standard",
-                "family": "S",
-                "size": "S1"
-              },
-              "properties": {
-                "name": "[variables('appServicePlan_name')]"
-              }
-            }
-          ]
-        }
-      }
-    }
-  ]
-}

+ 3 - 3
TEAMModelBI/TEAMModelBI.csproj

@@ -65,9 +65,9 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2310.25</Version>
-		<AssemblyVersion>5.2310.25.1</AssemblyVersion>
-		<FileVersion>5.2310.25.1</FileVersion>
+		<Version>5.2402.28</Version>
+		<AssemblyVersion>5.2402.28.1</AssemblyVersion>
+		<FileVersion>5.2402.28.1</FileVersion>
 		<Description>TEAMModelBI(BI)</Description>
 		<PackageReleaseNotes>BI版本说明版本切换标记2022000908</PackageReleaseNotes>
 		<PackageId>TEAMModelBI</PackageId>

+ 131 - 0
TEAMModelBI/Tool/Extension/GeoRegion.cs

@@ -0,0 +1,131 @@
+using Microsoft.IdentityModel.Tokens;
+using System;
+using System.Collections.Generic;
+using System.Drawing.Drawing2D;
+using System.IdentityModel.Tokens.Jwt;
+using System.IO;
+using System.Text;
+using System.Text.Json;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models.Cosmos.BI;
+
+namespace TEAMModelBI.Models.Extension
+{
+    public static class GeoRegion
+    {
+        //取得國省市區地理資料架構
+        public static regiondata GetRegionData()
+        {
+            regiondata region = new regiondata();
+            //國際
+            var regionTw = new List<regionrow>();
+            using (StreamReader r = new StreamReader("JsonFile/Region/region_gl.json"))
+            {
+                string json = r.ReadToEnd();
+                regionTw = JsonSerializer.Deserialize<List<regionrow>>(json);
+                foreach (regionrow itemcy in regionTw)
+                {
+                    //country
+                    string countryCode = itemcy.code;
+                    if (!region.country.ContainsKey(countryCode))
+                    {
+                        region.country.Add(countryCode, new regionbase() { code = countryCode, name = itemcy.name });
+                    }
+                    //province 無
+                    //city
+                    if (itemcy.children != null)
+                    {
+                        foreach (JsonElement itemcyChild in itemcy.children)
+                        {
+                            regionrow itemct = itemcyChild.ToObject<regionrow>();
+                            string provinceCode = "tw"; //台灣的省代碼用"tw"
+                            string cityCode = itemct.code;
+                            if (!region.city.ContainsKey(countryCode)) region.city.Add(countryCode, new Dictionary<string, Dictionary<string, regionbase>>());
+                            if (!region.city[countryCode].ContainsKey(provinceCode)) region.city[countryCode].Add(provinceCode, new Dictionary<string, regionbase>());
+                            if (!region.city[countryCode][provinceCode].ContainsKey(cityCode)) region.city[countryCode][provinceCode].Add(cityCode, new regionbase() { code = cityCode, name = itemct.name });
+                            //dist
+                            if (itemct.children != null)
+                            {
+                                foreach (JsonElement itemctChild in itemct.children)
+                                {
+                                    regionrow itemds = itemctChild.ToObject<regionrow>();
+                                    string distCode = itemds.code;
+                                    if (!region.dist.ContainsKey(countryCode)) region.dist.Add(countryCode, new Dictionary<string, Dictionary<string, Dictionary<string, regionbase>>>());
+                                    if (!region.dist[countryCode].ContainsKey(provinceCode)) region.dist[countryCode].Add(provinceCode, new Dictionary<string, Dictionary<string, regionbase>>());
+                                    if (!region.dist[countryCode][provinceCode].ContainsKey(cityCode)) region.dist[countryCode][provinceCode].Add(cityCode, new Dictionary<string, regionbase>());
+                                    if (!region.dist[countryCode][provinceCode][cityCode].ContainsKey(distCode)) region.dist[countryCode][provinceCode][cityCode].Add(distCode, new regionbase() { code = distCode, name = itemds.name });
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            //大陸
+            var regionCn = new List<regionrow>();
+            using (StreamReader r = new StreamReader("JsonFile/Region/region_cn.json"))
+            {
+                string json = r.ReadToEnd();
+                regionCn = JsonSerializer.Deserialize<List<regionrow>>(json);
+                //country
+                string countryCode = "CN";
+                string countryName = "中国";
+                if (!region.country.ContainsKey(countryCode))
+                {
+                    region.country.Add(countryCode, new regionbase() { code = countryCode, name = countryName });
+                }
+                //province
+                foreach (regionrow itempv in regionCn)
+                {
+                    string provinceCode = itempv.code.Replace("0000", "");
+                    if (!region.province.ContainsKey(countryCode)) region.province.Add(countryCode, new Dictionary<string, regionbase>());
+                    if (!region.province[countryCode].ContainsKey(provinceCode)) region.province[countryCode].Add(provinceCode, new regionbase() { code = provinceCode, name = itempv.name });
+                    //city
+                    if (itempv.children != null)
+                    {
+                        foreach (JsonElement itempvChild in itempv.children)
+                        {
+                            regionrow itemct = itempvChild.ToObject<regionrow>();
+                            string cityCode = itemct.code;
+                            if (!region.city.ContainsKey(countryCode)) region.city.Add(countryCode, new Dictionary<string, Dictionary<string, regionbase>>());
+                            if (!region.city[countryCode].ContainsKey(provinceCode)) region.city[countryCode].Add(provinceCode, new Dictionary<string, regionbase>());
+                            if (!region.city[countryCode][provinceCode].ContainsKey(cityCode)) region.city[countryCode][provinceCode].Add(cityCode, new regionbase() { code = cityCode, name = itemct.name });
+                            //dist
+                            if (itemct.children != null)
+                            {
+                                foreach (JsonElement itemctChild in itemct.children)
+                                {
+                                    regionrow itemds = itemctChild.ToObject<regionrow>();
+                                    string distCode = itemds.code;
+                                    if (!region.dist.ContainsKey(countryCode)) region.dist.Add(countryCode, new Dictionary<string, Dictionary<string, Dictionary<string, regionbase>>>());
+                                    if (!region.dist[countryCode].ContainsKey(provinceCode)) region.dist[countryCode].Add(provinceCode, new Dictionary<string, Dictionary<string, regionbase>>());
+                                    if (!region.dist[countryCode][provinceCode].ContainsKey(cityCode)) region.dist[countryCode][provinceCode].Add(cityCode, new Dictionary<string, regionbase>());
+                                    if (!region.dist[countryCode][provinceCode][cityCode].ContainsKey(distCode)) region.dist[countryCode][provinceCode][cityCode].Add(distCode, new regionbase() { code = distCode, name = itemds.name });
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            return region;
+        }
+
+        public class regiondata
+        {
+            public Dictionary<string, regionbase> country { get; set; } = new();
+            public Dictionary<string, Dictionary<string, regionbase>> province { get; set; } = new();
+            public Dictionary<string, Dictionary<string, Dictionary<string, regionbase>>> city { get; set; } = new();
+            public Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, regionbase>>>> dist { get; set; } = new();
+        }
+        public class regionbase
+        {
+            public string code { get; set; } //代碼
+            public string name { get; set; } //名稱
+        }
+        public class regionrow : regionbase
+        {
+            public List<object> children { get; set; }
+        }
+
+    }
+}

+ 0 - 264
TEAMModelFunction/.gitignore

@@ -1,264 +0,0 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# Azure Functions localsettings file
-local.settings.json
-
-# User-specific files
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Build results
-[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-x64/
-x86/
-bld/
-[Bb]in/
-[Oo]bj/
-[Ll]og/
-
-# Visual Studio 2015 cache/options directory
-.vs/
-# Uncomment if you have tasks that create the project's static files in wwwroot
-#wwwroot/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-# NUNIT
-*.VisualState.xml
-TestResult.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
-
-# DNX
-project.lock.json
-project.fragment.lock.json
-artifacts/
-
-*_i.c
-*_p.c
-*_i.h
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.svclog
-*.scc
-
-# Chutzpah Test files
-_Chutzpah*
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opendb
-*.opensdf
-*.sdf
-*.cachefile
-*.VC.db
-*.VC.VC.opendb
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-*.sap
-
-# TFS 2012 Local Workspace
-$tf/
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# JustCode is a .NET coding add-in
-.JustCode
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-nCrunchTemp_*
-
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings
-# but database connection strings (with potential passwords) will be unencrypted
-#*.pubxml
-*.publishproj
-
-# Microsoft Azure Web App publish settings. Comment the next line if you want to
-# checkin your Azure Web App publish settings, but sensitive information contained
-# in these scripts will be unencrypted
-PublishScripts/
-
-# NuGet Packages
-*.nupkg
-# The packages folder can be ignored because of Package Restore
-**/packages/*
-# except build/, which is used as an MSBuild target.
-!**/packages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
-*.nuget.props
-*.nuget.targets
-
-# Microsoft Azure Build Output
-csx/
-*.build.csdef
-
-# Microsoft Azure Emulator
-ecf/
-rcf/
-
-# Windows Store app package directories and files
-AppPackages/
-BundleArtifacts/
-Package.StoreAssociation.xml
-_pkginfo.txt
-
-# Visual Studio cache files
-# files ending in .cache can be ignored
-*.[Cc]ache
-# but keep track of directories ending in .cache
-!*.[Cc]ache/
-
-# Others
-ClientBin/
-~$*
-*~
-*.dbmdl
-*.dbproj.schemaview
-*.jfm
-*.pfx
-*.publishsettings
-node_modules/
-orleans.codegen.cs
-
-# Since there are multiple workflows, uncomment next line to ignore bower_components
-# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
-#bower_components/
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-
-# SQL Server files
-*.mdf
-*.ldf
-
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# GhostDoc plugin setting file
-*.GhostDoc.xml
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-# Visual Studio LightSwitch build output
-**/*.HTMLClient/GeneratedArtifacts
-**/*.DesktopClient/GeneratedArtifacts
-**/*.DesktopClient/ModelManifest.xml
-**/*.Server/GeneratedArtifacts
-**/*.Server/ModelManifest.xml
-_Pvt_Extensions
-
-# Paket dependency manager
-.paket/paket.exe
-paket-files/
-
-# FAKE - F# Make
-.fake/
-
-# JetBrains Rider
-.idea/
-*.sln.iml
-
-# CodeRush
-.cr/
-
-# Python Tools for Visual Studio (PTVS)
-__pycache__/
-*.pyc

+ 0 - 548
TEAMModelFunction/ActivityHttpTrigger.cs

@@ -1,548 +0,0 @@
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Azure.WebJobs;
-using Microsoft.Azure.WebJobs.Extensions.Http;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Logging;
-using TEAMModelOS.SDK.DI;
-using Azure.Cosmos;
-using System.Text.Json;
-using System.Collections.Generic;
-using TEAMModelOS.SDK.Models;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.Models.Cosmos;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-using System.Linq;
-using TEAMModelOS.Services.Common;
-using TEAMModelOS.SDK.Models.Service;
-using HTEXLib.COMM.Helpers;
-
-namespace TEAMModelFunction
-{
-    public   class ActivityHttpTrigger
-    {
-
-
-        private readonly AzureCosmosFactory _azureCosmos;
-        private readonly DingDing _dingDing;
-        private readonly AzureStorageFactory _azureStorage;
-        private readonly AzureRedisFactory _azureRedis;
-        public ActivityHttpTrigger(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage
-             , AzureRedisFactory azureRedis)
-        {
-            _azureCosmos = azureCosmos;
-            _dingDing = dingDing;
-            _azureStorage = azureStorage;
-            _azureRedis = azureRedis;
-        }
-
-        /// <summary>
-        /// 修复已存在的课程且未初始化学生课程列表的业务。
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("fix-stu-course")]
-        public  async Task<IActionResult> StuCourse([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log)
-        {
-            log.LogInformation("fix-stu-course...");
-            string originCode = await new StreamReader(req.Body).ReadToEndAsync();
-            List<Course> courses = new List<Course>();
-            var client = _azureCosmos.GetCosmosClient();
-            var query = $"select  *  from c ";
-            await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<Course>(queryText: query,
-                    requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Course-{originCode}") }))
-            {
-                courses.Add(item);
-            }
-            await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<Course>(queryText: query,
-                    requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Course-{originCode}") }))
-            {
-                courses.Add(item);
-            }
-            //2.获取课程的id 并尝试添加或移除对应的学生课程记录StuCourse。
-            foreach (var course in courses)
-            {
-                if (course.schedule.IsNotEmpty())
-                {
-                    foreach (var sc in course.schedule)
-                    {
-                        if (!string.IsNullOrEmpty(sc.stulist))
-                        {
-                            (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, new List<string>() { sc.stulist }, course.school);
-                            var addStudentsCls = tchList.FindAll(x => x.type == 2);
-                            var addTmdidsCls = tchList.FindAll(x => x.type == 1);
-                            foreach (var addStu in addStudentsCls)
-                            {
-                                var stuCourse = new StuCourse
-                                {
-                                    id = course.id,
-                                    scode = course.code,
-                                    name = course.name,
-                                    code = $"StuCourse-{course.school}-{addStu.id}",
-                                    scope = course.scope,
-                                    school = course.school,
-                                    creatorId = course.creatorId,
-                                    pk = "StuCourse",
-                                    createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
-                                };
-                                await client.GetContainer("TEAMModelOS", "Student").UpsertItemAsync(stuCourse, new PartitionKey(stuCourse.code));
-                            }
-                            foreach (var addTmd in addTmdidsCls)
-                            {
-                                var tmdCourse = new StuCourse
-                                {
-                                    id = course.id,
-                                    scode = course.code,
-                                    name = course.name,
-                                    code = $"StuCourse-{addTmd}",
-                                    scope = course.scope,
-                                    //school = courseChange.school,
-                                    creatorId = course.creatorId,
-                                    pk = "StuCourse",
-                                    createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
-                                };
-                                await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync(tmdCourse, new PartitionKey(tmdCourse.code));
-                            }
-                        }
-                    }
-                }
-            }
-            return new OkObjectResult(new { });
-        }
-        /// <summary>
-        /// 设置评测未初始化学生列表的
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("fix-exam-activity")]
-        public   async Task<IActionResult> ExamActivity([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,ILogger log)
-        {
-            log.LogInformation("fix-exam-activity...");
-            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
-            List<string> datas = JsonSerializer.Deserialize<List<string>>(requestBody);
-            var client = _azureCosmos.GetCosmosClient();
-           
-            var query = $"select  *  from c ";
-            foreach (string data in datas) {
-                List<ExamInfo> exams = new List<ExamInfo>();
-                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
-                    queryText: query,  requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{data}") }))
-                {
-                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
-                    {
-                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
-                        {
-                            exams.Add(obj.ToObject<ExamInfo>());
-                        }
-                    }
-                }
-                log.LogInformation($"{exams.ToJsonString()}");
-                foreach (var info in exams)
-                {
-                    List<string> classes = ExamService.getClasses(info.classes,info.stuLists);
-                    if (!classes.IsNotEmpty())
-                    {
-                        continue;
-                    }
-                    List<string> sub = new List<string>();
-                    foreach (ExamSubject subject in info.subjects)
-                    {
-                        sub.Add(subject.id);
-                    }
-                    (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, classes, info.school);
-                    var addStudentsCls = tchList.FindAll(x => x.type == 2);
-                    var addTmdidsCls = tchList.FindAll(x => x.type == 1);
-                    List<StuActivity> stuActivities = new List<StuActivity>();
-                    List<StuActivity> tmdActivities = new List<StuActivity>();
-                    if (addTmdidsCls.IsNotEmpty())
-                    {
-                        addTmdidsCls.ForEach(x => {
-                            tmdActivities.Add(new StuActivity
-                            {
-                                pk = "Activity",
-                                id = info.id,
-                                code = $"Activity-{x.id}",
-                                type = "Exam",
-                                name = info.name,
-                                startTime = info.startTime,
-                                endTime = info.endTime,
-                                scode = info.code,
-                                scope = info.scope,
-                                school = info.school,
-                                creatorId = info.creatorId,
-                                subjects = sub,
-                                blob = null,
-                                owner = info.owner,
-                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                taskStatus = -1,
-                                classIds = classes
-
-                            });
-                        });
-                    }
-                    if (addStudentsCls.IsNotEmpty())
-                    {
-                        addStudentsCls.ForEach(x => {
-                            stuActivities.Add(new StuActivity
-                            {
-                                pk = "Activity",
-                                id = info.id,
-                                code = $"Activity-{info.school}-{x.id}",
-                                type = "Exam",
-                                name = info.name,
-                                startTime = info.startTime,
-                                endTime = info.endTime,
-                                scode = info.code,
-                                scope = info.scope,
-                                school = info.school,
-                                creatorId = info.creatorId,
-                                subjects = sub,
-                                blob=null,
-                                owner = info.owner,
-                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                taskStatus = -1,
-                                classIds = classes
-                            });
-                        });
-                    }
-                    await ActivityService.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities,null);
-                }
-            }
-            return new OkObjectResult(new { });
-        }
-        /// <summary>
-        /// 设置投票未初始化学生列表的业务
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("fix-vote-activity")]
-        public async Task<IActionResult> VoteActivity(
-            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
-            ILogger log)
-        {
-
-            log.LogInformation("fix-vote-activity...");
-            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
-            List<string> datas = JsonSerializer.Deserialize<List<string>>(requestBody);
-            var client = _azureCosmos.GetCosmosClient();
-
-            var query = $"select  *  from c ";
-            foreach (string data in datas)
-            {
-                List<Vote> votes = new List<Vote>();
-                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
-                    queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Vote-{data}") }))
-                {
-                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
-                    {
-                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
-                        {
-                            votes.Add(obj.ToObject<Vote>());
-                        }
-                    }
-                }
-                log.LogInformation($"{votes.ToJsonString()}");
-                foreach (var info in votes)
-                {
-                    List<string> classes = ExamService.getClasses(info.classes, info.stuLists);
-                    if (classes.IsNotEmpty())
-                    {
-                        continue;
-                    }
-                    (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, classes, info.school);
-                    var addStudentsCls = tchList.FindAll(x => x.type == 2);
-                    var addTmdidsCls = tchList.FindAll(x => x.type == 1);
-                    List<StuActivity> stuActivities = new List<StuActivity>();
-                    List<StuActivity> tmdActivities = new List<StuActivity>();
-                    if (addTmdidsCls.IsNotEmpty())
-                    {
-                        addTmdidsCls.ForEach(x => {
-                            tmdActivities.Add(new StuActivity
-                            {
-                                pk = "Activity",
-                                id = info.id,
-                                code = $"Activity-{x.id}",
-                                type = "Vote",
-                                name = info.name,
-                                startTime = info.startTime,
-                                endTime = info.endTime,
-                                scode = info.code,
-                                scope = info.scope,
-                                school = info.school,
-                                creatorId = info.creatorId,
-                                subjects = new List<string>() { "" },
-                                blob = null,
-                                owner = info.owner,
-                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                taskStatus = -1,
-                                classIds = classes
-
-                            });
-                        });
-                    }
-                    if (addStudentsCls.IsNotEmpty())
-                    {
-                        addStudentsCls.ForEach(x => {
-                            stuActivities.Add(new StuActivity
-                            {
-                                pk = "Activity",
-                                id = info.id,
-                                code = $"Activity-{info.school}-{x.id}",
-                                type = "Vote",
-                                name = info.name,
-                                startTime = info.startTime,
-                                endTime = info.endTime,
-                                scode = info.code,
-                                scope = info.scope,
-                                school = info.school,
-                                creatorId = info.creatorId,
-                                subjects = new List<string>() { "" },
-                                blob = null,
-                                owner = info.owner,
-                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                taskStatus = -1,
-                                classIds = classes
-                            });
-                        });
-                    }
-                    await ActivityService.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities, null);
-                }
-            }
-            return new OkObjectResult(new { });
-        }
-
-        /// <summary>
-        /// 设置问卷调查未初始化学生列表的业务
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("fix-survey-activity")]
-        public async Task<IActionResult> SurveyActivity(
-            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
-            ILogger log)
-        {
-            log.LogInformation("fix-survey-activity...");
-            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
-            List<string> datas = JsonSerializer.Deserialize<List<string>>(requestBody);
-            var client = _azureCosmos.GetCosmosClient();
-
-            var query = $"select  *  from c ";
-            foreach (string data in datas)
-            {
-                List<Survey> surveys = new List<Survey>();
-                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
-                    queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Survey-{data}") }))
-                {
-                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
-                    {
-                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
-                        {
-                            surveys.Add(obj.ToObject<Survey>());
-                        }
-                    }
-                }
-                log.LogInformation($"{surveys.ToJsonString()}");
-                foreach (var info in surveys)
-                {
-                    List<string> classes = ExamService.getClasses(info.classes, info.stuLists);
-                    if (!classes.IsNotEmpty())
-                    {
-                        continue;
-                    }
-                    (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, classes, info.school);
-                    var addStudentsCls = tchList.FindAll(x => x.type == 2);
-                    var addTmdidsCls = tchList.FindAll(x => x.type == 1);
-                    List<StuActivity> stuActivities = new List<StuActivity>();
-                    List<StuActivity> tmdActivities = new List<StuActivity>();
-                    if (addTmdidsCls.IsNotEmpty())
-                    {
-                        addTmdidsCls.ForEach(x => {
-                            tmdActivities.Add(new StuActivity
-                            {
-                                pk = "Activity",
-                                id = info.id,
-                                code = $"Activity-{x.id}",
-                                type = "Survey",
-                                name = info.name,
-                                startTime = info.startTime,
-                                endTime = info.endTime,
-                                scode = info.code,
-                                scope = info.scope,
-                                school = info.school,
-                                creatorId = info.creatorId,
-                                subjects = new List<string>() { "" },
-                                blob = info.blob,
-                                owner=info.owner,
-                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                taskStatus = -1,
-                                classIds = classes
-
-                            });
-                        });
-                    }
-                    if (addStudentsCls.IsNotEmpty())
-                    {
-                        addStudentsCls.ForEach(x => {
-                            stuActivities.Add(new StuActivity
-                            {
-                                pk = "Activity",
-                                id = info.id,
-                                code = $"Activity-{info.school}-{x.id}",
-                                type = "Survey",
-                                name = info.name,
-                                startTime = info.startTime,
-                                endTime = info.endTime,
-                                scode = info.code,
-                                scope = info.scope,
-                                school = info.school,
-                                creatorId = info.creatorId,
-                                subjects = new List<string>() { "" },
-                                blob=info.blob,
-                                owner = info.owner,
-                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                taskStatus = -1,
-                                classIds = classes
-                            });
-                        });
-                    }
-                    await ActivityService.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities, null);
-                }
-            }
-            return new OkObjectResult(new { });
-        }
-        
-       
-        /// <summary>
-        ///获取单个目录的大小,用于获取评测,试题,试卷,问卷,投票等 文件层级超过两层的文件。
-        ///例如 /exam/uuid/xxx  /item/uuid/xxx   /paper/uuid/xxx  /vote/uuid/xxx  /suervy/uuid/xxx
-        /// {"name":"hbcn","/item/uuid/xxx"}
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("get-prefixsize")]
-        public async Task<IActionResult> GetPrefixsize(
-            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
-            ILogger log)
-        {
-            try {
-                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
-                var data = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(requestBody);
-                if (data.TryGetProperty("name", out JsonElement name) && data.TryGetProperty("root", out JsonElement root))
-                {
-                    var size = await _azureStorage.GetBlobContainerClient($"{name}").GetBlobsSize($"{root}");
-                    return new OkObjectResult(new { size = size });
-                }
-                else
-                {
-                    return new BadRequestResult();
-                }
-            } catch (Exception ex) {
-                await _dingDing.SendBotMsg($"TEAMModelFunction,ActivityHttpTrigger,get-prefixsize()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
-                return new BadRequestResult();
-            }
-
-        }
-        /// <summary>
-        ///获取多个blob路径的文件大小
-        /// {"name":"hbcn","blobs":["/paper/uuid/xxx.json","/paper/uuid/aaa.json"]}
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("used-space")]
-        public async Task<IActionResult> UsedSpace(
-            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
-            ILogger log)
-        {
-            try { 
-                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
-                var data = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(requestBody);
-                if (data.TryGetProperty("name", out JsonElement name) && data.TryGetProperty("blobs", out JsonElement blob))
-                {
-                    List<string> blobs = JsonSerializer.Deserialize<List<string>>(blob.ToJsonString());
-                   var size= await _azureStorage.GetBlobContainerClient($"{name}").GetBlobsSize(blobs);
-                    return new OkObjectResult(new { size = size });
-                }
-                else {
-                    return new BadRequestResult();
-                }
-              
-            } catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"TEAMModelFunction,ActivityHttpTrigger,get-blobsize()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
-                return new BadRequestResult();
-            }
-        }
-        /// <summary>
-        /// 修复容器的内容显示
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("fix-blob-content")]
-        public async Task<IActionResult> FixBlobContent(
-            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
-            ILogger log)
-        {
-            try
-            {
-                var client = _azureCosmos.GetCosmosClient();
-                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
-                var data = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(requestBody);
-                await FixDataService.FixBlobContent(client, _dingDing, _azureStorage, data);
-                return new OkObjectResult(new { });
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"TEAMModelFunction,ActivityHttpTrigger,fix-blob-content()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
-                return new BadRequestResult();
-            }
-        }
-        /// <summary>
-        /// 修复容器的内容显示
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("fix-student-info")]
-        public async Task<IActionResult> FixStudentInfo(
-            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
-            ILogger log)
-        {
-            var client = _azureCosmos.GetCosmosClient();
-            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
-            var data = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(requestBody);
-            await FixDataService.FixStudentInfo(client, _dingDing, _azureStorage, data);
-            return new OkObjectResult(new { });
-        }
-
-        /// <summary>
-        /// 修复评测publish字段内容
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("fix-exam-publish")]
-        public async Task<IActionResult> FixExamPublish(
-            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
-            ILogger log)
-        {
-            var client = _azureCosmos.GetCosmosClient();
-            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
-            var data = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(requestBody);
-            List<string> infos = await FixDataService.FixExamPublish(client, data);
-            return new OkObjectResult(new { infos });
-        }
-    }
-}

+ 0 - 342
TEAMModelFunction/CourseServiceBus.cs

@@ -1,342 +0,0 @@
-using Azure.Cosmos;
-using Microsoft.Azure.WebJobs;
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.Models;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-using HTEXLib.COMM.Helpers;
-using TEAMModelOS.Models;
-using Microsoft.Extensions.Options;
-
-namespace TEAMModelFunction
-{
-    public class CourseServiceBus
-    {
-        private readonly AzureCosmosFactory _azureCosmos;
-        private readonly DingDing _dingDing;
-        private readonly Option _option;
-        public CourseServiceBus(AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option)
-        {
-            _azureCosmos = azureCosmos;
-            _dingDing = dingDing;
-            _option = option?.Value;
-        }
-
-        /// <summary>
-        /// 完善课程变更
-        /// </summary>
-        /// <data msg>
-        /// CourseChange
-        ///// </data>
-        /// <param name="msg"></param>
-        /// <returns></returns>
-        [FunctionName("Course")]
-        public async Task Course([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "course", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
-        {
-            var client = _azureCosmos.GetCosmosClient();
-            try
-            {
-                //await _dingDing.SendBotMsg($"ServiceBus,CourseChange:{msg}", GroupNames.醍摩豆服務運維群組);
-                var jsonMsg = JsonDocument.Parse(msg);
-                CourseChange courseChange = msg.ToObject<CourseChange>();
-                if (courseChange == null)
-                {
-                    return;
-                }
-                foreach (var cls in courseChange.addClass)
-                {
-                    (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, new List<string> { cls }, courseChange.school);
-                    var addStudentsCls = tchList.FindAll(x => x.type == 2);
-                    var addTmdidsCls = tchList.FindAll(x => x.type == 1);
-                    foreach (var stu in addStudentsCls)
-                    {
-                        try
-                        {
-                            ItemResponse<StuCourse> stuCourse = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{courseChange.school}-{stu.id}"));
-                            if (!stuCourse.Value.classId.Contains(cls))
-                            {
-                                stuCourse.Value.classId.Add(cls);
-                            }
-                            await client.GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuCourse>(stuCourse, courseChange.id, new PartitionKey($"StuCourse-{courseChange.school}-{stu.id}"));
-                        }
-                        catch (CosmosException ex)
-                        {
-                            if (ex.Response.Status == 404)
-                            {
-                                var course = new StuCourse
-                                {
-                                    id = courseChange.id,
-                                    scode = courseChange.code,
-                                    name = courseChange.name,
-                                    code = $"StuCourse-{courseChange.school}-{stu.id}",
-                                    scope = courseChange.scope,
-                                    school = courseChange.school,
-                                    creatorId = courseChange.creatorId,
-                                    classId = new List<string> { cls },
-                                    pk = "StuCourse",
-                                    createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
-                                };
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").CreateItemAsync(course, new PartitionKey(course.code));
-
-                            }
-                            else {
-
-                                await _dingDing.SendBotMsg($"OS,{ Environment.GetEnvironmentVariable("Option:Location")},CourseServiceBus -CosmosDB异常\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-                            }
-                        }
-                    }
-                    foreach (var tmd in addTmdidsCls)
-                    {
-                        try
-                        {
-                            ItemResponse<StuCourse> stuCourse = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{tmd.id}"));
-                            if (!stuCourse.Value.classId.Contains(cls))
-                            {
-                                stuCourse.Value.classId.Add(cls);
-                            }
-                            await client.GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuCourse>(stuCourse, courseChange.id, new PartitionKey($"StuCourse-{tmd.id}"));
-                        }
-                        catch (CosmosException ex)
-                        {
-                            if (ex.Response.Status == 404)
-                            {
-                                var course = new StuCourse
-                                {
-                                    id = courseChange.id,
-                                    scode = courseChange.code,
-                                    name = courseChange.name,
-                                    code = $"StuCourse-{tmd.id}",
-                                    scope = courseChange.scope,
-                                    school = courseChange.school,
-                                    creatorId = courseChange.creatorId,
-                                    classId = new List<string> { cls },
-                                    pk = "StuCourse",
-                                    createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
-                                };
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").CreateItemAsync(course, new PartitionKey(course.code));
-                            }
-                            else
-                            {
-
-                                await _dingDing.SendBotMsg($"OS,{ Environment.GetEnvironmentVariable("Option:Location")},CourseServiceBus -CosmosDB异常\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-                            }
-                        }
-                    }
-                }
-
-                foreach (var list in courseChange.addList)
-                {
-                    (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, new List<string> { list }, courseChange.school);
-                    var addStudentsCls = tchList.FindAll(x => x.type == 2);
-                    var addTmdidsCls = tchList.FindAll(x => x.type == 1);
-                    foreach (var stu in addStudentsCls)
-                    {
-                        try
-                        {
-                            ItemResponse<StuCourse> stuCourse = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{stu.code}-{stu.id}"));
-                            if (!stuCourse.Value.stulist.Contains(list))
-                            {
-                                stuCourse.Value.stulist.Add(list);
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuCourse>(stuCourse, courseChange.id, new PartitionKey($"StuCourse-{stu.code}-{stu.id}"));
-                            }
-                        }
-                        catch (CosmosException ex)
-                        {
-                            if (ex.Response.Status == 404)
-                            {
-                                var course = new StuCourse
-                                {
-                                    id = courseChange.id,
-                                    scode = courseChange.code,
-                                    name = courseChange.name,
-                                    code = $"StuCourse-{courseChange.school}-{stu.id}",
-                                    scope = courseChange.scope,
-                                    school = courseChange.school,
-                                    creatorId = courseChange.creatorId,
-                                    stulist = new List<string> { list },
-                                    pk = "StuCourse",
-                                    createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
-                                };
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").CreateItemAsync(course, new PartitionKey(course.code));
-                            }
-                            else
-                            {
-
-                                await _dingDing.SendBotMsg($"OS,{ Environment.GetEnvironmentVariable("Option:Location")},CourseServiceBus -CosmosDB异常\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-                            }
-                        }
-                    }
-                    foreach (var tmd in addTmdidsCls)
-                    {
-                        try
-                        {
-                            ItemResponse<StuCourse> stuCourse = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{tmd.id}"));
-                            if (!stuCourse.Value.stulist.Contains(list))
-                            {
-                                stuCourse.Value.stulist.Add(list);
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuCourse>(stuCourse, courseChange.id, new PartitionKey($"StuCourse-{tmd.id}"));
-                            }
-
-                        }
-                        catch (CosmosException ex)
-                        {
-                            if (ex.Response.Status == 404)
-                            {
-                                var course = new StuCourse
-                                {
-                                    id = courseChange.id,
-                                    scode = courseChange.code,
-                                    name = courseChange.name,
-                                    code = $"StuCourse-{tmd.id}",
-                                    scope = courseChange.scope,
-                                    school = courseChange.school,
-                                    creatorId = courseChange.creatorId,
-                                    stulist = new List<string> { list },
-                                    pk = "StuCourse",
-                                    createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
-                                };
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").CreateItemAsync(course, new PartitionKey(course.code));
-                            }
-                            else
-                            {
-
-                                await _dingDing.SendBotMsg($"OS,{ Environment.GetEnvironmentVariable("Option:Location")},CourseServiceBus -CosmosDB异常\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-                            }
-                        }
-                    }
-                }
-
-                foreach (var delCls in courseChange.delClass)
-                {
-                    (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, new List<string> { delCls }, courseChange.school);
-                    var delStudentsCls = tchList.FindAll(x => x.type == 2);
-                    var delTmdidsCls = tchList.FindAll(x => x.type == 1);
-                    foreach (var stu in delStudentsCls)
-                    {
-                        try
-                        {
-                            ItemResponse<StuCourse> stuCourse = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{courseChange.school}-{stu.id}"));
-
-                            if (stuCourse.Value.classId.Contains(delCls))
-                            {
-                                stuCourse.Value.classId.Remove(delCls);
-                            }
-
-                            if (!stuCourse.Value.classId.IsNotEmpty() && !stuCourse.Value.stulist.IsNotEmpty())
-                            {
-                                //当两个列表都不存在时则直接删除
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").DeleteItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{courseChange.school}-{stu.id}"));
-                            }
-                            else
-                            {
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuCourse>(stuCourse, courseChange.id, new PartitionKey($"StuCourse-{courseChange.school}-{stu.id}"));
-                            }
-
-                        }
-                        catch (CosmosException ex)
-                        {
-                            await _dingDing.SendBotMsg($"OS,{ Environment.GetEnvironmentVariable("Option:Location")},CourseServiceBus -CosmosDB异常\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-                        }
-                    }
-                    foreach (var tmd in delTmdidsCls)
-                    {
-                        try
-                        {
-                            ItemResponse<StuCourse> stuCourse = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{tmd.id}"));
-
-                            if (stuCourse.Value.classId.Contains(delCls))
-                            {
-                                stuCourse.Value.classId.Remove(delCls);
-                            }
-
-                            if (!stuCourse.Value.classId.IsNotEmpty() && !stuCourse.Value.stulist.IsNotEmpty())
-                            {
-                                //当两个列表都不存在时则直接删除
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").DeleteItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{tmd.id}"));
-                            }
-                            else
-                            {
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuCourse>(stuCourse, courseChange.id, new PartitionKey($"StuCourse-{tmd.id}"));
-                            }
-
-                        }
-                        catch (CosmosException ex)
-                        {
-                            await _dingDing.SendBotMsg($"OS,{ Environment.GetEnvironmentVariable("Option:Location")},CourseServiceBus -CosmosDB异常\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-                        }
-                    }
-                }
-                foreach (var delList in courseChange.delList)
-                {
-                    (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, new List<string> { delList }, courseChange.school);
-                    var delStudentsCls = tchList.FindAll(x => x.type == 2);
-                    var delTmdidsCls = tchList.FindAll(x => x.type == 1);
-                    foreach (var stu in delStudentsCls)
-                    {
-                        try
-                        {
-                            ItemResponse<StuCourse> stuCourse = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{courseChange.school}-{stu.id}"));
-
-                            if (stuCourse.Value.stulist.Contains(delList))
-                            {
-                                stuCourse.Value.stulist.Remove(delList);
-                            }
-
-                            if (!stuCourse.Value.classId.IsNotEmpty() && !stuCourse.Value.stulist.IsNotEmpty())
-                            {
-                                //当两个列表都不存在时则直接删除
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").DeleteItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{courseChange.school}-{stu.id}"));
-                            }
-                            else
-                            {
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuCourse>(stuCourse, courseChange.id, new PartitionKey($"StuCourse-{courseChange.school}-{stu.id}"));
-                            }
-
-                        }
-                        catch (CosmosException ex)
-                        {
-                            await _dingDing.SendBotMsg($"OS,{ Environment.GetEnvironmentVariable("Option:Location")},CourseServiceBus -CosmosDB异常\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-                        }
-                    }
-                    foreach (var tmd in delTmdidsCls)
-                    {
-                        try
-                        {
-                            ItemResponse<StuCourse> stuCourse = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{tmd.id}"));
-
-                            if (stuCourse.Value.stulist.Contains(delList))
-                            {
-                                stuCourse.Value.stulist.Remove(delList);
-                            }
-
-                            if (!stuCourse.Value.classId.IsNotEmpty() && !stuCourse.Value.stulist.IsNotEmpty())
-                            {
-                                //当两个列表都不存在时则直接删除
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").DeleteItemAsync<StuCourse>(courseChange.id, new PartitionKey($"StuCourse-{tmd.id}"));
-                            }
-                            else
-                            {
-                                await client.GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<StuCourse>(stuCourse, courseChange.id, new PartitionKey($"StuCourse-{tmd.id}"));
-                            }
-
-                        }
-                        catch (CosmosException ex)
-                        {
-                            await _dingDing.SendBotMsg($"OS,{ Environment.GetEnvironmentVariable("Option:Location")},CourseServiceBus -CosmosDB异常\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-                        }
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"OS,{ Environment.GetEnvironmentVariable("Option:Location")},CourseServiceBus -Course\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-            }
-        }
-    }
-}

+ 0 - 89
TEAMModelFunction/LessonHttpTrigger.cs

@@ -1,89 +0,0 @@
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Azure.WebJobs;
-using Microsoft.Azure.WebJobs.Extensions.Http;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Logging;
-using Newtonsoft.Json;
-using TEAMModelOS.SDK.DI;
-using System.Text.Json;
-using TEAMModelOS.SDK.Models;
-using Azure.Cosmos;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-using System.Collections.Generic;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
-
-namespace TEAMModelFunction
-{
-    public class LessonHttpTrigger
-    {
-        private readonly AzureCosmosFactory _azureCosmos;
-        private readonly DingDing _dingDing;
-        public LessonHttpTrigger(AzureCosmosFactory azureCosmos, DingDing dingDing)
-        {
-            _azureCosmos = azureCosmos;
-            _dingDing = dingDing;
-        }
-        [FunctionName("insert-class-count")]
-        public async Task<IActionResult> Run(
-            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
-            ILogger log)
-        {
-            log.LogInformation("C# HTTP trigger function processed a request.");
-            var client = _azureCosmos.GetCosmosClient();
-            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
-
-            var data = System.Text.Json.JsonSerializer.Deserialize<LessonRecord>(requestBody);
-            /*int day = DateTimeOffset.FromUnixTimeMilliseconds(data.startTime).DayOfYear;
-            int year = DateTimeOffset.FromUnixTimeMilliseconds(data.startTime).Year;
-            int days = DateTimeHelper.getDays(year);
-            //int years = DateTimeOffset.UtcNow.DayOfYear;
-            string tbname = string.Empty;
-            string code = string.Empty;
-            if (data.scope.Equals("school"))
-            {
-                code = $"LessonCount-{data.school}";
-                tbname = "School";
-            }
-            else
-            {
-                code = $"LessonCount";
-                tbname = "Teacher";
-            }
-            var response = await client.GetContainer(Constant.TEAMModelOS, tbname).ReadItemStreamAsync(data.id.ToString(), new PartitionKey(code));
-            if (response.Status == 200)
-            {
-                using var json = await JsonDocument.ParseAsync(response.ContentStream);
-                LessonCount count = json.ToObject<LessonCount>();
-                if (count.courseIds.Count > 0)
-                {
-                    if (!count.courseIds.Contains(data.courseId))
-                    {
-                        count.courseIds.Add(data.courseId);
-                        count.beginCount[day] += 1;
-                    }
-                }
-                await client.GetContainer("TEAMModelOS", tbname).ReplaceItemAsync(count, count.id, new PartitionKey(code));
-            }
-            else
-            {
-                LessonCount count = new LessonCount
-                {
-                    id = data.tmdid,
-                    code = "LessonCount-" + data.school,
-                    year = year
-                };
-                double[] da = new double[days];
-                List<double> list = new List<double>(da);
-                list[day] += 1;
-                count.beginCount.AddRange(list);
-                //count.courseIds.Add(data.courseId);
-                await client.GetContainer("TEAMModelOS", "tbname").CreateItemAsync(count, new PartitionKey(code));
-            }*/
-            return new OkObjectResult(data);
-        }
-    }
-}

+ 0 - 155
TEAMModelFunction/MonitorCosmosDB.cs

@@ -1,155 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Net.Http;
-using System.Text.Json;
-using System.Threading.Tasks;
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using Microsoft.Azure.Documents;
-using Microsoft.Azure.WebJobs;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Logging;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Models;
-
-namespace TEAMModelFunction
-{
-    public class MonitorCosmosDB
-    {
-        private readonly AzureCosmosFactory _azureCosmos;
-        private readonly AzureServiceBusFactory _serviceBus;
-        private readonly AzureStorageFactory _azureStorage;
-        private readonly DingDing _dingDing;
-        private readonly AzureRedisFactory _azureRedis;
-         
-        private   IConfiguration _configuration { get; set; }
-        public MonitorCosmosDB( AzureCosmosFactory azureCosmos, AzureServiceBusFactory azureServiceBus, AzureStorageFactory azureStorage, DingDing dingDing, AzureRedisFactory azureRedis
-            , IConfiguration configuration
-            )
-        {
-            _azureCosmos = azureCosmos;
-            _serviceBus = azureServiceBus;
-            _azureStorage = azureStorage;
-            _dingDing = dingDing;
-            _azureRedis = azureRedis;
-            _configuration = configuration;
-        }
-        //[Function("Common")]
-        //public async Task Common([Microsoft.Azure.Functions.Worker.CosmosDBTriggerAttribute(
-        //    databaseName: "TEAMModelOS",
-        //    containerName: "Common",
-        //    Connection =    "Azure:Cosmos:ConnectionString",
-        //    LeaseContainerName = "leases",
-        //    LeaseContainerPrefix = "TEAMModelOS",
-        //    CreateLeaseContainerIfNotExists =true)]string josn, ILogger log)
-        //{
-        //    IReadOnlyList<Document> inputs = new List<Document>();
-
-
-        [FunctionName("Common")]
-        public async Task Common([Microsoft.Azure.WebJobs.CosmosDBTriggerAttribute(
-                databaseName: "TEAMModelOS",
-                collectionName: "Common",
-                ConnectionStringSetting  =    "Azure:Cosmos:ConnectionString",
-                LeaseCollectionName = "leases",
-                LeaseCollectionPrefix = "TEAMModelOS",
-                CreateLeaseCollectionIfNotExists  =true)]IReadOnlyList<Document> inputs, ILogger log)
-        {
-
-            if (inputs != null && inputs.Count > 0)
-            {
-                log.LogInformation("Documents modified " + inputs.Count);
-                log.LogInformation("First document Id " + inputs[0].Id);
-                var client = _azureCosmos.GetCosmosClient();
-                
-                foreach (var input in inputs)
-                {
-                    string pk = input.GetPropertyValue<string>("pk");
-                    if (!string.IsNullOrWhiteSpace(pk))
-                    {
-                        if (pk.Equals("Receiver", StringComparison.OrdinalIgnoreCase))
-                        { 
-                            ///通知接收者的变更
-                            return;
-                        }
-                        else {
-                            ///活动类型的变更
-                            int ttl = input.GetPropertyValue<int>("ttl");
-                            long stime = input.GetPropertyValue<long>("startTime");
-                            long etime = input.GetPropertyValue<long>("endTime");
-                            string school = input.GetPropertyValue<string>("school");
-                            string code = input.GetPropertyValue<string>("code");
-                            string creatorId = input.GetPropertyValue<string>("creatorId");
-                            string progress = input.GetPropertyValue<string>("progress");
-                            string scope = input.GetPropertyValue<string>("scope");
-                            string name = input.GetPropertyValue<string>("name");
-                            int? status = input.GetPropertyValue<int?>("status");
-                            int? publish = input.GetPropertyValue<int?>("publish");
-                            var data = new TriggerData
-                            {
-                                stime = stime,
-                                etime = etime,
-                                school = school,
-                                code = code,
-                                creatorId = creatorId,
-                                progress = progress,
-                                scope = scope,
-                                ttl = ttl,
-                                id = input.Id,
-                                status = status,
-                                name = name,
-                                publish = publish
-                            };
-#if DEBUG
-                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-CosmosDBTrigger,{pk}触发变更\n{data.ToJsonString()}",
-                                            GroupNames.成都开发測試群組);
-#endif
-                            switch (pk)
-                            {
-                                case "Exam":
-                                  await  TriggerExam.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client, input, code, stime, etime, school);
-                                    break;
-                                case "Vote":
-                                    await TriggerVote.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis, _configuration);
-                                    break;
-                                case "Survey":
-                                    await TriggerSurvey.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis, _configuration);
-                                    break;
-                                case "Correct":
-                                    await TriggerCorrect.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis);
-                                    break;
-                                case "ExamLite":
-                                    await TriggerExamLite.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis, _configuration);
-                                    break;
-                                case "Study":
-                                    await TriggerStudy.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis, _configuration);
-                                    break;
-                                case "Homework":
-                                    await TriggerHomework.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis, _configuration);
-                                    break;
-
-                            }
-
-                        }
-                        
-                    }
-                }
-            }
-        }
-    }
-    public class TriggerData {
-        public int? status { get; set; }
-        public string name { get; set; }
-        public long stime { get; set; }
-        public long etime { get; set; }
-        public string school { get; set; }
-        public string code { get; set; }
-        public string creatorId { get; set; }
-        public string progress { get; set; }
-        public string scope { get; set; }
-        public int ttl { get; set; }
-        public string id { get; set; }
-        public int? publish { get; set; }
-    }
-}

File diff suppressed because it is too large
+ 0 - 1033
TEAMModelFunction/MonitorServicesBus.cs


+ 0 - 175
TEAMModelFunction/Properties/ServiceDependencies/TEAMModelOSFunction - Zip Deploy/profile.arm.json

@@ -1,175 +0,0 @@
-{
-  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
-  "contentVersion": "1.0.0.0",
-  "metadata": {
-    "_dependencyType": "function.windows.appService"
-  },
-  "parameters": {
-    "resourceGroupName": {
-      "type": "string",
-      "defaultValue": "TEAMModelChengdu",
-      "metadata": {
-        "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
-      }
-    },
-    "resourceGroupLocation": {
-      "type": "string",
-      "defaultValue": "",
-      "metadata": {
-        "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
-      }
-    },
-    "resourceName": {
-      "type": "string",
-      "defaultValue": "TEAMModelOSFunction",
-      "metadata": {
-        "description": "Name of the main resource to be created by this template."
-      }
-    },
-    "resourceLocation": {
-      "type": "string",
-      "defaultValue": "[parameters('resourceGroupLocation')]",
-      "metadata": {
-        "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
-      }
-    }
-  },
-  "resources": [
-    {
-      "type": "Microsoft.Resources/resourceGroups",
-      "name": "[parameters('resourceGroupName')]",
-      "location": "[parameters('resourceGroupLocation')]",
-      "apiVersion": "2019-10-01"
-    },
-    {
-      "type": "Microsoft.Resources/deployments",
-      "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-      "resourceGroup": "[parameters('resourceGroupName')]",
-      "apiVersion": "2019-10-01",
-      "dependsOn": [
-        "[parameters('resourceGroupName')]"
-      ],
-      "properties": {
-        "mode": "Incremental",
-        "expressionEvaluationOptions": {
-          "scope": "inner"
-        },
-        "parameters": {
-          "resourceGroupName": {
-            "value": "[parameters('resourceGroupName')]"
-          },
-          "resourceGroupLocation": {
-            "value": "[parameters('resourceGroupLocation')]"
-          },
-          "resourceName": {
-            "value": "[parameters('resourceName')]"
-          },
-          "resourceLocation": {
-            "value": "[parameters('resourceLocation')]"
-          }
-        },
-        "template": {
-          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
-          "contentVersion": "1.0.0.0",
-          "parameters": {
-            "resourceGroupName": {
-              "type": "string"
-            },
-            "resourceGroupLocation": {
-              "type": "string"
-            },
-            "resourceName": {
-              "type": "string"
-            },
-            "resourceLocation": {
-              "type": "string"
-            }
-          },
-          "variables": {
-            "storage_name": "[toLower(concat('storage', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId))))]",
-            "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-            "storage_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Storage/storageAccounts/', variables('storage_name'))]",
-            "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]",
-            "function_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/sites/', parameters('resourceName'))]"
-          },
-          "resources": [
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[parameters('resourceName')]",
-              "type": "Microsoft.Web/sites",
-              "apiVersion": "2015-08-01",
-              "tags": {
-                "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
-              },
-              "dependsOn": [
-                "[variables('appServicePlan_ResourceId')]",
-                "[variables('storage_ResourceId')]"
-              ],
-              "kind": "functionapp",
-              "properties": {
-                "name": "[parameters('resourceName')]",
-                "kind": "functionapp",
-                "httpsOnly": true,
-                "reserved": false,
-                "serverFarmId": "[variables('appServicePlan_ResourceId')]",
-                "siteConfig": {
-                  "alwaysOn": true
-                }
-              },
-              "identity": {
-                "type": "SystemAssigned"
-              },
-              "resources": [
-                {
-                  "name": "appsettings",
-                  "type": "config",
-                  "apiVersion": "2015-08-01",
-                  "dependsOn": [
-                    "[variables('function_ResourceId')]"
-                  ],
-                  "properties": {
-                    "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
-                    "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
-                    "FUNCTIONS_EXTENSION_VERSION": "~3",
-                    "FUNCTIONS_WORKER_RUNTIME": "dotnet"
-                  }
-                }
-              ]
-            },
-            {
-              "location": "[parameters('resourceGroupLocation')]",
-              "name": "[variables('storage_name')]",
-              "type": "Microsoft.Storage/storageAccounts",
-              "apiVersion": "2017-10-01",
-              "tags": {
-                "[concat('hidden-related:', concat('/providers/Microsoft.Web/sites/', parameters('resourceName')))]": "empty"
-              },
-              "properties": {
-                "supportsHttpsTrafficOnly": true
-              },
-              "sku": {
-                "name": "Standard_LRS"
-              },
-              "kind": "Storage"
-            },
-            {
-              "location": "[parameters('resourceGroupLocation')]",
-              "name": "[variables('appServicePlan_name')]",
-              "type": "Microsoft.Web/serverFarms",
-              "apiVersion": "2015-08-01",
-              "sku": {
-                "name": "S1",
-                "tier": "Standard",
-                "family": "S",
-                "size": "S1"
-              },
-              "properties": {
-                "name": "[variables('appServicePlan_name')]"
-              }
-            }
-          ]
-        }
-      }
-    }
-  ]
-}

+ 0 - 113
TEAMModelFunction/Properties/ServiceDependencies/TEAMModelOSFunction - Zip 部署/profile.arm.json

@@ -1,113 +0,0 @@
-{
-  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
-  "contentVersion": "1.0.0.0",
-  "metadata": {
-    "_dependencyType": "appService.windows"
-  },
-  "parameters": {
-    "resourceGroupName": {
-      "type": "string",
-      "defaultValue": "TEAMModelChengdu",
-      "metadata": {
-        "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
-      }
-    },
-    "resourceGroupLocation": {
-      "type": "string",
-      "defaultValue": "",
-      "metadata": {
-        "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
-      }
-    },
-    "resourceName": {
-      "type": "string",
-      "defaultValue": "TEAMModelOSFunction",
-      "metadata": {
-        "description": "Name of the main resource to be created by this template."
-      }
-    },
-    "resourceLocation": {
-      "type": "string",
-      "defaultValue": "[parameters('resourceGroupLocation')]",
-      "metadata": {
-        "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
-      }
-    }
-  },
-  "variables": {
-    "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-    "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]"
-  },
-  "resources": [
-    {
-      "type": "Microsoft.Resources/resourceGroups",
-      "name": "[parameters('resourceGroupName')]",
-      "location": "[parameters('resourceGroupLocation')]",
-      "apiVersion": "2019-10-01"
-    },
-    {
-      "type": "Microsoft.Resources/deployments",
-      "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-      "resourceGroup": "[parameters('resourceGroupName')]",
-      "apiVersion": "2019-10-01",
-      "dependsOn": [
-        "[parameters('resourceGroupName')]"
-      ],
-      "properties": {
-        "mode": "Incremental",
-        "template": {
-          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
-          "contentVersion": "1.0.0.0",
-          "resources": [
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[parameters('resourceName')]",
-              "type": "Microsoft.Web/sites",
-              "apiVersion": "2015-08-01",
-              "tags": {
-                "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
-              },
-              "dependsOn": [
-                "[variables('appServicePlan_ResourceId')]"
-              ],
-              "kind": "app",
-              "properties": {
-                "name": "[parameters('resourceName')]",
-                "kind": "app",
-                "httpsOnly": true,
-                "reserved": false,
-                "serverFarmId": "[variables('appServicePlan_ResourceId')]",
-                "siteConfig": {
-                  "metadata": [
-                    {
-                      "name": "CURRENT_STACK",
-                      "value": "dotnetcore"
-                    }
-                  ]
-                }
-              },
-              "identity": {
-                "type": "SystemAssigned"
-              }
-            },
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[variables('appServicePlan_name')]",
-              "type": "Microsoft.Web/serverFarms",
-              "apiVersion": "2015-08-01",
-              "sku": {
-                "name": "S1",
-                "tier": "Standard",
-                "family": "S",
-                "size": "S1"
-              },
-              "properties": {
-                "name": "[variables('appServicePlan_name')]"
-              }
-            }
-          ]
-        }
-      }
-    }
-  ]
-}

+ 0 - 113
TEAMModelFunction/Properties/ServiceDependencies/TEAMModelOSFunction - 压缩部署/profile.arm.json

@@ -1,113 +0,0 @@
-{
-  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
-  "contentVersion": "1.0.0.0",
-  "metadata": {
-    "_dependencyType": "appService.windows"
-  },
-  "parameters": {
-    "resourceGroupName": {
-      "type": "string",
-      "defaultValue": "TEAMModelChengdu",
-      "metadata": {
-        "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
-      }
-    },
-    "resourceGroupLocation": {
-      "type": "string",
-      "defaultValue": "",
-      "metadata": {
-        "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
-      }
-    },
-    "resourceName": {
-      "type": "string",
-      "defaultValue": "TEAMModelOSFunction",
-      "metadata": {
-        "description": "Name of the main resource to be created by this template."
-      }
-    },
-    "resourceLocation": {
-      "type": "string",
-      "defaultValue": "[parameters('resourceGroupLocation')]",
-      "metadata": {
-        "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
-      }
-    }
-  },
-  "variables": {
-    "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-    "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]"
-  },
-  "resources": [
-    {
-      "type": "Microsoft.Resources/resourceGroups",
-      "name": "[parameters('resourceGroupName')]",
-      "location": "[parameters('resourceGroupLocation')]",
-      "apiVersion": "2019-10-01"
-    },
-    {
-      "type": "Microsoft.Resources/deployments",
-      "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-      "resourceGroup": "[parameters('resourceGroupName')]",
-      "apiVersion": "2019-10-01",
-      "dependsOn": [
-        "[parameters('resourceGroupName')]"
-      ],
-      "properties": {
-        "mode": "Incremental",
-        "template": {
-          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
-          "contentVersion": "1.0.0.0",
-          "resources": [
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[parameters('resourceName')]",
-              "type": "Microsoft.Web/sites",
-              "apiVersion": "2015-08-01",
-              "tags": {
-                "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
-              },
-              "dependsOn": [
-                "[variables('appServicePlan_ResourceId')]"
-              ],
-              "kind": "app",
-              "properties": {
-                "name": "[parameters('resourceName')]",
-                "kind": "app",
-                "httpsOnly": true,
-                "reserved": false,
-                "serverFarmId": "[variables('appServicePlan_ResourceId')]",
-                "siteConfig": {
-                  "metadata": [
-                    {
-                      "name": "CURRENT_STACK",
-                      "value": "dotnetcore"
-                    }
-                  ]
-                }
-              },
-              "identity": {
-                "type": "SystemAssigned"
-              }
-            },
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[variables('appServicePlan_name')]",
-              "type": "Microsoft.Web/serverFarms",
-              "apiVersion": "2015-08-01",
-              "sku": {
-                "name": "S1",
-                "tier": "Standard",
-                "family": "S",
-                "size": "S1"
-              },
-              "properties": {
-                "name": "[variables('appServicePlan_name')]"
-              }
-            }
-          ]
-        }
-      }
-    }
-  ]
-}

+ 0 - 175
TEAMModelFunction/Properties/ServiceDependencies/teammodelos-func-v4 - Zip Deploy/profile.arm.json

@@ -1,175 +0,0 @@
-{
-  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
-  "contentVersion": "1.0.0.0",
-  "metadata": {
-    "_dependencyType": "compute.function.windows.appService"
-  },
-  "parameters": {
-    "resourceGroupName": {
-      "type": "string",
-      "defaultValue": "TEAMModelChengdu",
-      "metadata": {
-        "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
-      }
-    },
-    "resourceGroupLocation": {
-      "type": "string",
-      "defaultValue": "",
-      "metadata": {
-        "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
-      }
-    },
-    "resourceName": {
-      "type": "string",
-      "defaultValue": "teammodelos-func-v4",
-      "metadata": {
-        "description": "Name of the main resource to be created by this template."
-      }
-    },
-    "resourceLocation": {
-      "type": "string",
-      "defaultValue": "[parameters('resourceGroupLocation')]",
-      "metadata": {
-        "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
-      }
-    }
-  },
-  "resources": [
-    {
-      "type": "Microsoft.Resources/resourceGroups",
-      "name": "[parameters('resourceGroupName')]",
-      "location": "[parameters('resourceGroupLocation')]",
-      "apiVersion": "2019-10-01"
-    },
-    {
-      "type": "Microsoft.Resources/deployments",
-      "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-      "resourceGroup": "[parameters('resourceGroupName')]",
-      "apiVersion": "2019-10-01",
-      "dependsOn": [
-        "[parameters('resourceGroupName')]"
-      ],
-      "properties": {
-        "mode": "Incremental",
-        "expressionEvaluationOptions": {
-          "scope": "inner"
-        },
-        "parameters": {
-          "resourceGroupName": {
-            "value": "[parameters('resourceGroupName')]"
-          },
-          "resourceGroupLocation": {
-            "value": "[parameters('resourceGroupLocation')]"
-          },
-          "resourceName": {
-            "value": "[parameters('resourceName')]"
-          },
-          "resourceLocation": {
-            "value": "[parameters('resourceLocation')]"
-          }
-        },
-        "template": {
-          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
-          "contentVersion": "1.0.0.0",
-          "parameters": {
-            "resourceGroupName": {
-              "type": "string"
-            },
-            "resourceGroupLocation": {
-              "type": "string"
-            },
-            "resourceName": {
-              "type": "string"
-            },
-            "resourceLocation": {
-              "type": "string"
-            }
-          },
-          "variables": {
-            "storage_name": "[toLower(concat('storage', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId))))]",
-            "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-            "storage_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Storage/storageAccounts/', variables('storage_name'))]",
-            "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]",
-            "function_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/sites/', parameters('resourceName'))]"
-          },
-          "resources": [
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[parameters('resourceName')]",
-              "type": "Microsoft.Web/sites",
-              "apiVersion": "2015-08-01",
-              "tags": {
-                "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
-              },
-              "dependsOn": [
-                "[variables('appServicePlan_ResourceId')]",
-                "[variables('storage_ResourceId')]"
-              ],
-              "kind": "functionapp",
-              "properties": {
-                "name": "[parameters('resourceName')]",
-                "kind": "functionapp",
-                "httpsOnly": true,
-                "reserved": false,
-                "serverFarmId": "[variables('appServicePlan_ResourceId')]",
-                "siteConfig": {
-                  "alwaysOn": true
-                }
-              },
-              "identity": {
-                "type": "SystemAssigned"
-              },
-              "resources": [
-                {
-                  "name": "appsettings",
-                  "type": "config",
-                  "apiVersion": "2015-08-01",
-                  "dependsOn": [
-                    "[variables('function_ResourceId')]"
-                  ],
-                  "properties": {
-                    "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
-                    "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
-                    "FUNCTIONS_EXTENSION_VERSION": "~3",
-                    "FUNCTIONS_WORKER_RUNTIME": "dotnet"
-                  }
-                }
-              ]
-            },
-            {
-              "location": "[parameters('resourceGroupLocation')]",
-              "name": "[variables('storage_name')]",
-              "type": "Microsoft.Storage/storageAccounts",
-              "apiVersion": "2017-10-01",
-              "tags": {
-                "[concat('hidden-related:', concat('/providers/Microsoft.Web/sites/', parameters('resourceName')))]": "empty"
-              },
-              "properties": {
-                "supportsHttpsTrafficOnly": true
-              },
-              "sku": {
-                "name": "Standard_LRS"
-              },
-              "kind": "Storage"
-            },
-            {
-              "location": "[parameters('resourceGroupLocation')]",
-              "name": "[variables('appServicePlan_name')]",
-              "type": "Microsoft.Web/serverFarms",
-              "apiVersion": "2015-08-01",
-              "sku": {
-                "name": "S1",
-                "tier": "Standard",
-                "family": "S",
-                "size": "S1"
-              },
-              "properties": {
-                "name": "[variables('appServicePlan_name')]"
-              }
-            }
-          ]
-        }
-      }
-    }
-  ]
-}

+ 0 - 175
TEAMModelFunction/Properties/ServiceDependencies/teammodelosfunction-test - Zip Deploy/profile.arm.json

@@ -1,175 +0,0 @@
-{
-  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
-  "contentVersion": "1.0.0.0",
-  "metadata": {
-    "_dependencyType": "function.windows.appService"
-  },
-  "parameters": {
-    "resourceGroupName": {
-      "type": "string",
-      "defaultValue": "TEAMModelChengdu",
-      "metadata": {
-        "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
-      }
-    },
-    "resourceGroupLocation": {
-      "type": "string",
-      "defaultValue": "",
-      "metadata": {
-        "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
-      }
-    },
-    "resourceName": {
-      "type": "string",
-      "defaultValue": "test",
-      "metadata": {
-        "description": "Name of the main resource to be created by this template."
-      }
-    },
-    "resourceLocation": {
-      "type": "string",
-      "defaultValue": "[parameters('resourceGroupLocation')]",
-      "metadata": {
-        "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
-      }
-    }
-  },
-  "resources": [
-    {
-      "type": "Microsoft.Resources/resourceGroups",
-      "name": "[parameters('resourceGroupName')]",
-      "location": "[parameters('resourceGroupLocation')]",
-      "apiVersion": "2019-10-01"
-    },
-    {
-      "type": "Microsoft.Resources/deployments",
-      "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-      "resourceGroup": "[parameters('resourceGroupName')]",
-      "apiVersion": "2019-10-01",
-      "dependsOn": [
-        "[parameters('resourceGroupName')]"
-      ],
-      "properties": {
-        "mode": "Incremental",
-        "expressionEvaluationOptions": {
-          "scope": "inner"
-        },
-        "parameters": {
-          "resourceGroupName": {
-            "value": "[parameters('resourceGroupName')]"
-          },
-          "resourceGroupLocation": {
-            "value": "[parameters('resourceGroupLocation')]"
-          },
-          "resourceName": {
-            "value": "[parameters('resourceName')]"
-          },
-          "resourceLocation": {
-            "value": "[parameters('resourceLocation')]"
-          }
-        },
-        "template": {
-          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
-          "contentVersion": "1.0.0.0",
-          "parameters": {
-            "resourceGroupName": {
-              "type": "string"
-            },
-            "resourceGroupLocation": {
-              "type": "string"
-            },
-            "resourceName": {
-              "type": "string"
-            },
-            "resourceLocation": {
-              "type": "string"
-            }
-          },
-          "variables": {
-            "storage_name": "[toLower(concat('storage', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId))))]",
-            "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-            "storage_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Storage/storageAccounts/', variables('storage_name'))]",
-            "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]",
-            "function_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/sites/', parameters('resourceName'))]"
-          },
-          "resources": [
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[parameters('resourceName')]",
-              "type": "Microsoft.Web/sites",
-              "apiVersion": "2015-08-01",
-              "tags": {
-                "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
-              },
-              "dependsOn": [
-                "[variables('appServicePlan_ResourceId')]",
-                "[variables('storage_ResourceId')]"
-              ],
-              "kind": "functionapp",
-              "properties": {
-                "name": "[parameters('resourceName')]",
-                "kind": "functionapp",
-                "httpsOnly": true,
-                "reserved": false,
-                "serverFarmId": "[variables('appServicePlan_ResourceId')]",
-                "siteConfig": {
-                  "alwaysOn": true
-                }
-              },
-              "identity": {
-                "type": "SystemAssigned"
-              },
-              "resources": [
-                {
-                  "name": "appsettings",
-                  "type": "config",
-                  "apiVersion": "2015-08-01",
-                  "dependsOn": [
-                    "[variables('function_ResourceId')]"
-                  ],
-                  "properties": {
-                    "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
-                    "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
-                    "FUNCTIONS_EXTENSION_VERSION": "~3",
-                    "FUNCTIONS_WORKER_RUNTIME": "dotnet"
-                  }
-                }
-              ]
-            },
-            {
-              "location": "[parameters('resourceGroupLocation')]",
-              "name": "[variables('storage_name')]",
-              "type": "Microsoft.Storage/storageAccounts",
-              "apiVersion": "2017-10-01",
-              "tags": {
-                "[concat('hidden-related:', concat('/providers/Microsoft.Web/sites/', parameters('resourceName')))]": "empty"
-              },
-              "properties": {
-                "supportsHttpsTrafficOnly": true
-              },
-              "sku": {
-                "name": "Standard_LRS"
-              },
-              "kind": "Storage"
-            },
-            {
-              "location": "[parameters('resourceGroupLocation')]",
-              "name": "[variables('appServicePlan_name')]",
-              "type": "Microsoft.Web/serverFarms",
-              "apiVersion": "2015-08-01",
-              "sku": {
-                "name": "S1",
-                "tier": "Standard",
-                "family": "S",
-                "size": "S1"
-              },
-              "properties": {
-                "name": "[variables('appServicePlan_name')]"
-              }
-            }
-          ]
-        }
-      }
-    }
-  ]
-}

+ 0 - 175
TEAMModelFunction/Properties/ServiceDependencies/teammodelosfunction__test - 压缩部署/profile.arm.json

@@ -1,175 +0,0 @@
-{
-  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
-  "contentVersion": "1.0.0.0",
-  "metadata": {
-    "_dependencyType": "function.windows.appService"
-  },
-  "parameters": {
-    "resourceGroupName": {
-      "type": "string",
-      "defaultValue": "TEAMModelChengdu",
-      "metadata": {
-        "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
-      }
-    },
-    "resourceGroupLocation": {
-      "type": "string",
-      "defaultValue": "",
-      "metadata": {
-        "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
-      }
-    },
-    "resourceName": {
-      "type": "string",
-      "defaultValue": "test",
-      "metadata": {
-        "description": "Name of the main resource to be created by this template."
-      }
-    },
-    "resourceLocation": {
-      "type": "string",
-      "defaultValue": "[parameters('resourceGroupLocation')]",
-      "metadata": {
-        "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
-      }
-    }
-  },
-  "resources": [
-    {
-      "type": "Microsoft.Resources/resourceGroups",
-      "name": "[parameters('resourceGroupName')]",
-      "location": "[parameters('resourceGroupLocation')]",
-      "apiVersion": "2019-10-01"
-    },
-    {
-      "type": "Microsoft.Resources/deployments",
-      "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-      "resourceGroup": "[parameters('resourceGroupName')]",
-      "apiVersion": "2019-10-01",
-      "dependsOn": [
-        "[parameters('resourceGroupName')]"
-      ],
-      "properties": {
-        "mode": "Incremental",
-        "expressionEvaluationOptions": {
-          "scope": "inner"
-        },
-        "parameters": {
-          "resourceGroupName": {
-            "value": "[parameters('resourceGroupName')]"
-          },
-          "resourceGroupLocation": {
-            "value": "[parameters('resourceGroupLocation')]"
-          },
-          "resourceName": {
-            "value": "[parameters('resourceName')]"
-          },
-          "resourceLocation": {
-            "value": "[parameters('resourceLocation')]"
-          }
-        },
-        "template": {
-          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
-          "contentVersion": "1.0.0.0",
-          "parameters": {
-            "resourceGroupName": {
-              "type": "string"
-            },
-            "resourceGroupLocation": {
-              "type": "string"
-            },
-            "resourceName": {
-              "type": "string"
-            },
-            "resourceLocation": {
-              "type": "string"
-            }
-          },
-          "variables": {
-            "storage_name": "[toLower(concat('storage', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId))))]",
-            "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-            "storage_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Storage/storageAccounts/', variables('storage_name'))]",
-            "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]",
-            "function_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/sites/', parameters('resourceName'))]"
-          },
-          "resources": [
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[parameters('resourceName')]",
-              "type": "Microsoft.Web/sites",
-              "apiVersion": "2015-08-01",
-              "tags": {
-                "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
-              },
-              "dependsOn": [
-                "[variables('appServicePlan_ResourceId')]",
-                "[variables('storage_ResourceId')]"
-              ],
-              "kind": "functionapp",
-              "properties": {
-                "name": "[parameters('resourceName')]",
-                "kind": "functionapp",
-                "httpsOnly": true,
-                "reserved": false,
-                "serverFarmId": "[variables('appServicePlan_ResourceId')]",
-                "siteConfig": {
-                  "alwaysOn": true
-                }
-              },
-              "identity": {
-                "type": "SystemAssigned"
-              },
-              "resources": [
-                {
-                  "name": "appsettings",
-                  "type": "config",
-                  "apiVersion": "2015-08-01",
-                  "dependsOn": [
-                    "[variables('function_ResourceId')]"
-                  ],
-                  "properties": {
-                    "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
-                    "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
-                    "FUNCTIONS_EXTENSION_VERSION": "~3",
-                    "FUNCTIONS_WORKER_RUNTIME": "dotnet"
-                  }
-                }
-              ]
-            },
-            {
-              "location": "[parameters('resourceGroupLocation')]",
-              "name": "[variables('storage_name')]",
-              "type": "Microsoft.Storage/storageAccounts",
-              "apiVersion": "2017-10-01",
-              "tags": {
-                "[concat('hidden-related:', concat('/providers/Microsoft.Web/sites/', parameters('resourceName')))]": "empty"
-              },
-              "properties": {
-                "supportsHttpsTrafficOnly": true
-              },
-              "sku": {
-                "name": "Standard_LRS"
-              },
-              "kind": "Storage"
-            },
-            {
-              "location": "[parameters('resourceGroupLocation')]",
-              "name": "[variables('appServicePlan_name')]",
-              "type": "Microsoft.Web/serverFarms",
-              "apiVersion": "2015-08-01",
-              "sku": {
-                "name": "S1",
-                "tier": "Standard",
-                "family": "S",
-                "size": "S1"
-              },
-              "properties": {
-                "name": "[variables('appServicePlan_name')]"
-              }
-            }
-          ]
-        }
-      }
-    }
-  ]
-}

+ 0 - 8
TEAMModelFunction/Properties/launchSettings.json

@@ -1,8 +0,0 @@
-{
-  "profiles": {
-    "TEAMModelFunction": {
-      "commandName": "Project",
-      "nativeDebugging": false
-    }
-  }
-}

+ 0 - 3
TEAMModelFunction/Properties/serviceDependencies.json

@@ -1,3 +0,0 @@
-{
-  "dependencies": {}
-}

+ 0 - 3
TEAMModelFunction/Properties/serviceDependencies.local.json

@@ -1,3 +0,0 @@
-{
-  "dependencies": {}
-}

+ 0 - 611
TEAMModelFunction/ScsApisHttpTrigger.cs

@@ -1,611 +0,0 @@
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Azure.WebJobs;
-using Microsoft.Azure.WebJobs.Extensions.Http;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Logging;
-using TEAMModelOS.SDK.DI;
-using Azure.Cosmos;
-using System.Text.Json;
-using System.Collections.Generic;
-using TEAMModelOS.SDK.Models;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.Models.Cosmos;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-using System.Linq;
-using TEAMModelOS.Services.Common;
-using TEAMModelOS.SDK.Models.Service;
-using HTEXLib.COMM.Helpers;
-using System.Text;
-using static TEAMModelOS.SDK.Models.Teacher;
-using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
-using Azure.Storage.Blobs.Models;
-
-namespace TEAMModelFunction
-{
-    public class ScsApisHttpTrigger
-    {
-        private readonly AzureCosmosFactory _azureCosmos;
-        private readonly DingDing _dingDing;
-        private readonly AzureStorageFactory _azureStorage;
-        private readonly AzureRedisFactory _azureRedis;
-        private readonly ThirdApisService _thirdApisService;
-        public static string Code { get; set; }
-        public static Dictionary<string, object> parameterMap = null;
-        public ScsApisHttpTrigger(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, ThirdApisService thirdApisService
-             , AzureRedisFactory azureRedis)
-        {
-            _azureCosmos = azureCosmos;
-            _dingDing = dingDing;
-            _azureStorage = azureStorage;
-            _azureRedis = azureRedis;
-            _thirdApisService = thirdApisService;
-        }
-
-        /// <summary>
-        /// 数据推送接口
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("knowledge-change")]
-        public async Task<IActionResult> KnowledgeChange([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log) {
-            string data = await new StreamReader(req.Body).ReadToEndAsync();
-            var  json = JsonDocument.Parse(data).RootElement;
-            List<OldNew> old_new = null;
-            string school = null;
-            if (json.TryGetProperty("school", out JsonElement _school))
-            {
-                school = _school.GetString();
-            }
-            if (json.TryGetProperty("old_new", out JsonElement _old_new))
-            {
-                old_new = _old_new.ToObject<List<OldNew>>();
-            }
-            if (old_new.IsNotEmpty() && !string.IsNullOrWhiteSpace(school))
-            {
-                foreach (var on in old_new)
-                {
-                    List<ItemInfo> items = new List<ItemInfo>();
-                    string sql = $"select value(c) from c    where array_contains(c.knowledge,'{on._old}') ";
-                    await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ItemInfo>
-                        (queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{_school}") }))
-                    {
-                        items.Add(item);
-                    }
-
-                    items.ForEach(item => {
-                        //修改知识点
-                        if (!string.IsNullOrEmpty(on._new))
-                        {
-                            for (int i = 0; i < item.knowledge.Count; i++)
-                            {
-                                if (item.knowledge[i].Equals(on._old))
-                                {
-                                    item.knowledge[i] = on._new;
-                                }
-                            }
-                        }
-                        else
-                        {
-                            //表示删除知识点
-                            item.knowledge.RemoveAll(x => x.Equals(on._old));
-                        }
-                    });
-                    foreach (var item in items)
-                    {
-                        ItemBlob itemBlob = null;
-                        try
-                        {
-                            BlobDownloadInfo blobDownloadResult = await _azureStorage.GetBlobContainerClient($"hbcn").GetBlobClient($"/item/{item.id}/{item.id}.json").DownloadAsync();
-                            if (blobDownloadResult != null)
-                            {
-                                var blob = JsonDocument.Parse(blobDownloadResult.Content);
-                                itemBlob = blob.RootElement.ToObject<ItemBlob>();
-                                itemBlob.exercise.knowledge = item.knowledge;
-                                await _azureStorage.UploadFileByContainer("hbcn", itemBlob.ToJsonString(), "item", $"{item.id}/{item.id}.json", true);
-                            }
-                        }
-                        catch (Exception ex)
-                        {
-                            itemBlob = null;
-                        }
-                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(item, item.id, new PartitionKey(item.code));
-                    }
-                }
-            }
-            return new OkResult();
-        }
-        /// <summary>
-        /// 数据推送接口
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("SchoolDataPush")]
-        public async Task<IActionResult> SchoolDataPush([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log) {
-            var client = _azureCosmos.GetCosmosClient();
-            string data = await new StreamReader(req.Body).ReadToEndAsync();
-            JsonElement accessConfig = data.ToObject<JsonElement>().GetProperty("accessConfig");
-            ScAccessConfig config = $"{accessConfig}".ToObject<ScAccessConfig>();
-            JsonElement school = data.ToObject<JsonElement>().GetProperty("school");
-            StringBuilder queryText = new StringBuilder($"SELECT distinct value(c) FROM c where c.type='yxtrain'");
-            List<GroupList> yxtrain = new List<GroupList>();
-            await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupList>(queryText: queryText.ToString(),
-            requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{school}") }))
-            {
-                yxtrain.Add(item);
-            }
-            List<TeacherTrain> trains = new List<TeacherTrain>();
-            var members = yxtrain.SelectMany(x => x.members).ToList();
-            if (members.IsNotEmpty()) {
-                queryText = new StringBuilder($"SELECT distinct value(c) FROM c where c.type='yxtrain' " +
-                    $"and  c.id in ({string.Join(",", members.Select(x => $"'{x.id}'"))}) ");
-                await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<TeacherTrain>(queryText: queryText.ToString(),
-                requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"TeacherTrain-{school}") }))
-                {
-                    trains.Add(item);
-                }
-            }
-
-            string sql = $" SELECT value(c) FROM c join a in c.binds where ARRAY_LENGTH(c.binds)>0 and a.type='{config.config}' ";
-            List<Teacher> teachers = new List<Teacher>();
-            await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<Teacher>(queryText: sql,
-                requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
-            {
-                teachers.Add(item);
-            }
-            //5.3.1.12学员培训基本情况批量回写-UpdateTeacherListSituation
-            List<TeacherTrain> trains53112OK = new List<TeacherTrain>();
-
-            //5.3.1.13学员能力点测评结果批量回写-UpdateTeacherListDiagnosis
-            List<TeacherTrain> trains53113OK = new List<TeacherTrain>();
-
-            //5.3.1.17学员课堂实录批量回写-UploadKTSLList
-            List<TeacherTrain> trains53117OK = new List<TeacherTrain>();
-
-            //5.3.1.22学员校本教研PDF(每人可以返回多条)批量回写-UploadSBTARPDFListV2
-            List<TeacherTrain> trains53122OK = new List<TeacherTrain>();
-
-            List<KeyValuePair<TeacherTrain,string>> trainsNO = new List<KeyValuePair<TeacherTrain, string>>();
-            List<PushFail> fails= new List<PushFail>();
-            trains.ForEach(x => {
-                var teacher = teachers.Find(t => t.id.Equals(x.id));
-                if (teacher == null)
-                {
-                    fails.Add(new PushFail { tmdid = x.id, msgs = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("tmdid-unexistent", "账号不存在!") } });
-                }
-                else {
-                    List<KeyValuePair<string, string>> msgs = new List<KeyValuePair<string, string>>();
-                    var binddata = teachers.Where(t => t.id.Equals(x.id)).SelectMany(z => z.binds)
-                        .Where(d => d.data.IsNotEmpty()).SelectMany(d => d.data)
-                        .Where(d => string.IsNullOrEmpty(d) && d.Contains(config.config) && d.Contains(config.path));
-                    if (binddata != null && binddata.Count() > 0)
-                    {
-                        var bindData = binddata.First().ToObject<ScBindData>();
-                        if (binddata != null)
-                        {
-                        }
-                        else
-                        {
-                            //如果没有找到绑定信息,则去blob查找。
-                        }
-                    }
-                    else
-                    {
-                        //如果没有找到绑定信息,则去blob查找。
-                    }
-                }
-            });
-            return new OkObjectResult(new { });
-        }
-
-        /// <summary>
-        /// 5.3.1.1获取项目列表
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("GetProjectInfoByTrainComID")]
-        public async Task<IActionResult> GetProjectInfoByTrainComID([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log)
-        {
-            List<ScProject> projects = new List<ScProject>() ;
-            string data = await new StreamReader(req.Body).ReadToEndAsync();
-            JsonElement accessConfig = data.ToObject<JsonElement>().GetProperty("accessConfig");
-            ScAccessConfig config = $"{accessConfig}".ToObject<ScAccessConfig>();
-            Code = "GetProjectInfoByTrainComID";
-            parameterMap = new Dictionary<string, object>();
-            parameterMap.Add("TrainComID", config.trainComID);
-            ScsResult result = new ScsResult { code = Code, title = "5.3.1.1获取项目列表" };
-            try
-            {
-                result = await _thirdApisService.Post(config.url, Code, config.passKey, config.privateKey, parameterMap);
-                if (result.result)
-                {
-                    projects = result.content.ToObject<List<ScProject>>();
-                }
-                else { 
-                
-                }
-                return new OkObjectResult(new { data = projects.ToJsonString() });
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IES5.ScApisService:GetProjectInfoByTrainComID\n{ex.Message}{ex.StackTrace}\n{result.ToJsonString()}\n{data}", GroupNames.成都开发測試群組);
-                return new OkObjectResult(new { data = projects.ToJsonString() });
-            }
-        }
-
-
-        /// <summary>
-        ///  5.3.1.18根据机构ID、项目ID、子项目ID返回学校列表
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("GetSchoolList")]
-        public async Task<IActionResult> GetSchoolList([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log)
-        {
-            List<ScSchool> scSchools = new List<ScSchool>();
-            string data = await new StreamReader(req.Body).ReadToEndAsync();
-            JsonElement accessConfig = data.ToObject<JsonElement>().GetProperty("accessConfig");
-            ScAccessConfig config = $"{accessConfig}".ToObject<ScAccessConfig>();
-            Code = "GetSchoolList";
-            parameterMap = new Dictionary<string, object>();
-            parameterMap.Add("TrainComID", config.trainComID);
-            List<ScsResult> results = new List<ScsResult>();
-            try
-            {
-                if (config.p.IsNotEmpty())
-                {
-                    foreach (var ps in config.p)
-                    {
-                        parameterMap["ProjectID"] = ps.pd;
-                        parameterMap["ProjectItemID"] = ps.pid;
-                        ScsResult result = new ScsResult { code = Code, title = " 5.3.1.18根据机构ID、项目ID、子项目ID返回学校列表" };
-                        result = await _thirdApisService.Post(config.url, Code, config.passKey, config.privateKey, parameterMap);
-                        if (result.result)
-                        {
-                            List<ScSchool> schools = result.content.ToObject<List<ScSchool>>();
-                            if (schools.IsNotEmpty())
-                            {
-                                scSchools.AddRange(schools);
-                            }
-                        }
-                        results.Add(result);
-                    }
-                }
-                return new OkObjectResult(new { data = scSchools.ToJsonString() });
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IES5.ScApisService:GetSchoolList\n{ex.Message}{ex.StackTrace}\n{results.ToJsonString()}\n{data}", GroupNames.成都开发測試群組);
-                return new OkObjectResult(new { data = scSchools.ToJsonString() });
-            }
-        }
-        /// <summary>
-        /// 5.3.1.2获取学员名单
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("GetTeachersListByProject")]
-        public async Task<IActionResult> GetTeachersListByProject([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log)
-        {
-            List<ScTeacher> scTeachers = new List<ScTeacher>();
-            string data = await new StreamReader(req.Body).ReadToEndAsync();
-            JsonElement accessConfig = data.ToObject<JsonElement>().GetProperty("accessConfig");
-            ScAccessConfig config = $"{accessConfig}".ToObject<ScAccessConfig>();
-            Code = "GetTeachersListByProject";
-            parameterMap = new Dictionary<string, object>();
-            parameterMap.Add("TrainComID", config.trainComID);
-            List<ScsResult> results = new List<ScsResult>();
-            try
-            {
-                if (config.p.IsNotEmpty())
-                {
-                    foreach (var ps in config.p)
-                    {
-                        parameterMap["ProjectID"] = ps.pd;
-                        parameterMap["ProjectItemID"] = ps.pid;
-                        ScsResult result = new ScsResult { code = Code, title = "5.3.1.2获取学员名单" };
-                        result = await _thirdApisService.Post(config.url, Code, config.passKey, config.privateKey, parameterMap);
-                        if (result.result)
-                        {
-                            List<ScTeacher> teachers = result.content.ToObject<List<ScTeacher>>();
-                            if (teachers.IsNotEmpty())
-                            {
-                                scTeachers.AddRange(teachers);
-                            }
-                        }
-                        results.Add(result);
-                    }
-                }
-                return new OkObjectResult(new { data = scTeachers.ToJsonString() });
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IES5.ScApisService:GetTeachersListByProject\n{ex.Message}{ex.StackTrace}\n{results.ToJsonString()}\n{data}", GroupNames.成都开发測試群組);
-                return new OkObjectResult(new { data = scTeachers.ToJsonString() });
-            }
-        }
-        /// <summary>
-        /// 5.3.1.20获取学校设置的可选能力点
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("GetSchoolDiagnosis")]
-        public async Task<IActionResult> GetSchoolDiagnosis([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log) {
-            List<ScsProjectDiagnosis> projects = new List<ScsProjectDiagnosis>();
-            string data = await new StreamReader(req.Body).ReadToEndAsync();
-            JsonElement accessConfig = data.ToObject<JsonElement>().GetProperty("accessConfig");
-            JsonElement schoolCode = data.ToObject<JsonElement>().GetProperty("schoolCode");
-            ScAccessConfig config = $"{accessConfig}".ToObject<ScAccessConfig>();
-            Code = "GetSchoolDiagnosis";
-            parameterMap = new Dictionary<string, object>();
-            parameterMap.Add("TrainComID", config.trainComID);
-            List<ScsResult> results = new List<ScsResult>();
-            try
-            {
-                if (config.p.IsNotEmpty())
-                {
-                    foreach (var ps in config.p)
-                    {
-                        parameterMap["ProjectID"] = ps.pd;
-                        parameterMap["ProjectItemID"] = ps.pid;
-                        parameterMap["SchoolID"] = $"{schoolCode}";
-                        parameterMap["School"] = $"{schoolCode}";
-                        ScsResult result = new ScsResult { code = Code, title = " 5.3.1.20获取学校设置的可选能力点" };
-                        result = await _thirdApisService.Post(config.url, Code, config.passKey, config.privateKey, parameterMap);
-                        if (result.result)
-                        {
-                            List<ScPDiagnosis> diagnoses = result.content.ToObject<List<ScPDiagnosis>>();
-                            if (diagnoses.IsNotEmpty())
-                            {
-                                projects.Add(new ScsProjectDiagnosis { project = ps, diagnoses = diagnoses });
-                                await _azureStorage.SaveOrUpdate<ScProjectDiagnosis>(new ScProjectDiagnosis { RowKey = $"{ps.pid}-{schoolCode}", PartitionKey = "ScSchoolDiagnosis", abilityNos = diagnoses.ToJsonString() });
-                            }
-                        }
-                        else
-                        {
-                            List<ScProjectDiagnosis> teacherDiagnoses = await _azureStorage.FindListByDict<ScProjectDiagnosis>(new Dictionary<string, object> { { "PartitionKey", "ScSchoolDiagnosis" }, { "RowKey", $"{ps.pid}-{schoolCode}" } });
-                            if (teacherDiagnoses.IsNotEmpty())
-                            {
-                                projects.Add(new ScsProjectDiagnosis { project = ps, diagnoses = teacherDiagnoses[0].abilityNos.ToObject<List<ScPDiagnosis>>() });
-
-                            }
-                        }
-                        results.Add(result);
-                    }
-                }
-                return new OkObjectResult(new { data = projects.ToJsonString() });
-            }
-            catch (Exception ex)
-            {
-                //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IES5.ScApisService:GetSchoolDiagnosis\n{ex.Message}{ex.StackTrace}\n{results.ToJsonString()}\n{data}", GroupNames.成都开发測試群組);
-
-                if (config.p.IsNotEmpty()) {
-                    foreach (var ps in config.p)
-                    {
-                        List<ScProjectDiagnosis> teacherDiagnoses = await _azureStorage.FindListByDict<ScProjectDiagnosis>(new Dictionary<string, object> { { "PartitionKey", "ScSchoolDiagnosis" }, { "RowKey", $"{ps.pid}-{schoolCode}" } });
-                        if (teacherDiagnoses.IsNotEmpty())
-                        {
-                            projects.Add(new ScsProjectDiagnosis { project = ps, diagnoses = teacherDiagnoses[0].abilityNos.ToObject<List<ScPDiagnosis>>() });
-
-                        }
-                    }
-                }
-                return new OkObjectResult(new { data = projects.ToJsonString() });
-            }
-        }
-        /// <summary>
-        /// 5.3.1.19获取项目设置的可选能力点
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("GetProjectDiagnosis")]
-        public async Task<IActionResult> GetProjectDiagnosis([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log)
-        {
-            List<ScsProjectDiagnosis> projects =  new List<ScsProjectDiagnosis> () ;
-            string data = await new StreamReader(req.Body).ReadToEndAsync();
-            JsonElement accessConfig = data.ToObject<JsonElement>().GetProperty("accessConfig");
-            ScAccessConfig config = $"{accessConfig}".ToObject<ScAccessConfig>();
-            Code = "GetProjectDiagnosis";
-            parameterMap = new Dictionary<string, object>();
-            parameterMap.Add("TrainComID", config.trainComID);
-            List<ScsResult> results = new List<ScsResult>();
-            try
-            {
-                if (config.p.IsNotEmpty())
-                {
-                    foreach (var ps in config.p)
-                    {
-                        parameterMap["ProjectID"] = ps.pd;
-                        parameterMap["ProjectItemID"] = ps.pid;
-                        ScsResult result = new ScsResult { code = Code, title = "5.3.1.19获取项目设置的可选能力点" };
-                        result = await _thirdApisService.Post(config.url, Code, config.passKey, config.privateKey, parameterMap);
-                        if (result.result)
-                        {
-                            List<ScPDiagnosis> diagnoses = result.content.ToObject<List<ScPDiagnosis>>();
-                            if (diagnoses.IsNotEmpty())
-                            {
-                                projects.Add(new ScsProjectDiagnosis { project = ps, diagnoses = diagnoses });
-                                await _azureStorage.SaveOrUpdate<ScProjectDiagnosis>(new ScProjectDiagnosis { RowKey = $"{ps.pid}", PartitionKey = "ScProjectDiagnosis", abilityNos = diagnoses.ToJsonString() });
-                            }
-                        }
-                        else
-                        {
-                            List<ScProjectDiagnosis> teacherDiagnoses = await _azureStorage.FindListByDict<ScProjectDiagnosis>(new Dictionary<string, object> { { "PartitionKey", "ScProjectDiagnosis" }, { "RowKey", $"{ps.pid}" } });
-                            if (teacherDiagnoses.IsNotEmpty())
-                            {
-                                projects.Add(new ScsProjectDiagnosis { project = ps, diagnoses = teacherDiagnoses[0].abilityNos.ToObject<List<ScPDiagnosis>>() });
-
-                            }
-                        }
-                        results.Add(result);
-                    }
-                }
-                return new OkObjectResult(new { data = projects.ToJsonString() });
-            }
-            catch (Exception ex)
-            {
-                if (config.p.IsNotEmpty()) {
-                    foreach (var ps in config.p)
-                    {
-                        //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IES5.ScApisService:GetProjectDiagnosis\n{ex.Message}{ex.StackTrace}\n{results.ToJsonString()}\n{data}", GroupNames.成都开发測試群組);
-                        List<ScProjectDiagnosis> teacherDiagnoses = await _azureStorage.FindListByDict<ScProjectDiagnosis>(new Dictionary<string, object> { { "PartitionKey", "ScProjectDiagnosis" }, { "RowKey", $"{ps.pid}" } });
-                        if (teacherDiagnoses.IsNotEmpty())
-                        {
-                            projects.Add(new ScsProjectDiagnosis { project = ps, diagnoses = teacherDiagnoses[0].abilityNos.ToObject<List<ScPDiagnosis>>() });
-
-                        }
-                    }
-                }
-                return new OkObjectResult(new { data = projects.ToJsonString() });
-            }
-        }
-
-        /// <summary>
-        /// 5.3.1.3通过项目编号获取学员测评能力项V2
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("GetDiagnosisListByProject_V2")]
-        public async Task<IActionResult> GetDiagnosisListByProject_V2([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log) {
-            List<string> abilityNos = new  List<string>();
-            string data = await new StreamReader(req.Body).ReadToEndAsync();
-            JsonElement accessConfig=  data.ToObject<JsonElement>().GetProperty("accessConfig");
-            JsonElement pxid = data.ToObject<JsonElement>().GetProperty("pxid");
-            ScAccessConfig config = $"{accessConfig}".ToObject<ScAccessConfig>();
-            Code = "GetDiagnosisListByProject_V2";
-            parameterMap = new Dictionary<string, object>();
-            parameterMap.Add("TrainComID", config.trainComID);
-            parameterMap.Add("PXID", pxid);
-            ScsResult result = new ScsResult { code = Code, title = "5.3.1.3通过项目编号获取学员测评能力项V2" };
-            try
-            {
-                result = await _thirdApisService.Post(config.url, Code, config.passKey, config.privateKey, parameterMap);
-                if (result.result)
-                {
-                    List<ScDiagnosis> diagnoses = result.content.ToObject<List<ScDiagnosis>>();
-                    if (diagnoses != null)
-                    {
-                        abilityNos = diagnoses.Select(x => x.DiagnosisDicNum).ToList();
-                    }
-                    if (abilityNos .IsNotEmpty()) {
-                        await _azureStorage.SaveOrUpdate<ScTeacherDiagnosis>(new ScTeacherDiagnosis { RowKey = $"{pxid}", PartitionKey = "ScTeacherDiagnosis",abilityNos=abilityNos.ToJsonString() });
-                    }
-                }
-                else {
-
-                    List<ScTeacherDiagnosis> teacherDiagnoses = await _azureStorage.FindListByDict<ScTeacherDiagnosis>(new Dictionary<string, object> { { "PartitionKey", "ScTeacherDiagnosis" },  { "RowKey", $"{pxid}" } });
-                    if (teacherDiagnoses.IsNotEmpty()) {
-                        abilityNos = teacherDiagnoses[0].abilityNos.ToObject<List<string>>();
-                    }
-                }
-                return new  OkObjectResult(new { data= abilityNos .ToJsonString()});
-            }
-            catch (Exception ex)
-            {
-                //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IES5.ScApisService:getDiagnosisListByProject_V2\n{ex.Message}{ex.StackTrace}\n{result.ToJsonString()}\n{data}", GroupNames.成都开发測試群組);
-
-                List<ScTeacherDiagnosis> teacherDiagnoses = await _azureStorage.FindListByDict<ScTeacherDiagnosis>(new Dictionary<string, object> { { "PartitionKey", "ScTeacherDiagnosis" }, { "RowKey", $"{pxid}" } });
-                if (teacherDiagnoses.IsNotEmpty())
-                {
-                    abilityNos = teacherDiagnoses[0].abilityNos.ToObject<List<string>>();
-                }
-                return new OkObjectResult(new { data = abilityNos.ToJsonString() });
-            }
-        }
-        /// <summary>
-        /// 5.3.1.11获取跳转学员信息,用于sso单点,后端验证。
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("GetSingleTeacherByProject")]
-        public async Task<IActionResult> GetSingleTeacherByProject([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log)
-        {
-            string teacher=null;
-            string data = await new StreamReader(req.Body).ReadToEndAsync();
-            JsonElement accessConfig = data.ToObject<JsonElement>().GetProperty("accessConfig");
-            JsonElement pxid = data.ToObject<JsonElement>().GetProperty("pxid");
-            JsonElement tid = data.ToObject<JsonElement>().GetProperty("tid");
-            ScAccessConfig config = $"{accessConfig}".ToObject<ScAccessConfig>();
-            Code = "GetSingleTeacherByProject";
-            parameterMap = new Dictionary<string, object>();
-            parameterMap.Add("TrainComID", config.trainComID);
-            parameterMap.Add("Pxid", $"{pxid}");
-            parameterMap.Add("Tid", $"{tid}");
-            ScsResult result = new ScsResult { code = Code, title = "5.3.1.11获取跳转学员信息,用于sso单点,后端验证。" };
-            try
-            {
-                ///{“result”:true,”reason”:null,”content”:”{“PXID”:””,”TID”:””,”TeacherName”:””,”ProjectTitle”:””,”ProjectItemTitle”:””,”CityName”:””,
-                ///”DisName”:””,”SchoolName”:””,”Sex”:””,”PXXK”:””,”PXXD”:””,”TeacherXK”:””,”TeacherXD”:””,”Email”:””}”,”pagecount”:1}
-                result = await _thirdApisService.Post(config.url, Code, config.passKey, config.privateKey, parameterMap);
-                if (result.result)
-                {
-                      teacher = result.content;
-                }
-                return new OkObjectResult(new {data= teacher });
-            }
-            catch (Exception ex)
-            {
-                //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")},IES5.ScApisService:GetSingleTeacherByProject\n{ex.Message}{ex.StackTrace}\n{result.ToJsonString()}\n{data}", GroupNames.成都开发測試群組);
-                return new OkObjectResult(new { data = teacher });
-            }
-        }
-
-        public (int t53112OK, List<KeyValuePair<string, string>> msgs) check53112(TeacherTrain teacherTrain, List<KeyValuePair<string, string>> msgs)
-        {
-            //校验 基本情况是否满足
-            int t53112OK = 1;
-            if (teacherTrain.finalScore < 0)
-            {
-                msgs.Add(new KeyValuePair<string, string>("finalScore", $"最终评定结果参数:{teacherTrain.finalScore}"));
-                t53112OK = 0;
-            }
-            if (string.IsNullOrEmpty(teacherTrain.summary) || teacherTrain.summary.Length > 300)
-            {
-                string msg = string.IsNullOrEmpty(teacherTrain.summary) ? "未填写" : teacherTrain.summary.Length > 300 ? "字数超过300." : "";
-                msgs.Add(new KeyValuePair<string, string>("summary", $"教师培训总结:{msg}"));
-                t53112OK = 0;
-            }
-            if (teacherTrain.totalTime <= 0)
-            {
-                msgs.Add(new KeyValuePair<string, string>("totalTime", $"未获得学时:{teacherTrain.totalTime}"));
-                t53112OK = 0;
-            }
-            return (t53112OK, msgs);
-        }
-
-        public (int t53112OK, List<KeyValuePair<string, string>> msgs) check53113(TeacherTrain teacherTrain, List<KeyValuePair<string, string>> msgs)
-        {
-            //校验 基本情况是否满足
-            int t53112OK = 1;
-            if (teacherTrain.finalScore < 0)
-            {
-                msgs.Add(new KeyValuePair<string, string>("finalScore", $"最终评定结果参数:{teacherTrain.finalScore}"));
-                t53112OK = 0;
-            }
-            if (string.IsNullOrEmpty(teacherTrain.summary) || teacherTrain.summary.Length > 300)
-            {
-                string msg = string.IsNullOrEmpty(teacherTrain.summary) ? "未填写" : teacherTrain.summary.Length > 300 ? "字数超过300." : "";
-                msgs.Add(new KeyValuePair<string, string>("summary", $"教师培训总结:{msg}"));
-                t53112OK = 0;
-            }
-            if (teacherTrain.totalTime <= 0)
-            {
-                msgs.Add(new KeyValuePair<string, string>("totalTime", $"未获得学时:{teacherTrain.totalTime}"));
-                t53112OK = 0;
-            }
-            return (t53112OK, msgs);
-        }
-    }
-}

+ 0 - 34
TEAMModelFunction/Startup.cs

@@ -1,34 +0,0 @@
-using Microsoft.Azure.Functions.Extensions.DependencyInjection;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using System;
-using System.Collections.Generic;
-using System.Configuration;
-using System.IO;
-using System.Reflection;
-using System.Text;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Models.Service;
-
-[assembly: FunctionsStartup(typeof(TEAMModelFunction.Startup))]
-namespace TEAMModelFunction
-{
-    public class Startup : FunctionsStartup
-    {
-        public override void Configure(IFunctionsHostBuilder builder)
-        {
-            builder.Services.AddHttpClient();
-            builder.Services.AddHttpClient<DingDing>();
-            builder.Services.AddHttpClient<ThirdApisService>();
-            builder.Services.AddHttpClient<NotificationService>();
-            builder.Services.AddAzureServiceBus(Environment.GetEnvironmentVariable("Azure:ServiceBus:ConnectionString"));
-            builder.Services.AddAzureStorage(Environment.GetEnvironmentVariable("Azure:Storage:ConnectionString"));
-            builder.Services.AddAzureCosmos(Environment.GetEnvironmentVariable("Azure:Cosmos:ConnectionString"));
-            builder.Services.AddAzureRedis(Environment.GetEnvironmentVariable("Azure:Redis:ConnectionString"));
-        }
-
-
-    }
-}

+ 0 - 43
TEAMModelFunction/TEAMModelFunction.csproj

@@ -1,43 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-	<PropertyGroup>
-		<TargetFramework>net6.0</TargetFramework>
-		<AzureFunctionsVersion>v4</AzureFunctionsVersion>
-		<!--<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>-->
-		<Version>5.2112.21</Version>
-		<AssemblyVersion>5.2107.29.2</AssemblyVersion>
-		<FileVersion>5.2107.29.2</FileVersion>
-		<!--<OutputType>Exe</OutputType>
-		<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
-		<SignAssembly>true</SignAssembly>-->
-	</PropertyGroup>
-	<!--<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
-		<DefineConstants>DEBUG;TRACE</DefineConstants>
-	</PropertyGroup>-->
-	<ItemGroup>
-		<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.0.1" />
-		<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
-		<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.10" />
-		<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus" Version="5.2.0" />
-		<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Http" Version="3.0.12" />
-		<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="5.0.0" />
-		<!--<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.6.0" />
-		<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.3.0" />
-		<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
-		<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage" Version="5.0.0" />
-		<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.ServiceBus" Version="5.0.0-beta.6" />
-		<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.CosmosDB" Version="4.0.0-preview2" />
-		<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs" Version="5.0.0" />-->
-	</ItemGroup>
-	<ItemGroup>
-		<ProjectReference Include="..\TEAMModelOS.SDK\TEAMModelOS.SDK.csproj" />
-	</ItemGroup>
-	<ItemGroup>
-		<None Update="host.json">
-			<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-		</None>
-		<None Update="local.settings.json">
-			<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-			<CopyToPublishDirectory>Never</CopyToPublishDirectory>
-		</None>
-	</ItemGroup>
-</Project>

+ 0 - 427
TEAMModelFunction/TriggerCorrect.cs

@@ -1,427 +0,0 @@
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using Microsoft.Azure.Documents;
-using System;
-using System.Collections.Generic;
-using System.Text.Json;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.Models;
-using TEAMModelOS.SDK.Models.Cosmos;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-using TEAMModelOS.SDK.Models.Table;
-using HTEXLib.COMM.Helpers;
-using Azure;
-
-namespace TEAMModelFunction
-{
-    public static class TriggerCorrect
-    {
-        public static async Task Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
-           CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis)
-        {
-            if ((tdata.status != null && tdata.status.Value == 404) || tdata.ttl > 0)
-            {
-                return;
-            }
-            var adid = tdata.id;
-            var adcode = "";
-            string blobcntr = null;
-            if (tdata.scope.Equals("school"))
-            {
-                adcode = $"Activity-{tdata.school}";
-                blobcntr = tdata.school;
-            }
-            else
-            {
-                return;
-            }
-            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}阅卷配置【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在执行", GroupNames.成都开发測試群組);
-            try {
-                Correct correct = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Correct>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-
-                if (correct != null)
-                {
-                    string PartitionKey = string.Format("{0}{1}{2}", correct.code, "-", correct.progress);
-                    List<ChangeRecord> correctRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
-                    switch (correct.progress)
-                    {
-                        case "pending":
-                            var messageCorrect = new ServiceBusMessage(new { id = input.Id, progress = "going", code = tdata.code }.ToJsonString());
-                            messageCorrect.ApplicationProperties.Add("name", "Correct");
-                            if (correctRecords.Count > 0)
-                            {
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageCorrect, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), correctRecords[0].sequenceNumber);
-                                correctRecords[0].sequenceNumber = start;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(correctRecords[0]);
-                            }
-                            else
-                            {
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageCorrect, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = start,
-                                    msgId = messageCorrect.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-                            break;
-                        case "going":
-                            //评测id
-                            string eid = correct.id;
-                            //评测的分区键
-                            string ecode = correct.scode;
-                            ExamInfo info = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(input.Id, new Azure.Cosmos.PartitionKey($"{ecode}"));
-                            if (correct.subs.IsNotEmpty())
-                            {
-
-                                foreach (var sub in correct.subs)
-                                {
-                                    ///生成阅卷教师的阅卷任务列表
-                                    if (sub.markers.IsNotEmpty())
-                                    {
-                                        foreach (var marker in sub.markers)
-                                        {
-                                            CorrectTask task = new CorrectTask
-                                            {
-                                                ttl = -1,
-                                                pk = "CorrectTask",
-                                                code = "CorrectTask-" + marker.id,
-
-                                                id = Guid.NewGuid().ToString(),
-                                                //评测id 或者阅卷配置id
-                                                cid = correct.id,
-                                                //科目
-                                                subject = sub.id,
-                                                //科目名称
-                                                subjectName = sub.name,
-                                                //评测code
-                                                ecode = correct.scode,
-                                                //阅卷配置code
-                                                scode = correct.code,
-                                                //任务名称
-                                                name = correct.name,
-                                                progress = "going",
-                                                //开始时间
-                                                startTime = correct.startTime,
-                                                //结束时间
-                                                endTime = correct.endTime,
-                                                //批改数量
-                                                count = marker.count,
-                                                //按题阅卷时,题号
-                                                qu = marker.qu,
-                                                //模块数
-                                                model = sub.model,
-                                                type = 1,
-                                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                                source = info.source
-                                            };
-                                            await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<CorrectTask>(task, new Azure.Cosmos.PartitionKey(task.code));
-                                        }
-                                    }
-
-
-                                    //生成异常卷处理人员
-                                    if (sub.err.IsNotEmpty())
-                                    {
-
-                                        foreach (var tId in sub.err)
-                                        {
-                                            CorrectTask task = new CorrectTask
-                                            {
-                                                ttl = -1,
-                                                pk = "CorrectTask",
-                                                code = "CorrectTask-" + tId,
-
-                                                id = Guid.NewGuid().ToString(),
-                                                //评测id 或者阅卷配置id
-                                                cid = correct.id,
-                                                //科目
-                                                subject = sub.id,
-                                                //科目名称
-                                                subjectName = sub.name,
-                                                //评测code
-                                                ecode = correct.scode,
-                                                //阅卷配置code
-                                                scode = correct.code,
-                                                progress = "going",
-                                                //任务名称
-                                                name = correct.name,
-                                                //开始时间
-                                                startTime = correct.startTime,
-                                                //结束时间
-                                                endTime = correct.endTime,
-                                                //模块数
-                                                model = sub.model,
-                                                type = 2,
-                                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
-                                            };
-                                            await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<CorrectTask>(task, new Azure.Cosmos.PartitionKey(task.code));
-                                        }
-
-
-                                    }
-
-                                    //生成仲裁人员
-
-                                    if (sub.arb.IsNotEmpty())
-                                    {
-
-                                        foreach (var tId in sub.arb)
-                                        {
-                                            CorrectTask task = new CorrectTask
-                                            {
-                                                ttl = -1,
-                                                pk = "CorrectTask",
-                                                code = "CorrectTask-" + tId,
-
-                                                id = Guid.NewGuid().ToString(),
-                                                //评测id 或者阅卷配置id
-                                                cid = correct.id,
-                                                //科目
-                                                subject = sub.id,
-                                                //科目名称
-                                                subjectName = sub.name,
-                                                progress = "going",
-                                                //评测code
-                                                ecode = correct.scode,
-                                                //阅卷配置code
-                                                scode = correct.code,
-                                                //任务名称
-                                                name = correct.name,
-                                                //开始时间
-                                                startTime = correct.startTime,
-                                                //结束时间
-                                                endTime = correct.endTime,
-                                                //模块数
-                                                model = sub.model,
-                                                type = 3,
-                                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
-                                            };
-                                            await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<CorrectTask>(task, new Azure.Cosmos.PartitionKey(task.code));
-                                        }
-
-
-                                    }
-                                    //评测科目
-                                    string subjectId = sub.id;
-                                    //生成临时作答数据存放到redis
-                                    //var redisClient = _azureRedis.GetRedisClient(8);
-                                    //ExamInfo info = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(eid, new Azure.Cosmos.PartitionKey(ecode));
-                                    List<ExamClassResult> classResults = new List<ExamClassResult>();
-                                    //获取原题配分
-                                    int paperIndex = 0;
-                                    foreach (ExamSubject subject in info.subjects)
-                                    {
-                                        if (subject.id.Equals(subjectId))
-                                        {
-                                            break;
-                                        }
-                                        else
-                                        {
-                                            paperIndex++;
-                                        }
-                                    }
-                                    List<double> paperPoint = info.papers[paperIndex].point;
-                                    List<List<string>> ans = info.papers[paperIndex].answers;
-                                    if (info.scope.Equals("school"))
-                                    {
-
-                                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamClassResult>(
-                                        queryText: $"select value(c) from c where c.examId = '{eid}' and c.subjectId = '{subjectId}'",
-                                        requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{info.school}") }))
-                                        {
-                                            classResults.Add(item);
-                                        }
-                                    }
-                                    else
-                                    {
-                                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamClassResult>(
-                                            queryText: $"select value(c) from c where c.examId = '{eid}' and c.subjectId = '{subjectId}'",
-                                            requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{info.creatorId}") }))
-                                        {
-                                            classResults.Add(item);
-                                        }
-                                    }
-                                    List<Task<ItemResponse<Scoring>>> tasks = new List<Task<ItemResponse<Scoring>>>();
-                                    //初始化老师阅卷记录
-                                    //List<string> tmds = new List<string>();
-                                    /*                                List<string> marks = new List<string>();
-                                                                    for (int i = 0; i < correct.num; i++)
-                                                                    {
-                                                                        marks.Add("");
-                                                                    }*/
-                                    foreach (ExamClassResult examClass in classResults)
-                                    {
-                                        foreach (string stuId in examClass.studentIds)
-                                        {
-                                            int index = examClass.studentIds.IndexOf(stuId);
-                                            if (index > -1)
-                                            {
-                                                List<double> scc = examClass.studentScores[index];
-                                                List<Item> items = new List<Item>();
-                                                List<Qs> qss = new List<Qs>();
-                                                int itemIndex = 0;
-                                                foreach (double psc in scc)
-                                                {
-                                                    //初始化异常卷信息,初始化仲裁卷信息
-                                                    Qs qs = new Qs();
-                                                    List<Info> infos = new List<Info>();
-                                                    Item item = new Item
-                                                    {
-                                                        ssc = paperPoint[itemIndex],
-                                                        scores = infos
-                                                    };
-                                                    itemIndex++;
-                                                    items.Add(item);
-                                                    qss.Add(qs);
-                                                }
-                                                //处理学生未作答 生成阅卷数据时 客观题分数为-1的情况
-                                                List<double> scores = new List<double>();
-                                                int n = 0;
-                                                foreach (List<string> answer in ans)
-                                                {
-                                                    var scs = examClass.studentScores[index][n];
-
-                                                    if (answer.Count > 0)
-                                                    {
-                                                        if (scs == -1)
-                                                        {
-                                                            scores.Add(0);
-                                                        }
-                                                        else
-                                                        {
-                                                            scores.Add(scs);
-                                                        }
-                                                    }
-                                                    else
-                                                    {
-                                                        scores.Add(scs);
-                                                    }
-                                                    n++;
-                                                }
-                                                Scoring sc = new Scoring
-                                                {
-                                                    id = Guid.NewGuid().ToString(),
-                                                    code = "Scoring-" + info.school,
-                                                    blob = examClass.studentAnswers[index].Count > 0 ? examClass.studentAnswers[index][0] : "",
-                                                    stuId = stuId,
-                                                    examId = eid,
-                                                    subjectId = subjectId,
-                                                    scores = scores,
-                                                    count = correct.num,
-                                                    //marks = marks,
-                                                    items = items,
-                                                    qs = qss,
-                                                    //endTime = correct.endTime,
-                                                    model = sub.model
-
-                                                };
-                                                tasks.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<Scoring>(sc, new Azure.Cosmos.PartitionKey(sc.code)));
-                                            }
-                                            //tasks.Add(redisClient.HashSetAsync($"Exam:Scoring:{eid}-{subjectId}", stuId, new { tmdId = tmds, ans = examClass.studentAnswers[index].Count > 0 ? examClass.studentAnswers[index][0] : "", score = examClass.studentScores[index] }.ToJsonString()));
-                                        }
-
-                                    }
-                                    await Task.WhenAll(tasks);
-                                }
-                            }
-                            var messageCorrectEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = tdata.code }.ToJsonString());
-                            messageCorrectEnd.ApplicationProperties.Add("name", "Correct");
-                            if (correctRecords.Count > 0)
-                            {
-                                long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageCorrectEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), correctRecords[0].sequenceNumber);
-                                correctRecords[0].sequenceNumber = end;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(correctRecords[0]);
-                            }
-                            else
-                            {
-                                long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageCorrectEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = end,
-                                    msgId = messageCorrectEnd.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-                            break;
-                        case "finish":
-                            foreach (var sub in correct.subs)
-                            {
-                                List<string> ids = new List<string>();
-                                ///阅卷教师的阅卷任务列表
-                                if (sub.markers.IsNotEmpty())
-                                {
-                                    foreach (var marker in sub.markers)
-                                    {
-                                        ids.Add(marker.id);
-                                        //await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<CorrectTask>(task, new Azure.Cosmos.PartitionKey(task.code),new ItemRequestOptions().PostTriggers);
-                                    }
-                                }
-                                //异常卷处理人员
-                                if (sub.err.IsNotEmpty())
-                                {
-
-                                    foreach (var tId in sub.err)
-                                    {
-                                        if (!ids.Contains(tId))
-                                        {
-                                            ids.Add(tId);
-                                        }
-                                    }
-                                }
-
-                                //仲裁人员
-
-                                if (sub.arb.IsNotEmpty())
-                                {
-                                    foreach (var tId in sub.arb)
-                                    {
-                                        if (!ids.Contains(tId))
-                                        {
-                                            ids.Add(tId);
-                                        }
-                                    }
-                                }
-                                List<CorrectTask> corrects = new List<CorrectTask>();
-                                foreach (string id in ids)
-                                {
-                                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<CorrectTask>(
-                                          queryText: $"select value(c) from c where c.cid = '{correct.id}'",
-                                          requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"CorrectTask-{id}") }))
-                                    {
-                                        corrects.Add(item);
-                                    }
-                                }
-                                List<Task<ItemResponse<CorrectTask>>> tasks = new List<Task<ItemResponse<CorrectTask>>>();
-                                foreach (CorrectTask task in corrects)
-                                {
-                                    task.progress = "finish";
-                                    tasks.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync(task, task.id, new Azure.Cosmos.PartitionKey(task.code)));
-                                }
-                                await Task.WhenAll(tasks);
-                            }
-                            break;
-                    }
-                }
-            }
-            catch (CosmosException e)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-CosmosDB异常{e.Message}\n{e.Status}", GroupNames.成都开发測試群組);
-            }
-            catch (Exception e)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-阅卷异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
-            }
-            
-        }
-    }
-}

+ 0 - 997
TEAMModelFunction/TriggerExam.cs

@@ -1,997 +0,0 @@
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using Microsoft.Azure.Documents;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.Models;
-using TEAMModelOS.SDK.Models.Cosmos;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-using TEAMModelOS.SDK.Models.Service;
-using HTEXLib.COMM.Helpers;
-
-namespace TEAMModelFunction
-{
-    public class TriggerExam
-    {
-        public static async Task Trigger(AzureCosmosFactory _azureCosmos, AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
-            CosmosClient client, Document input, string code, long stime, long etime, string school)
-        {
-
-            List<ExamClassResult> examClassResults = new List<ExamClassResult>();
-            List<ExamSubject> examSubjects = new List<ExamSubject>();
-            try
-            {
-                ExamInfo info = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
-                if (info != null)
-                {
-                    if (info.scope.Equals("teacher", StringComparison.OrdinalIgnoreCase) || info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
-                    {
-                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{info.creatorId}") }))
-                        {
-                            using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                            if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
-                            {
-                                foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
-                                {
-                                    examClassResults.Add(obj.ToObject<ExamClassResult>());
-                                }
-                            }
-                        }
-                    }
-                    else
-                    {
-                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{school}") }))
-                        {
-                            using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                            if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
-                            {
-                                foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
-                                {
-                                    examClassResults.Add(obj.ToObject<ExamClassResult>());
-                                }
-                            }
-                        }
-                    }
-
-                    string PartitionKey = string.Format("{0}{1}{2}", info.code, "-", info.progress);
-                    List<ChangeRecord> records = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
-                    //处理科目信息
-                    List<string> sub = new List<string>();
-                    foreach (ExamSubject subject in info.subjects)
-                    {
-                        sub.Add(subject.id);
-                    }
-                    //ChangeRecord record = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ChangeRecord>(input.Id, new Azure.Cosmos.PartitionKey($"{info.progress}"));
-                    switch (info.progress)
-                    {
-                        case "pending":
-                            var message = new ServiceBusMessage(new { id = input.Id, progress = "going", code = code }.ToJsonString());
-                            message.ApplicationProperties.Add("name", "Exam");
-                            if (records.Count > 0)
-                            {
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
-                                records[0].sequenceNumber = start;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
-                                //await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
-                            }
-                            else
-                            {
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
-                                //string pk = String.Format("{0}{1}{2}", info.code, "-", "pending");
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = start,
-                                    msgId = message.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                                //await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
-                            }
-                            break;
-                        case "going":
-
-                            try
-                            {
-                                //处理活动中间件
-                                (List<string> classes, List<RGroupList> members) = await Activity(info, client, _dingDing, sub);
-                                //向学生或醍摩豆账号发起通知
-                                #region
-                                //Notice notice = new Notice()
-                                //{
-                                //    msgId = info.id,
-                                //    creation = info.startTime,
-                                //    expire = info.endTime,
-                                //    creatorId = info.creatorId,
-                                //    stuids = studentss,
-                                //    tmdids = tmdids,
-                                //    type = "notice",//评测参加通知
-                                //    priority = "normal",
-                                //    school = info.school,
-                                //    scope = info.scope,
-                                //    //data = new { }.ToJsonString()
-                                //    body = new Body { sid = info.id, scode = info.code, spk = info.pk, biztype = "exam-join" }
-
-                                //};
-                                //var messageBlob = new ServiceBusMessage(notice.ToJsonString());
-                                //messageBlob.ApplicationProperties.Add("name", "Notice");
-                                //await _serviceBus.GetServiceBusClient().SendMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageBlob);
-                                #endregion
-                                if (examClassResults.Count == 0)
-                                {
-
-                                    foreach (string cla in classes)
-                                    {
-                                        int m = 0;
-                                        foreach (ExamSubject subject in info.subjects)
-                                        {
-                                            string classCode = string.Empty;
-                                            string cname = string.Empty;
-                                            if (string.IsNullOrEmpty(info.school) || !info.scope.Equals("school", StringComparison.OrdinalIgnoreCase))
-                                            {
-                                                classCode = "ExamClassResult-" + info.creatorId;                                               
-                                                //cname = members.Select(m => m.members.Where(c => c.groupId.Equals(cla)).Select(g => g.groupName)).ToString();
-                                            }
-                                            else
-                                            {
-                                                classCode = "ExamClassResult-" + info.school;
-                                                //cname = members.Select(m => m.members.Where(c => c.classId.Equals(cla)).Select(g => g.groupName)).ToString();
-                                            }
-                                            cname = members.Where(m => m.id.Equals(cla)).FirstOrDefault()?.name;
-                                            ExamClassResult result = new ExamClassResult
-                                            {
-                                                code = classCode,
-                                                examId = info.id,
-                                                id = Guid.NewGuid().ToString(),
-                                                subjectId = subject.id,
-                                                year = info.year,
-                                                scope = info.scope,
-                                            };
-                                            result.info.name = cname;
-                                            result.info.id = cla;
-                                            result.info.name = cname;
-                                            List<string> ans = new List<string>();
-                                            List<List<string>> anses = new List<List<string>>();
-                                            List<List<Details>> marks = new List<List<Details>>();
-                                            List<double> ansPoint = new List<double>();
-                                            List<string> ids = new List<string>();
-                                            foreach (double p in info.papers[m].point)
-                                            {
-                                                //Details details = new Details();
-                                                //ans.Add(new List<string>());
-                                                anses.Add(new List<string>());
-                                                marks.Add(new List<Details>());
-                                                ansPoint.Add(-1);
-                                            }
-                                            var sresponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"Class-{info.school}"));
-                                            if (sresponse.Status == 200)
-                                            {
-
-                                                using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
-                                                Class classroom = json.ToObject<Class>();
-                                                School sc = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(info.school, new Azure.Cosmos.PartitionKey("Base"));
-                                                foreach (Period period in sc.period)
-                                                {
-                                                    if (period.id.Equals(classroom.periodId))
-                                                    {
-                                                        foreach (Semester semester in period.semesters)
-                                                        {
-                                                            if (semester.start == 1)
-                                                            {
-                                                                int year = DateTimeOffset.UtcNow.Year;
-                                                                int month = DateTimeOffset.UtcNow.Month;
-                                                                int day = DateTimeOffset.UtcNow.Day;
-                                                                int time = 0;
-                                                                if (month == semester.month)
-                                                                {
-                                                                    time = day >= semester.day ? 0 : 1;
-                                                                }
-                                                                else
-                                                                {
-                                                                    time = month > semester.month ? 0 : 1;
-                                                                }
-                                                                int eyear = year - time;
-                                                                result.gradeId = (eyear - classroom.year).ToString();
-                                                            }
-                                                        }
-                                                    }
-                                                }
-                                                //result.info.id = classroom.id;                                               
-                                                //result.gradeId = classroom.year.ToString();
-                                                //处理班级人数
-                                               /* await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: $"select c.id from c where c.classId = '{classroom.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Base-{info.school}") }))
-                                                {
-                                                    using var json_stu = await JsonDocument.ParseAsync(item.ContentStream);
-                                                    if (json_stu.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
-                                                    {
-                                                        var accounts = json_stu.RootElement.GetProperty("Documents").EnumerateArray();
-                                                        while (accounts.MoveNext())
-                                                        {
-                                                            JsonElement account = accounts.Current;
-                                                            ids.Add(account.GetProperty("id").GetString());
-                                                        }
-                                                    }
-                                                }*/
-                                            }
-                                            /*if (info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
-                                            {
-                                                var stuResponse = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"GroupList"));
-                                                if (stuResponse.Status == 200)
-                                                {
-                                                    using var json = await JsonDocument.ParseAsync(stuResponse.ContentStream);
-                                                    GroupList stuList = json.ToObject<GroupList>();
-                                                    //result.info.id = stuList.id;
-                                                    result.info.name = stuList.name;
-                                                    //处理发布对象为自选名单(个人)
-
-                                                    foreach (Member stus in stuList.members)
-                                                    {
-
-                                                        if (!ids.Contains(stus.id))
-                                                        {
-                                                            ids.Add(stus.id);
-                                                        }
-                                                    }
-                                                }
-                                            }
-                                            else
-                                            {
-                                                var stuResponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"GroupList-{info.school}"));
-                                                if (stuResponse.Status == 200)
-                                                {
-                                                    using var json = await JsonDocument.ParseAsync(stuResponse.ContentStream);
-                                                    GroupList stuList = json.ToObject<GroupList>();
-                                                    //result.info.id = stuList.id;
-                                                    result.info.name = stuList.name;
-                                                    //处理发布对象为自选名单(校本)
-                                                    foreach (Member stus in stuList.members)
-                                                    {
-                                                        if (!ids.Contains(stus.id))
-                                                        {
-                                                            ids.Add(stus.id);
-                                                        }
-                                                    }
-                                                }
-                                            }*/
-                                            ids = members.Where(c => c.id.Equals(cla)).SelectMany( m => m.members).Select(g => g.id).ToList();
-                                            foreach (string stu in ids)
-                                            {
-                                                result.mark.Add(marks);
-                                                result.studentIds.Add(stu);
-                                                result.studentAnswers.Add(ans);
-                                                result.studentScores.Add(ansPoint);
-                                                result.ans.Add(anses);
-                                                result.sum.Add(0);
-                                            }
-
-                                            //result.progress = info.progress;
-                                            result.school = info.school;
-                                            m++;
-                                            await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(result, new Azure.Cosmos.PartitionKey($"{result.code}"));
-                                        }
-                                    }
-
-
-                                }
-                                else
-                                {
-                                    //处理单科结算时科目与试卷信息匹配的问题
-                                    int gno = 0;
-                                    foreach (ExamSubject subject in info.subjects)
-                                    {
-                                        if (subject.classCount == classes.Count)
-                                        {
-                                            await createClassResultAsync(info, examClassResults, subject, gno, _azureCosmos, _dingDing, _azureStorage);
-                                        }
-                                        gno++;
-                                    }
-                                }
-                            }
-                            catch (Exception e)
-                            {
-                                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测going状态异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
-                            }
-                            finally
-                            {
-                                // 发送信息通知
-                                var messageEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
-                                messageEnd.ApplicationProperties.Add("name", "Exam");
-                                if (records.Count > 0)
-                                {
-                                    long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
-                                    records[0].sequenceNumber = end;
-                                    await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
-                                    //await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
-                                }
-                                else
-                                {
-                                    long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                                    //string pk = String.Format("{0}{1}{2}", info.code, "-", "going");
-                                    ChangeRecord changeRecord = new ChangeRecord
-                                    {
-                                        RowKey = input.Id,
-                                        PartitionKey = PartitionKey,
-                                        sequenceNumber = end,
-                                        msgId = messageEnd.MessageId
-                                    };
-                                    await _azureStorage.Save<ChangeRecord>(changeRecord);
-                                    //await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
-                                }
-                            }
-                            break;
-                        case "finish":
-                            int fno = 0;
-                            try
-                            {
-                                //处理活动中间件
-                                await Activity(info, client, _dingDing, sub);
-                                foreach (ExamSubject subject in info.subjects)
-                                {
-                                    await createClassResultAsync(info, examClassResults, subject, fno, _azureCosmos, _dingDing, _azureStorage);
-                                    fno++;
-                                }
-
-                                //计算单次考试简易统计信息
-                                List<ExamResult> examResults = new List<ExamResult>();
-                                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamResult>(
-                                                   queryText: $"select value(c) from c where c.examId  = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamResult-{info.id}") }))
-                                {
-                                    examResults.Add(item);
-                                }
-                                List<Task<ItemResponse<ExamClassResult>>> tasks = new List<Task<ItemResponse<ExamClassResult>>>();
-                                //结算单科单班的标准差和平均分
-                                foreach (ExamClassResult classResult in examClassResults)
-                                {
-                                    //标记单科单班总得分
-                                    double subScore = 0;
-                                    //标准差
-                                    double sPowSum = 0;
-                                    List<double> newSumScore = new List<double>();
-                                    var scount = classResult.studentIds.Count;
-                                    foreach (List<double> sc in classResult.studentScores)
-                                    {
-                                        List<double> newSc = new List<double>();
-                                        foreach (double ssc in sc)
-                                        {
-                                            if (ssc == -1)
-                                            {
-                                                newSc.Add(0);
-                                            }
-                                            else
-                                            {
-                                                newSc.Add(ssc);
-                                            }
-                                        }
-                                        double nc = newSc.Sum();
-                                        newSumScore.Add(nc);
-                                        subScore += nc;
-                                    }
-                                    double rateScore = scount > 0 ? Math.Round(subScore * 1.0 / scount, 2) : 0;
-                                    foreach (double scs in newSumScore)
-                                    {
-                                        sPowSum += Math.Pow(scs - rateScore, 2);
-
-                                    }
-                                    classResult.standard = Math.Round(scount > 0 ? Math.Pow(sPowSum / scount, 0.5) : 0, 2);
-                                    classResult.average = scount > 0 ? Math.Round(subScore / scount, 2) : 0;
-                                    classResult.progress = true;
-                                    tasks.Add(client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(classResult, classResult.id, new Azure.Cosmos.PartitionKey($"{classResult.code}")));
-                                }
-                                await Task.WhenAll(tasks);
-                                //记录某次考试所有学生得分总分
-                                double score = 0;
-                                double allScore = 0;
-                                int stuCount = 0;
-                                //标准差
-                                double powSum = 0;
-                                List<string> losStu = new List<string>();
-                                //先与第一个值取并集
-                                if (examResults.Count > 0)
-                                {
-                                    losStu = losStu.Union(examResults[0].lostStus).ToList();
-                                    foreach (ExamResult examResult in examResults)
-                                    {
-                                        if (info.id == examResult.examId)
-                                        {
-                                            foreach (List<double> sc in examResult.studentScores)
-                                            {
-                                                score += sc.Sum();
-                                            }
-                                            stuCount = examResult.studentIds.Count;
-                                        }
-                                        //powSum += Math.Pow(score - examResult.studentIds.Count > 0 ? Math.Round(score * 1.0 / examResult.studentIds.Count, 2) : 0, 2);
-                                        //取交集
-                                        losStu = losStu.Intersect(examResult.lostStus).ToList();
-                                    }
-                                }
-                                double NewsRateScore = stuCount > 0 ? Math.Round(score * 1.0 / stuCount, 2) : 0;
-                                foreach (PaperSimple simple in info.papers)
-                                {
-                                    allScore += simple.point.Sum();
-                                }
-                                //计算全科标准差
-                                foreach (string id in examResults[0].studentIds)
-                                {
-                                    double sc = 0;
-                                    foreach (ExamResult result in examResults)
-                                    {
-                                        sc += result.studentScores[result.studentIds.IndexOf(id)].Sum();
-                                    }
-                                    powSum += Math.Pow(sc - NewsRateScore, 2);
-                                }
-                                info.standard = Math.Round(examResults[0].studentIds.Count > 0 ? Math.Pow(powSum / examResults[0].studentIds.Count, 0.5) : 0, 2);
-                                double NewsRate = allScore > 0 ? Math.Round(NewsRateScore / allScore * 100, 2) : 0;
-                                info.lostStu = losStu;
-                                /*//补充历史数据的容器名称
-                                if (string.IsNullOrEmpty(info.cn)) {
-                                    if (info.scope.Equals("school"))
-                                    {
-                                        info.cn = info.school;
-                                    }
-                                    else {
-                                        info.cn = info.creatorId;
-                                    }
-                                }*/
-                                //判断均分是否发生变化,便于实时的更新评测基本信息
-                                if (info.sRate != NewsRate || info.average != NewsRateScore)
-                                {
-                                    info.sRate = NewsRate;
-                                    info.average = NewsRateScore;
-                                    await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync<ExamInfo>(info, info.id, new Azure.Cosmos.PartitionKey(info.code));
-                                }
-                            }
-                            catch (Exception e)
-                            {
-                                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测finish状态异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
-                            }
-                            break;
-                    }
-                }
-
-            }
-            catch (CosmosException e)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-CosmosDB异常{e.Message}\n{e.Status}", GroupNames.成都开发測試群組);
-            } catch (Exception e) {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-评测结算异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
-            }
-
-        }
-        //处理全部学生选题计数
-        public static async Task examRecordCount(ExamInfo info, ExamSubject subject, DingDing _dingDing, int no, ExamResult result, List<ExamClassResult> classResults, AzureCosmosFactory _azureCosmos)
-        {
-            try
-            {
-                List<double> scores = new List<double>();
-                foreach (List<double> sc in result.studentScores)
-                {
-                    scores.Add(sc.Sum());
-                }
-                //确定高分组 最低分数
-                scores.Sort((s1, s2) => { return s2.CompareTo(s1); });
-                double rhwCount = Math.Floor(scores.Count * 0.27);
-                double rhw = rhwCount > 0 ? scores[int.Parse(rhwCount.ToString("0"))] : 0;
-                //确定低分组 最高分数
-                //scores.Sort((s1, s2) => { return s1.CompareTo(s2); });
-                double rhlCount = Math.Ceiling(scores.Count * 0.73);
-                double rhl = rhlCount > 0 ? scores[int.Parse(rhlCount.ToString("0")) - 1] : 0;
-                //存放高分组学生ID
-                List<string> phId = new List<string>();
-                List<string> plId = new List<string>();
-                List<List<List<string>>> opth = new List<List<List<string>>>();
-                List<List<List<string>>> optl = new List<List<List<string>>>();
-                await knowledgeCount(info, subject, _dingDing, no, classResults, rhwCount, rhw, rhlCount, rhl, _azureCosmos);
-                await fieldCount(info, subject, _dingDing, no, classResults, rhwCount, rhw, rhlCount, rhl, _azureCosmos);
-                int PHCount = 0;
-                int PLCount = 0;
-                foreach (ExamClassResult classResult in classResults)
-                {
-                    if (classResult.subjectId.Equals(subject.id))
-                    {
-                        foreach (string id in classResult.studentIds)
-                        {
-                            int index = classResult.studentIds.IndexOf(id);
-                            if (classResult.studentScores.Count > 0)
-                            {
-                                if (classResult.studentScores[index].Sum() >= rhw && PHCount < rhwCount)
-                                {
-                                    if (classResult.ans.Count > 0)
-                                    {
-                                        opth.Add(classResult.ans[index]);
-                                        PHCount++;
-                                        continue;
-                                    }
-
-                                }
-                                if (classResult.studentScores[index].Sum() <= rhl && PLCount < (scores.Count - rhlCount))
-                                {
-                                    if (classResult.ans.Count > 0)
-                                    {
-                                        optl.Add(classResult.ans[index]);
-                                        PLCount++;
-                                        continue;
-                                    }
-                                }
-
-                            }
-
-                        }
-                    }
-                }
-                result.phc = getMore(info, no, opth);
-                result.plc = getMore(info, no, optl);
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测作答记录结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
-            }
-        }
-        public static async Task<(List<string> classes, List<RGroupList> members)> Activity(ExamInfo info, CosmosClient client, DingDing _dingDing, List<string> sub) {
-            List<(string pId, List<string> gid)> ps = new List<(string pId, List<string> gid)>();
-            if (info.groupLists.Count > 0)
-            {
-                var group = info.groupLists;
-                foreach (var gp in group)
-                {
-                    foreach (KeyValuePair<string, List<string>> pp in gp)
-                    {
-                        ps.Add((pp.Key, pp.Value));
-                    }
-                }
-            }
-            List<string> classes = ExamService.getClasses(info.classes, info.stuLists);
-            (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, classes, info.school, ps);
-            var addStudentsCls = tchList.FindAll(x => x.type == 2);
-            var addTmdidsCls = tchList.FindAll(x => x.type == 1);
-            List<StuActivity> stuActivities = new List<StuActivity>();
-            List<StuActivity> tmdActivities = new List<StuActivity>();
-            if (addTmdidsCls.IsNotEmpty())
-            {
-                addTmdidsCls.ForEach(x =>
-                {
-                    tmdActivities.Add(new StuActivity
-                    {
-                        pk = "Activity",
-                        id = info.id,
-                        code = $"Activity-{x.id}",
-                        type = "Exam",
-                        name = info.name,
-                        source = info.source,
-                        startTime = info.startTime,
-                        endTime = info.endTime,
-                        scode = info.code,
-                        scope = info.scope,
-                        school = info.school,
-                        creatorId = info.creatorId,
-                        subjects = sub,
-                        blob = null,
-                        owner = info.owner,
-                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                        taskStatus = -1,
-                        classIds = classes
-
-                    });
-                });
-            }
-            if (addStudentsCls.IsNotEmpty())
-            {
-                addStudentsCls.ForEach(x =>
-                {
-                    stuActivities.Add(new StuActivity
-                    {
-                        pk = "Activity",
-                        id = info.id,
-                        code = $"Activity-{x.code.Replace("Base-", "")}-{x.id}",
-                        type = "Exam",
-                        name = info.name,
-                        source = info.source,
-                        startTime = info.startTime,
-                        endTime = info.endTime,
-                        scode = info.code,
-                        scope = info.scope,
-                        school = info.school,
-                        creatorId = info.creatorId,
-                        subjects = sub,
-                        blob = null,
-                        owner = info.owner,
-                        classIds = classes,
-                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                        taskStatus = -1
-                    });
-                });
-            }
-            await ActivityService.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities, null);
-            return (classes, classLists);
-        }
-
-        public static async Task knowledgeCount(ExamInfo info, ExamSubject subject, DingDing _dingDing, int no, List<ExamClassResult> classResults,
-            double rhwCount, double rhw, double rhlCount, double rhl, AzureCosmosFactory _azureCosmos)
-        {
-            try
-            {
-                int phcount = 0;
-                int plcount = 0;
-                //存放并去重知识点
-                HashSet<string> kname = new HashSet<string>();
-                if (info.papers[no].knowledge.Count > 0)
-                {
-                    info.papers[no].knowledge.ForEach(kno =>
-                    {
-                        kno.ForEach(k =>
-                        {
-                            kname.Add(k);
-                        });
-                    });
-                    List<string> knowledgeName = new List<string>();
-                    foreach (string cla in kname)
-                    {
-                        knowledgeName.Add(cla);
-                    }
-                    for (int k = 0; k < knowledgeName.Count; k++)
-                    {
-                        if (null == knowledgeName[k])
-                        {
-                            knowledgeName.Remove(knowledgeName[k]);
-                        }
-                    }
-
-                    foreach (ExamClassResult classResult in classResults)
-                    {
-                        if (classResult.subjectId.Equals(subject.id))
-                        {
-                            //List<int> phc = new List<int>();
-                            List<int> ph = new List<int>();
-                            List<int> pl = new List<int>();
-                            List<int> pc = new List<int>();
-                            List<double> persent = new List<double>();
-                            for (int i = 0; i < knowledgeName.Count; i++)
-                            {
-                                //初始化单个知识点得分
-                                double score = 0;
-                                double allScore = 0;
-                                int n = 0;
-                                int phCount = 0;
-                                int plCount = 0;
-                                int pCount = 0;
-                                foreach (List<string> str in info.papers[no].knowledge)
-                                {
-                                    if (str.Contains(knowledgeName[i]))
-                                    {
-                                        var itemPersent = str.Count > 0 ? 1 / Convert.ToDouble(str.Count) : 0;
-                                        allScore += info.papers[no].point.Count > 0 ? info.papers[no].point[n] * itemPersent : 0;
-                                        foreach (string id in classResult.studentIds)
-                                        {
-                                            int index = classResult.studentIds.IndexOf(id);
-                                            if (classResult.studentScores.Count > 0)
-                                            {
-                                                if (classResult.studentScores[index].Count > 0)
-                                                {
-                                                    score += classResult.studentScores[index][n] == -1 ? 0 : classResult.studentScores[index][n];
-                                                    if (classResult.studentScores[index].Sum() >= rhw && phcount < rhwCount)
-                                                    {
-                                                        if (classResult.studentScores[index][n] <= 0)
-                                                        {
-                                                            phCount++;
-                                                        }
-                                                        phcount++;
-                                                        continue;
-                                                    }
-                                                    if (classResult.studentScores[index].Sum() <= rhl && plcount < (info.stuCount - rhlCount))
-                                                    {
-                                                        if (classResult.studentScores[index][n] <= 0)
-                                                        {
-                                                            plCount++;
-                                                        }
-                                                        plcount++;
-                                                        continue;
-                                                    }
-                                                    if (classResult.studentScores[index][n] <= 0)
-                                                    {
-                                                        pCount++;
-                                                    }
-                                                }
-                                            }
-
-                                        }
-                                    }
-                                    n++;
-                                }
-                                pc.Add(pCount);
-                                ph.Add(phCount);
-                                pl.Add(plCount);
-                                double per = classResult.studentIds.Count > 0 ? Math.Round(score / classResult.studentIds.Count, 2) : 0;
-                                persent.Add(allScore > 0 ? per / allScore : 0);
-                            }
-                            classResult.phc = ph;
-                            classResult.plc = pl;
-                            classResult.pc = pc;
-                            classResult.krate = persent;
-                        }
-                        //await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(classResult, classResult.id, new Azure.Cosmos.PartitionKey($"{classResult.code}"));
-                    }
-                }
-
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测知识点结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
-            }
-        }
-
-        public static async Task fieldCount(ExamInfo info, ExamSubject subject, DingDing _dingDing, int no, List<ExamClassResult> classResults,
-            double rhwCount, double rhw, double rhlCount, double rhl, AzureCosmosFactory _azureCosmos)
-        {
-            try
-            {
-                int phcount = 0;
-                int plcount = 0;
-                //存放并去重知识点
-                List<int> knowledgeName = new List<int>() { 1,2,3,4,5,6};
-/*                knowledgeName.Add(1);
-                knowledgeName.Add(2);
-                knowledgeName.Add(3);
-                knowledgeName.Add(4);
-                knowledgeName.Add(5);
-                knowledgeName.Add(6);*/
-                foreach (ExamClassResult classResult in classResults)
-                {
-                    if (classResult.subjectId.Equals(subject.id))
-                    {
-                        //List<int> phc = new List<int>();
-                        List<int> ph = new List<int>();
-                        List<int> pl = new List<int>();
-                        List<int> pc = new List<int>();
-                        List<double> persent = new List<double>();
-                        for (int i = 0; i < knowledgeName.Count; i++)
-                        {
-                            //初始化单个知识点得分
-                            double score = 0;
-                            double allScore = 0;
-                            int n = 0;
-                            int phCount = 0;
-                            int plCount = 0;
-                            int pCount = 0;
-                            if (info.papers[no].field.Count > 0)
-                            {
-                                foreach (int str in info.papers[no].field)
-                                {
-                                    if (str == knowledgeName[i])
-                                    {
-                                        var itemPersent = 1;
-                                        allScore += info.papers[no].point.Count > 0 ? info.papers[no].point[n] * itemPersent : 0;
-                                        foreach (string id in classResult.studentIds)
-                                        {
-                                            int index = classResult.studentIds.IndexOf(id);
-                                            if (classResult.studentScores.Count > 0)
-                                            {
-                                                if (classResult.studentScores[index].Count > 0)
-                                                {
-                                                    score += classResult.studentScores[index][n] == -1 ? 0 : classResult.studentScores[index][n];
-                                                    if (classResult.studentScores[index].Sum() >= rhw && phcount < rhwCount)
-                                                    {
-                                                        if (classResult.studentScores[index][n] <= 0)
-                                                        {
-                                                            phCount++;
-                                                        }
-                                                        phcount++;
-                                                        continue;
-                                                    }
-                                                    if (classResult.studentScores[index].Sum() <= rhl && plcount < (info.stuCount - rhlCount))
-                                                    {
-                                                        if (classResult.studentScores[index][n] <= 0)
-                                                        {
-                                                            plCount++;
-                                                        }
-                                                        plcount++;
-                                                        continue;
-                                                    }
-                                                    if (classResult.studentScores[index][n] <= 0)
-                                                    {
-                                                        pCount++;
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-                                    n++;
-                                }
-                                pc.Add(pCount);
-                                ph.Add(phCount);
-                                pl.Add(plCount);
-                                double per = classResult.studentIds.Count > 0 ? Math.Round(score / classResult.studentIds.Count, 2) : 0;
-                                persent.Add(allScore > 0 ? per / allScore : 0);
-                            }
-                        }
-                        classResult.fphc = ph;
-                        classResult.fplc = pl;
-                        classResult.fpc = pc;
-                        classResult.frate = persent;
-                    }
-                    //await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(classResult, classResult.id, new Azure.Cosmos.PartitionKey($"{classResult.code}"));
-                }
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测认知层次结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
-            }
-        }
-        //处理选题计数
-        public static List<Dictionary<string, int>> getMore(ExamInfo info, int no, List<List<List<string>>> list)
-        {
-            List<Dictionary<string, int>> recorde = new List<Dictionary<string, int>>();
-            try
-            {
-                for (int i = 0; i < info.papers[no].answers.Count; i++)
-                {
-                    if (info.papers[no].answers[i].Count <= 0)
-                    {
-                        recorde.Add(new Dictionary<string, int>());
-                        continue;
-                    }
-                    Dictionary<string, int> optCount = new Dictionary<string, int>();
-                    foreach (List<List<string>> stu in list)
-                    {
-                        if (stu.Count == info.papers[no].answers.Count)
-                        {
-
-                            var item = stu[i];
-                            foreach (string opt in item)
-                            {
-                                if (optCount.ContainsKey(opt))
-                                {
-                                    optCount[opt] = optCount[opt] + 1;
-                                }
-                                else
-                                {
-                                    optCount[opt] = 1;
-                                }
-                            }
-
-                        }
-                    }
-                    recorde.Add(optCount);
-                }
-                return recorde;
-            }
-            catch (Exception)
-            {
-                return recorde;
-            }
-        }
-        public static async Task createClassResultAsync(ExamInfo info, List<ExamClassResult> examClassResults, ExamSubject subject, int no, AzureCosmosFactory _azureCosmos, DingDing _dingDing, AzureStorageFactory _azureStorage)
-        {
-            //保证试卷信息与科目信息同步
-            ExamResult result = new ExamResult();
-            //人数总和
-            int Count = 0;
-            int m = 0;
-            double score = 0;
-            //标准差
-            double powSum = 0;
-            double allScore = info.papers[no].point.Sum();
-            List<ClassRange> classRanges = new List<ClassRange>();
-            List<string> lostStu = new List<string>();
-            List<double> csRate = new List<double>();
-            List<List<List<string>>> opt = new List<List<List<string>>>();
-            foreach (ExamClassResult classResult in examClassResults)
-            {
-                double classSrate = 0;
-                if (classResult.subjectId.Equals(subject.id))
-                {
-                    foreach (List<List<string>> op in classResult.ans)
-                    {
-                        opt.Add(op);
-                    }
-                    //记录缺考学生索引位置
-                    int index = 0;
-                    foreach (List<double> scores in classResult.studentScores)
-                    {
-                        List<double> newScores = new List<double>();
-                        int count = 0;
-                        foreach (double sc in scores)
-                        {
-                            newScores.Add(sc > -1 ? sc : 0);
-                            if (sc == -1)
-                            {
-                                count++;
-                            }
-                        }
-                        if (count == scores.Count)
-                        {
-                            lostStu.Add(classResult.studentIds[index]);
-                            //mcount++;
-                        }
-                        classSrate += newScores.Sum();
-                        score += newScores.Sum();
-                        result.studentScores.Add(newScores);
-                        index++;
-                    }
-
-                    //处理班级信息
-                    ClassRange range = new ClassRange();
-                    range.id = classResult.info.id;
-                    range.name = classResult.info.name;
-                    range.gradeId = classResult.gradeId;
-                    List<int> ran = new List<int>();
-                    int stuCount = classResult.studentIds.Count;
-                    Count += stuCount;
-                    if (m == 0)
-                    {
-                        ran.Add(0);
-                        ran.Add(stuCount - 1);
-                    }
-                    else
-                    {
-                        ran.Add(Count - stuCount);
-                        ran.Add(Count - 1);
-                    }
-                    m++;
-                    range.range = ran;
-                    classRanges.Add(range);
-                    //处理学生ID 
-                    foreach (string id in classResult.studentIds)
-                    {
-                        result.studentIds.Add(id);
-                    }
-                    if (allScore > 0)
-                    {
-                        csRate.Add(classResult.studentIds.Count > 0 ? Math.Round(classSrate * 1.0 / classResult.studentIds.Count, 2) : 0 / allScore);
-
-                    }
-                    else
-                    {
-                        csRate.Add(0);
-                    }
-
-                    //powSum += Math.Pow(classSrate - result.average, 2);
-                    //处理选项计数内容
-                }
-            }
-            await examRecordCount(info, subject, _dingDing, no, result, examClassResults, _azureCosmos);
-            result.record = getMore(info, no, opt);
-            result.average = result.studentIds.Count > 0 ? Math.Round(score * 1.0 / result.studentIds.Count, 2) : 0;
-            double stand = 0;
-            int sco = 0;
-            foreach (ExamClassResult classResult in examClassResults)
-            {
-
-                //double classSrate = 0;
-                if (classResult.subjectId.Equals(subject.id))
-                {
-                    stand += classResult.standard;
-                    sco++;
-                }
-
-            }
-            result.standard = sco > 0 ? Math.Round(stand / sco, 2) : 0;
-            result.csRate = csRate;
-            result.lostStus = lostStu;
-
-            result.sRate = allScore > 0 ? Math.Round(result.average / allScore * 100, 2) : 0;
-            result.classes = classRanges;
-            result.code = "ExamResult-" + info.id;
-            result.school = info.school;
-            result.id = subject.id;
-            result.examId = info.id;
-            result.subjectId = subject.id;
-            result.year = info.year;
-            result.paper = info.papers[no];
-            //result.point = info.papers[j].point;
-            result.scope = info.scope;
-            result.name = info.name;
-            result.time = info.startTime;
-
-            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").UpsertItemAsync(result, new Azure.Cosmos.PartitionKey($"ExamResult-{info.id}"));
-
-        }
-    }
-}

+ 0 - 170
TEAMModelFunction/TriggerExamLite.cs

@@ -1,170 +0,0 @@
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using HTEXLib.COMM.Helpers;
-using Microsoft.Azure.Documents;
-using Microsoft.Extensions.Configuration;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Models;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-
-namespace TEAMModelFunction
-{
-    public static class TriggerExamLite
-    {
-        public static async Task Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
-                    CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis, IConfiguration _configuration)
-        {
-            try
-            {
-                if ((tdata.status != null && tdata.status.Value == 404) || tdata.ttl > 0)
-                {
-                    return;
-                }
-                var adid = tdata.id;
-                var adcode = "";
-                string blobcntr = null;
-                if (tdata.scope.Equals("school"))
-                {
-                    adcode = $"Activity-{tdata.school}";
-                    blobcntr = tdata.school;
-                }
-                else
-                {
-                    adcode = $"Activity-{tdata.creatorId}";
-                    blobcntr = tdata.creatorId;
-                }
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修评测活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
-                ExamLite lite = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamLite>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-                
-                if (lite != null)
-                {
-                    string PartitionKey = string.Format("{0}{1}{2}", lite.code, "-", lite.progress);
-                    List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
-                    switch (lite.progress)
-                    {
-                        case "pending":
-                            var messageWork = new ServiceBusMessage(new { id = input.Id, progress = "going", code = tdata.code }.ToJsonString());
-                            messageWork.ApplicationProperties.Add("name", "ExamLite");
-                            if (changeRecords.Count > 0)
-                            {
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWork, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                changeRecords[0].sequenceNumber = start;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
-                            }
-                            else
-                            {
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWork, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = start,
-                                    msgId = messageWork.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-                            break;
-                        case "going":
-                            List<(string pId, List<string> gid)> ps = new List<(string pId, List<string> gid)>();
-                            if (lite.groupLists.Count > 0)
-                            {
-                                var group = lite.groupLists;
-                                foreach (var gp in group)
-                                {
-                                    foreach (KeyValuePair<string, List<string>> pp in gp)
-                                    {
-                                        ps.Add((pp.Key, pp.Value));
-                                    }
-                                }
-                            }
-                            (List<RMember> tchList, List<RGroupList> classInfos) = await GroupListService.GetStutmdidListids(client, _dingDing, lite.tchLists, lite.school, ps);
-                            List<StuActivity> tchActivities = new List<StuActivity>();
-                            (string standard, List<string> tmdids, string school, List<string> update, int statistics)  list =    (null,null, null, new List<string> { StatisticsService.TeacherExamLite }, 0)  ;
-                            if (tchList.IsNotEmpty())
-                            {
-                                list.tmdids = tchList.Select(x => x.id).ToList();
-                                School school = null;
-                                if (!string.IsNullOrEmpty(lite.school))
-                                {
-                                    school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(lite.school, new Azure.Cosmos.PartitionKey("Base"));
-                                    list.school = school.id;
-                                    list.standard = school.standard;
-                                }
-                                tchList.ForEach(x =>
-                                {
-                                    tchActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = lite.id,
-                                        code = $"Activity-{x.id}",
-                                        type = "ExamLite",
-                                        name = lite.name,
-                                        startTime = lite.startTime,
-                                        endTime = lite.endTime,
-                                        scode = lite.code,
-                                        scope = lite.scope,
-                                        school = lite.school,
-                                        creatorId = lite.creatorId,
-                                        subjects = new List<string> { "" },
-                                        blob = null,
-                                        owner = lite.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = lite.tchLists
-                                    });
-                                   
-                                });
-                              
-                            }
-                            await ActivityService.SaveStuActivity(client, _dingDing, null, null, tchActivities);
-                            await StatisticsService.SendServiceBus(list, _configuration, _serviceBus,   client);
-                            var messageWorkEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = tdata.code }.ToJsonString());
-                            messageWorkEnd.ApplicationProperties.Add("name", "ExamLite");
-                            if (changeRecords.Count > 0)
-                            {
-                                long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWorkEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
-                                changeRecords[0].sequenceNumber = end;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
-                            }
-                            else
-                            {
-                                long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWorkEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = end,
-                                    msgId = messageWorkEnd.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-                            break;
-                        case "finish":
-                            break;
-                    }
-
-
-                }
-
-            }
-            catch (CosmosException e)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-CosmosDB异常{e.Message}\n{e.Status}", GroupNames.成都开发測試群組);
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修评测异常{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-            }
-
-        }
-    }
-}

+ 0 - 229
TEAMModelFunction/TriggerHomework.cs

@@ -1,229 +0,0 @@
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using HTEXLib.COMM.Helpers;
-using Microsoft.Azure.Documents;
-using Microsoft.Extensions.Configuration;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Models;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-using TEAMModelOS.SDK.Models.Service;
-
-namespace TEAMModelFunction
-{
-    public static class TriggerHomework
-    {
-        public static async Task Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
-                    CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis, IConfiguration _configuration)
-        {
-            try
-            {
-                if ((tdata.status != null && tdata.status.Value == 404) || tdata.ttl > 0)
-                {
-                    return;
-                }
-                var adid = tdata.id;
-                var adcode = "";
-                string blobcntr = null;
-                if (tdata.scope.Equals("school"))
-                {
-                    adcode = $"Activity-{tdata.school}";
-                    blobcntr = tdata.school;
-                }
-                else
-                {
-                    adcode = $"Activity-{tdata.creatorId}";
-                    blobcntr = tdata.creatorId;
-                }
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}作业活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
-                Homework work = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Homework>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-                
-                if (work != null)
-                {
-                    string PartitionKey = string.Format("{0}{1}{2}", work.code, "-", work.progress);
-                    List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
-                    switch (work.progress)
-                    {
-                        case "pending":
-                            var messageWork = new ServiceBusMessage(new { id = input.Id, progress = "going", code = tdata.code }.ToJsonString());
-                            messageWork.ApplicationProperties.Add("name", "Homework");
-                            if (changeRecords.Count > 0)
-                            {
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWork, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                changeRecords[0].sequenceNumber = start;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
-                            }
-                            else
-                            {
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWork, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = start,
-                                    msgId = messageWork.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-                            break;
-                        case "going":
-                            List<(string pId, List<string> gid)> ps = new List<(string pId, List<string> gid)>();
-                            if (work.groupLists.Count > 0)
-                            {
-                                var group = work.groupLists;
-                                foreach (var gp in group)
-                                {
-                                    foreach (KeyValuePair<string, List<string>> pp in gp)
-                                    {
-                                        ps.Add((pp.Key, pp.Value));
-                                    }
-                                }
-                            }
-                            List<string> classes = ExamService.getClasses(work.classes, work.stuLists);
-                            (List<RMember> tmdids, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, classes, work.school, ps);
-                            var addStudentsCls = tmdids.FindAll(x => x.type == 2);
-                            var addTmdidsCls = tmdids.FindAll(x => x.type == 1);
-                            List<StuActivity> stuActivities = new List<StuActivity>();
-                            List<StuActivity> tmdActivities = new List<StuActivity>();
-                            List<StuActivity> tchActivities = new List<StuActivity>();
-                            if (addTmdidsCls.IsNotEmpty())
-                            {
-                                addTmdidsCls.ForEach(x =>
-                                {
-                                    tmdActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = work.id,
-                                        code = $"Activity-{x.id}",
-                                        type = "Homework",
-                                        name = work.name,
-                                        startTime = work.startTime,
-                                        endTime = work.endTime,
-                                        scode = work.code,
-                                        scope = work.scope,
-                                        school = work.school,
-                                        creatorId = work.creatorId,
-                                        subjects = new List<string> { "" },
-                                        blob = work.blob,
-                                        owner = work.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = classes
-                                    });
-                                });
-                            }
-                            if (addStudentsCls.IsNotEmpty())
-                            {
-                                addStudentsCls.ForEach(x =>
-                                {
-                                    stuActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = work.id,
-                                        code = $"Activity-{x.code.Replace("Base-", "")}-{x.id}",
-                                        type = "Homework",
-                                        name = work.name,
-                                        startTime = work.startTime,
-                                        endTime = work.endTime,
-                                        scode = work.code,
-                                        scope = work.scope,
-                                        school = work.school,
-                                        creatorId = work.creatorId,
-                                        subjects = new List<string> { "" },
-                                        blob = work.blob,
-                                        owner = work.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = classes
-                                    });
-                                });
-                            }
-                            (List<RMember> tchList, List<RGroupList> classInfos) = await GroupListService.GetStutmdidListids(client, _dingDing, work.tchLists, work.school,ps);
-                            (string standard, List<string> tmdids, string school, List<string> update, int statistics) list = (null, null, null, new List<string> { StatisticsService.OfflineRecord }, 0);
-                            if (tchList.IsNotEmpty())
-                            {
-                                list.tmdids = tchList.Select(x => x.id).ToList();
-                                School school = null;
-                                if (!string.IsNullOrEmpty(work.school))
-                                {
-                                    school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(work.school, new Azure.Cosmos.PartitionKey("Base"));
-                                    list.school = school.id;
-                                    list.standard = school.standard;
-                                }
-                                tchList.ForEach(x =>
-                                {
-                                    tchActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = work.id,
-                                        code = $"Activity-{x.id}",
-                                        type = "Homework",
-                                        name = work.name,
-                                        startTime = work.startTime,
-                                        endTime = work.endTime,
-                                        scode = work.code,
-                                        scope = work.scope,
-                                        school = work.school,
-                                        creatorId = work.creatorId,
-                                        subjects = new List<string> { "" },
-                                        blob = work.blob,
-                                        owner = work.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = work.tchLists
-                                    });
-                                     
-                                });
-                            }
-                            await ActivityService.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities, tchActivities);
-                            await StatisticsService.SendServiceBus(list, _configuration, _serviceBus, client);
-                            var messageWorkEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = tdata.code }.ToJsonString());
-                            messageWorkEnd.ApplicationProperties.Add("name", "Homework");
-                            if (changeRecords.Count > 0)
-                            {
-                                long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWorkEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
-                                changeRecords[0].sequenceNumber = end;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
-                            }
-                            else
-                            {
-                                long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWorkEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = end,
-                                    msgId = messageWorkEnd.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-                            //if (bustasks.IsNotEmpty())
-                            //{
-                            //    await Task.WhenAll(bustasks);
-                            //}
-                            break;
-                        case "finish":
-                            break;
-                    }
-
-                }
-            }
-            catch (CosmosException e)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-CosmosDB异常{e.Message}\n{e.Status}", GroupNames.成都开发測試群組);
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修作业活动异常{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-            }
-        }
-    }
-}

+ 0 - 175
TEAMModelFunction/TriggerStudy.cs

@@ -1,175 +0,0 @@
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using HTEXLib.COMM.Helpers;
-using Microsoft.Azure.Documents;
-using Microsoft.Extensions.Configuration;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Models;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-
-namespace TEAMModelFunction
-{
-    public static class TriggerStudy
-    {
-        public static async Task Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
-                    CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis, IConfiguration _configuration)
-        {
-            try
-            {
-                if ((tdata.status != null && tdata.status.Value == 404) || tdata.ttl > 0 || tdata.publish == 1)
-                {
-                    return;
-                }
-                var adid = tdata.id;
-                var adcode = "";
-                string blobcntr = null;
-                if (tdata.scope.Equals("school"))
-                {
-                    adcode = $"Activity-{tdata.school}";
-                    blobcntr = tdata.school;
-                }
-                else
-                {
-                    adcode = $"Activity-{tdata.creatorId}";
-                    blobcntr = tdata.creatorId;
-                }
-              
-                Study study = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Study>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-                
-                if (study != null)
-                {
-                    string PartitionKey = string.Format("{0}{1}{2}", study.code, "-", study.progress);
-                    List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
-                    switch (study.progress)
-                    {
-                        case "pending":
-                            var messageWork = new ServiceBusMessage(new { id = input.Id, progress = "going", code = tdata.code }.ToJsonString());
-                            messageWork.ApplicationProperties.Add("name", "Study");
-                            if (changeRecords.Count > 0)
-                            {
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWork, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                changeRecords[0].sequenceNumber = start;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
-                            }
-                            else
-                            {
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWork, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = start,
-                                    msgId = messageWork.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-                            break;
-                        case "going":
-                            try {
-                                List<(string pId, List<string> gid)> ps = new List<(string pId, List<string> gid)>();
-                                if (study.groupLists.Count > 0)
-                                {
-                                    var group = study.groupLists;
-                                    foreach (var gp in group)
-                                    {
-                                        foreach (KeyValuePair<string, List<string>> pp in gp)
-                                        {
-                                            ps.Add((pp.Key, pp.Value));
-                                        }
-                                    }
-                                }
-                                (List<RMember> tchList, List<RGroupList> classInfos) = await GroupListService.GetStutmdidListids(client, _dingDing, study.tchLists, study.school, ps);
-                                List<StuActivity> tchActivities = new List<StuActivity>();
-                                (string standard, List<string> tmdids, string school, List<string> update, int statistics) list = (null, null, null, new List<string> { StatisticsService.OfflineRecord }, 0);
-                                if (tchList.IsNotEmpty())
-                                {
-                                    list.tmdids = tchList.Select(x => x.id).ToList();
-                                    School school = null;
-                                    if (!string.IsNullOrEmpty(study.school))
-                                    {
-                                        school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(study.school, new Azure.Cosmos.PartitionKey("Base"));
-                                        list.school = school.id;
-                                        list.standard = school.standard;
-                                    }
-                                    tchList.ForEach(x =>
-                                    {
-                                        tchActivities.Add(new StuActivity
-                                        {
-                                            pk = "Activity",
-                                            id = study.id,
-                                            code = $"Activity-{x.id}",
-                                            type = "Study",
-                                            name = study.name,
-                                            startTime = study.startTime,
-                                            endTime = study.endTime,
-                                            scode = study.code,
-                                            scope = study.scope,
-                                            school = study.school,
-                                            creatorId = study.creatorId,
-                                            subjects = new List<string> { "" },
-                                            blob = null,
-                                            owner = study.owner,
-                                            createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                            taskStatus = -1,
-                                            classIds = study.tchLists
-                                        });
-                                    });
-
-                                }
-
-                                await ActivityService.SaveStuActivity(client, _dingDing, null, null, tchActivities);
-                                await StatisticsService.SendServiceBus(list, _configuration, _serviceBus,client);
-                                var messageWorkEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = tdata.code }.ToJsonString());
-                                messageWorkEnd.ApplicationProperties.Add("name", "Study");
-                                if (changeRecords.Count > 0)
-                                {
-                                    long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWorkEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
-                                    changeRecords[0].sequenceNumber = end;
-                                    await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
-                                }
-                                else
-                                {
-                                    long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWorkEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                    ChangeRecord changeRecord = new ChangeRecord
-                                    {
-                                        RowKey = input.Id,
-                                        PartitionKey = PartitionKey,
-                                        sequenceNumber = end,
-                                        msgId = messageWorkEnd.MessageId
-                                    };
-                                    await _azureStorage.Save<ChangeRecord>(changeRecord);
-                                }
-
-                            }
-                            catch (Exception ex) {
-                                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修活动异常-going {ex.Message}{ex.StackTrace}{tdata.ToJsonString()}{input}", GroupNames.成都开发測試群組);
-                            }
-                           
-                            break;
-                        case "finish":
-                            break;
-                    }
-                }
-
-            }
-            catch (CosmosException e)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-CosmosDB异常{e.Message}\n{e.Status}", GroupNames.成都开发測試群組);
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修活动异常{ex.Message}{ex.StackTrace}{tdata.ToJsonString()}{input}", GroupNames.成都开发測試群組);
-            }
-
-        }
-    }
-}

+ 0 - 398
TEAMModelFunction/TriggerSurvey.cs

@@ -1,398 +0,0 @@
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using Azure.Storage.Blobs.Models;
-using Azure.Storage.Sas;
-using Microsoft.Azure.Documents;
-using System;
-using System.Collections.Generic;
-using System.Net.Http;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.Models;
-using TEAMModelOS.SDK.Models.Cosmos;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
-using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
-using TEAMModelOS.SDK.Models.Service;
-using HTEXLib.COMM.Helpers;
-using Microsoft.Extensions.Configuration;
-using System.Linq;
-
-namespace TEAMModelFunction
-{
-    public class TriggerSurvey
-    {
-        public static async Task Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
-               CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis, IConfiguration _configuration)
-        {
-            try
-            {
-                if ((tdata.status != null && tdata.status.Value == 404) || tdata.ttl > 0)
-                {
-                    _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Record:{tdata.id}");
-                    _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Submit:{tdata.id}");
-                    return;
-                }
-                var adid = tdata.id;
-                var adcode = "";
-                string blobcntr = null;
-                if (tdata.scope.Equals("school"))
-                {
-                    adcode = $"Activity-{tdata.school}";
-                    blobcntr = tdata.school;
-                }
-                else
-                {
-                    adcode = $"Activity-{tdata.creatorId}";
-                    blobcntr = tdata.creatorId;
-                }
-                Survey survey = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Survey>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-
-                if (survey != null)
-                {
-                    string PartitionKey = string.Format("{0}{1}{2}", survey.code, "-", survey.progress);
-                    List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
-                    switch (survey.progress)
-                    {
-                        case "pending":
-                            var messageSurvey = new ServiceBusMessage(new { id = input.Id, progress = "going", code = tdata.code }.ToJsonString());
-                            messageSurvey.ApplicationProperties.Add("name", "Survey");
-                            if (changeRecords.Count > 0)
-                            {
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageSurvey, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                changeRecords[0].sequenceNumber = start;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
-                            }
-                            else
-                            {
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageSurvey, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = start,
-                                    msgId = messageSurvey.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-                            break;
-                        case "going":
-                            List<(string pId, List<string> gid)> ps = new List<(string pId, List<string> gid)>();
-                            if (survey.groupLists.Count > 0)
-                            {
-                                var group = survey.groupLists;
-                                foreach (var gp in group)
-                                {
-                                    foreach (KeyValuePair<string, List<string>> pp in gp)
-                                    {
-                                        ps.Add((pp.Key, pp.Value));
-                                    }
-                                }
-                            }
-                            List<string> classes = ExamService.getClasses(survey.classes, survey.stuLists);
-                            (List<RMember> tmdIds, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, classes, survey.school);
-                            var addStudentsCls = tmdIds.FindAll(x => x.type == 2);
-                            var addTmdidsCls = tmdIds.FindAll(x => x.type == 1);
-#if DEBUG
-                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查{tdata.id}写入学生表作为活动列表!", GroupNames.成都开发測試群組);
-#endif
-                            List<StuActivity> stuActivities = new List<StuActivity>();
-                            List<StuActivity> tmdActivities = new List<StuActivity>();
-                            List<StuActivity> tchActivities = new List<StuActivity>();
-                            if (addTmdidsCls.IsNotEmpty())
-                            {
-                                addTmdidsCls.ForEach(x =>
-                                {
-                                    tmdActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = survey.id,
-                                        code = $"Activity-{x.id}",
-                                        type = "Survey",
-                                        name = survey.name,
-                                        startTime = survey.startTime,
-                                        endTime = survey.endTime,
-                                        scode = survey.code,
-                                        scope = survey.scope,
-                                        school = survey.school,
-                                        creatorId = survey.creatorId,
-                                        subjects = new List<string> { "" },
-                                        blob = survey.blob,
-                                        owner = survey.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = classes
-                                    });
-                                });
-                            }
-                            if (addStudentsCls.IsNotEmpty())
-                            {
-                                addStudentsCls.ForEach(x =>
-                                {
-                                    stuActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = survey.id,
-                                        code = $"Activity-{x.code.Replace("Base-", "")}-{x.id}",
-                                        type = "Survey",
-                                        name = survey.name,
-                                        startTime = survey.startTime,
-                                        endTime = survey.endTime,
-                                        scode = survey.code,
-                                        scope = survey.scope,
-                                        school = survey.school,
-                                        creatorId = survey.creatorId,
-                                        subjects = new List<string> { "" },
-                                        blob = survey.blob,
-                                        owner = survey.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = classes
-                                    });
-                                });
-                            }
-                            (List<RMember> tchList, List<RGroupList> classInfos) = await GroupListService.GetStutmdidListids(client, _dingDing, survey.tchLists, survey.school, ps);
-                            (string standard, List<string> tmdids, string school, List<string> update, int statistics) list = (null, null, null, new List<string> { StatisticsService.TeacherSurvey }, 0);
-                            if (tchList.IsNotEmpty())
-                            {
-                                list.tmdids = tchList.Select(x => x.id).ToList();
-                                School school = null;
-                                if (!string.IsNullOrEmpty(survey.school))
-                                {
-                                    school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(survey.school, new Azure.Cosmos.PartitionKey("Base"));
-                                    list.school = school.id;
-                                    list.standard = school.standard;
-                                }
-                                tchList.ForEach(x =>
-                                {
-                                    tchActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = survey.id,
-                                        code = $"Activity-{x.id}",
-                                        type = "Survey",
-                                        name = survey.name,
-                                        startTime = survey.startTime,
-                                        endTime = survey.endTime,
-                                        scode = survey.code,
-                                        scope = survey.scope,
-                                        school = survey.school,
-                                        creatorId = survey.creatorId,
-                                        subjects = new List<string> { "" },
-                                        blob = survey.blob,
-                                        owner = survey.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = survey.tchLists
-                                    });
-                                });
-
-                            }
-                            await ActivityService.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities, tchActivities);
-                            await StatisticsService.SendServiceBus(list, _configuration, _serviceBus, client);
-                            //向学生或醍摩豆账号发起通知
-                            #region
-                            //Notice notice = new Notice()
-                            //{
-                            //    creation = survey.startTime,
-                            //    expire = survey.endTime,
-                            //    creatorId = survey.creatorId,
-                            //    stuids = students,
-                            //    tmdids = tmdids,
-                            //    type = "notice",//问卷参加参加通知
-                            //    priority = "normal",
-                            //    //data = new { }.ToJsonString()
-                            //    msgId = survey.id,
-                            //    school = survey.school,
-                            //    scope = survey.scope,
-                            //    body = new Body { sid = survey.id, scode = survey.code, spk = survey.pk, biztype = "survey-join" }
-
-                            //};
-                            //var messageBlob = new ServiceBusMessage(notice.ToJsonString());
-                            //messageBlob.ApplicationProperties.Add("name", "Notice");
-                            //await _serviceBus.GetServiceBusClient().SendMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageBlob);
-                            #endregion
-#if DEBUG
-                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查{tdata.id}写入完成!", GroupNames.成都开发測試群組);
-#endif
-                            var messageSurveyEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = tdata.code }.ToJsonString());
-                            messageSurveyEnd.ApplicationProperties.Add("name", "Survey");
-                            if (changeRecords.Count > 0)
-                            {
-                                long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageSurveyEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
-                                changeRecords[0].sequenceNumber = end;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
-                            }
-                            else
-                            {
-                                long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageSurveyEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = end,
-                                    msgId = messageSurveyEnd.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-#if DEBUG
-                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查{tdata.id}将于:{tdata.etime}完成并结算!", GroupNames.成都开发測試群組);
-#endif
-                            break;
-                        case "finish":
-#if DEBUG
-                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查{tdata.id}开始结算{tdata.etime}!", GroupNames.成都开发測試群組);
-#endif
-                            var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}");
-                            var submits = await _azureRedis.GetRedisClient(8).SetMembersAsync($"Survey:Submit:{survey.id}");
-                            List<dynamic> recs = new List<dynamic>();
-                            foreach (var rcd in records)
-                            {
-                                var value = rcd.Value.ToString().ToObject<JsonElement>();
-                                recs.Add(new { index = rcd.Name.ToString(), ans = value });
-                            }
-
-                            List<dynamic> userids = new List<dynamic>();
-                            foreach (var submit in submits)
-                            {
-                                var value = submit.ToString();
-                                userids.Add(value);
-                            }
-
-                            List<QuestionRecord> questionRecords = new List<QuestionRecord>();
-                            //结算每道题的答题情况
-                            var ContainerClient = _azureStorage.GetBlobContainerClient(blobcntr);
-                            List<Task<string>> tasks = new List<Task<string>>();
-                            //获取
-                            List<SurveyRecord> surveyRecords = new List<SurveyRecord>();
-                            try
-                            {
-                                List<string> items = await ContainerClient.List($"survey/{survey.id}/urecord");
-
-                                foreach (string item in items)
-                                {
-                                    var Download = await _azureStorage.GetBlobContainerClient(blobcntr).GetBlobClient(item).DownloadAsync();
-                                    var json = await JsonDocument.ParseAsync(Download.Value.Content);
-                                    var Record = json.RootElement.ToObject<SurveyRecord>();
-                                    surveyRecords.Add(Record);
-                                }
-#if DEBUG
-                                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查问题结算数据{surveyRecords.ToJsonString()}", GroupNames.成都开发測試群組);
-#endif
-                                for (int index = 0; index < survey.answers.Count; index++)
-                                {
-                                    string url = $"{survey.id}/qrecord/{index}.json";
-                                    QuestionRecord question = new QuestionRecord() { index = index };
-                                    foreach (SurveyRecord record in surveyRecords)
-                                    {
-                                        if (record.ans.Count == survey.answers.Count)
-                                        {
-                                            foreach (var an in record.ans[index])
-                                            {
-                                                //
-                                                if (question.opt.ContainsKey(an))
-                                                {
-                                                    if (question.opt[an] != null)
-                                                    {
-                                                        question.opt[an].Add(record.userid);
-                                                    }
-                                                    else
-                                                    {
-                                                        question.opt[an] = new HashSet<string>() { record.userid };
-                                                    }
-                                                }
-                                                else
-                                                {
-                                                    if (survey.answers[index].Contains(an))
-                                                    {
-                                                        //如果是客观题code
-                                                        question.opt.Add(an, new HashSet<string> { record.userid });
-                                                    }
-                                                    else
-                                                    {
-                                                        //如果不是客观code
-                                                        question.other[record.userid] = an;
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-                                    questionRecords.Add(question);
-                                    tasks.Add(_azureStorage.UploadFileByContainer(blobcntr, question.ToJsonString(), "survey", url));
-                                }
-                                await Task.WhenAll(tasks);
-                            }
-                            catch (Exception ex)
-                            {
-                                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查问题结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
-                            }
-                            var cods = new { records = recs, userids, question = questionRecords, urecord = surveyRecords };
-                            //问卷整体情况
-                            await _azureStorage.UploadFileByContainer(blobcntr, cods.ToJsonString(), "survey", $"{survey.id}/record.json");
-                            if (string.IsNullOrEmpty(survey.recordUrl))
-                            {
-                                survey.recordUrl = $"/survey/{survey.id}/record.json";
-                                await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync<Survey>(survey, survey.id, new Azure.Cosmos.PartitionKey(survey.code));
-                            }
-                            else
-                            {
-                                _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Record:{survey.id}");
-                                _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Submit:{survey.id}");
-                                break;
-                            }
-
-                            //更新结束状态
-                            //data.progress = "finish";
-                            //if (survey.scope .Equals("school"))
-                            //{
-                            //    await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
-                            //}
-                            //else if (survey.scope .Equals("private"))
-                            //{
-                            //    await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
-                            //}
-
-                            break;
-                    }
-                }
-            }
-
-            catch (CosmosException e)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-CosmosDB异常{e.Message}\n{e.Status}", GroupNames.成都开发測試群組);
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
-
-            }
-        }
-    }
-    /**
-     * {survey.id}/qrecord/{index}.json
-        {
-            "opt": {
-                "A": [
-                    "userid1",
-                    "userid2",
-                    "userid3"
-                ],
-                "B": [
-                    "userid1",
-                    "userid2",
-                    "userid3"
-                ]
-            },
-            "other": {
-                "userid1": "建议XXXX1",
-                "userid2": "建议XXXX2"
-            }
-        }
-     **/
-}

+ 0 - 318
TEAMModelFunction/TriggerVote.cs

@@ -1,318 +0,0 @@
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using Microsoft.Azure.Documents;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK;
-using TEAMModelOS.SDK.Models;
-using TEAMModelOS.SDK.Models.Cosmos;
-using TEAMModelOS.SDK.Models.Cosmos.Common;
-using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
-using TEAMModelOS.SDK.Models.Service;
-using HTEXLib.COMM.Helpers;
-using Microsoft.Extensions.Configuration;
-
-namespace TEAMModelFunction
-{
-    public static class TriggerVote
-    {
-
-        public static async Task Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
-            CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis, IConfiguration _configuration)
-        {
-            try
-            {
-                if ((tdata.status != null && tdata.status.Value == 404) || tdata.ttl > 0)
-                {
-                    //异动,且已经有结算记录则不必再继续。
-                    _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Record:{tdata.id}");
-                    _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Count:{tdata.id}");
-                    return;
-                }
-                var adid = tdata.id;
-                var adcode = "";
-                string blobcntr = null;
-                if (tdata.scope.Equals("school"))
-                {
-                    adcode = $"Activity-{tdata.school}";
-                    blobcntr = tdata.school;
-                }
-                else
-                {
-                    adcode = $"Activity-{tdata.creatorId}";
-                    blobcntr = tdata.creatorId;
-                }
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}投票活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
-                Vote vote = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-
-                if (vote != null)
-                {
-                    string PartitionKey = string.Format("{0}{1}{2}", vote.code, "-", vote.progress);
-                    List<ChangeRecord> voteRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
-                    switch (vote.progress)
-                    {
-                        case "pending":
-                            var messageVote = new ServiceBusMessage(new { id = input.Id, progress = "going", code = tdata.code }.ToJsonString());
-                            messageVote.ApplicationProperties.Add("name", "Vote");
-                            if (voteRecords.Count > 0)
-                            {
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageVote, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), voteRecords[0].sequenceNumber);
-                                voteRecords[0].sequenceNumber = start;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(voteRecords[0]);
-                            }
-                            else
-                            {
-                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageVote, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = start,
-                                    msgId = messageVote.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-                            break;
-                        case "going":
-                            List<(string pId, List<string> gid)> ps = new List<(string pId, List<string> gid)>();
-                            if (vote.groupLists.Count > 0)
-                            {
-                                var group = vote.groupLists;
-                                foreach (var keys in group)
-                                {
-                                    foreach (KeyValuePair<string, List<string>> pp in keys)
-                                    {
-                                        ps.Add((pp.Key, pp.Value));
-                                    }
-                                }
-                            }
-                            List<string> classes = ExamService.getClasses(vote.classes, vote.stuLists);
-                            (List<RMember> tmdIds, List<RGroupList> classLists) = await GroupListService.GetStutmdidListids(client, _dingDing, classes, vote.school, ps);
-                            var addStudentsCls = tmdIds.FindAll(x => x.type == 2);
-                            var addTmdidsCls = tmdIds.FindAll(x => x.type == 1);
-                            //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}投票活动" +
-                            //    $"{tmdids.ToJsonString()}\n" +
-                            //    $"{students.ToJsonString()}\n" +
-                            //    $"{classLists.ToJsonString()}\n" +
-                            //    $"{classes.ToJsonString()}\n", GroupNames.成都开发測試群組);
-                            List<string> tmds = new List<string>();
-                            if (addTmdidsCls.IsNotEmpty())
-                            {
-                                tmds.AddRange(addTmdidsCls.Select(x => x.id).ToList());
-                            }
-                            List<StuActivity> stuActivities = new List<StuActivity>();
-                            List<StuActivity> tmdActivities = new List<StuActivity>();
-                            List<StuActivity> tchActivities = new List<StuActivity>();
-                            if (tmds.IsNotEmpty())
-                            {
-                                tmds.ForEach(x =>
-                                {
-                                    tmdActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = vote.id,
-                                        code = $"Activity-{x}",
-                                        type = "Vote",
-                                        name = vote.name,
-                                        startTime = vote.startTime,
-                                        endTime = vote.endTime,
-                                        scode = vote.code,
-                                        scope = vote.scope,
-                                        school = vote.school,
-                                        creatorId = vote.creatorId,
-                                        subjects = new List<string> { "" },
-                                        blob = null,
-                                        owner = vote.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = classes
-                                    });
-                                });
-                            }
-                            if (addStudentsCls.IsNotEmpty())
-                            {
-                                addStudentsCls.ForEach(x =>
-                                {
-                                    stuActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = vote.id,
-                                        code = $"Activity-{x.code.Replace("Base-", "")}-{x.id}",
-                                        type = "Vote",
-                                        name = vote.name,
-                                        startTime = vote.startTime,
-                                        endTime = vote.endTime,
-                                        scode = vote.code,
-                                        scope = vote.scope,
-                                        school = vote.school,
-                                        creatorId = vote.creatorId,
-                                        subjects = new List<string> { "" },
-                                        blob = null,
-                                        owner = vote.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = classes
-                                    });
-                                });
-                            }
-                            (List<RMember> tchList, List<RGroupList> classInfos) = await GroupListService.GetStutmdidListids(client, _dingDing, vote.tchLists, vote.school, ps);
-                            (string standard, List<string> tmdids, string school, List<string> update, int statistics) list = (null, null, null, new List<string> { StatisticsService.TeacherVote }, 0);
-                            if (tchList.IsNotEmpty())
-                            {
-                                list.tmdids = tchList.Select(x => x.id).ToList();
-                                School school = null;
-                                if (!string.IsNullOrEmpty(vote.school))
-                                {
-                                    school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(vote.school, new Azure.Cosmos.PartitionKey("Base"));
-                                    list.school = school.id;
-                                    list.standard = school.standard;
-                                }
-                                tchList.ForEach(x =>
-                                {
-                                    tchActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = vote.id,
-                                        code = $"Activity-{x.id}",
-                                        type = "Vote",
-                                        name = vote.name,
-                                        startTime = vote.startTime,
-                                        endTime = vote.endTime,
-                                        scode = vote.code,
-                                        scope = vote.scope,
-                                        school = vote.school,
-                                        creatorId = vote.creatorId,
-                                        subjects = new List<string> { "" },
-                                        blob = null,
-                                        owner = vote.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = classes
-                                    });
-                                });
-
-                            }
-                            //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}投票活动,:教研组活动:" +
-
-                            //   $"{tchActivities.ToJsonString()}\n", GroupNames.成都开发測試群組);
-                            await ActivityService.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities, tchActivities);
-                            await StatisticsService.SendServiceBus(list, _configuration, _serviceBus, client);
-                            //向学生或醍摩豆账号发起通知
-                            #region
-                            //Notice notice = new Notice()
-                            //{
-
-                            //    creation = vote.startTime,
-                            //    expire = vote.endTime,
-                            //    creatorId = vote.creatorId,
-                            //    stuids = students,
-                            //    tmdids = tmdids,
-                            //    type = "notice",//问卷参加参加通知
-                            //    priority = "normal",
-                            //    msgId=vote.id,
-                            //    school = vote.school,
-                            //    scope = vote.scope,
-                            //    //data = new { }.ToJsonString()
-                            //    body = new Body { sid = vote.id, scode = vote.code, spk = vote.pk,  biztype = "vote-join" }
-
-                            //};
-
-                            //var messageBlob = new ServiceBusMessage(notice.ToJsonString());
-                            //messageBlob.ApplicationProperties.Add("name", "Notice");
-                            //await _serviceBus.GetServiceBusClient().SendMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:NoticeTask"), messageBlob);
-                            #endregion
-                            var messageVoteEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = tdata.code }.ToJsonString());
-                            messageVoteEnd.ApplicationProperties.Add("name", "Vote");
-                            if (voteRecords.Count > 0)
-                            {
-                                long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageVoteEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), voteRecords[0].sequenceNumber);
-                                voteRecords[0].sequenceNumber = end;
-                                await _azureStorage.SaveOrUpdate<ChangeRecord>(voteRecords[0]);
-                            }
-                            else
-                            {
-                                long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageVoteEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
-                                ChangeRecord changeRecord = new ChangeRecord
-                                {
-                                    RowKey = input.Id,
-                                    PartitionKey = PartitionKey,
-                                    sequenceNumber = end,
-                                    msgId = messageVoteEnd.MessageId
-                                };
-                                await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            }
-#if DEBUG
-                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}投票活动{tdata.id}将于:{tdata.etime}完成并结算!", GroupNames.成都开发測試群組);
-#endif
-                            break;
-                        case "finish":
-#if DEBUG
-                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}投票活动{tdata.id}开始结算{tdata.etime}!", GroupNames.成都开发測試群組);
-#endif
-                            //获取投票活动的所有投票记录
-                            var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Vote:Record:{vote.id}");
-                            //获取投票活动的选项及投票数
-                            var counts = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Vote:Count:{vote.id}");
-                            List<dynamic> countcds = new List<dynamic>();
-                            if (counts != null && counts.Length > 0)
-                            {
-                                foreach (var count in counts)
-                                {
-                                    countcds.Add(new { code = count.Element.ToString(), count = (int)count.Score });
-                                }
-                            }
-                            List<Task<string>> tasks = new List<Task<string>>();
-                            List<VoteRecord> recordsBlob = new List<VoteRecord>();
-                            foreach (var rcd in records)
-                            {
-                                var value = rcd.Value.ToString().ToObject<VoteRecord>();
-                                recordsBlob.Add(value);
-                            }
-                            //分组每个人的 
-                            var gp = recordsBlob.GroupBy(x => x.userid).Select(x => new { key = x.Key, list = x.ToList() });
-                            foreach (var g in gp)
-                            {
-                                tasks.Add(_azureStorage.UploadFileByContainer(blobcntr, g.list.ToJsonString(), "vote", $"{vote.id}/urecord/{g.key}.json"));
-                            }
-                            //处理活动方的记录, 
-                            string url = $"/vote/{vote.id}/record.json";
-                            tasks.Add(_azureStorage.UploadFileByContainer(blobcntr, new { options = countcds, records = recordsBlob }.ToJsonString(), "vote", $"{vote.id}/record.json"));
-                            //处理投票者的记录
-
-                            if (string.IsNullOrEmpty(vote.recordUrl))
-                            {
-                                vote.recordUrl = url;
-                                await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync<Vote>(vote, vote.id, new Azure.Cosmos.PartitionKey(vote.code));
-                            }
-                            else
-                            {
-                                //异动,且已经有结算记录则不必再继续。
-                                _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Record:{vote.id}");
-                                _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Count:{vote.id}");
-                                break;
-                            }
-                            await Task.WhenAll(tasks);
-                            break;
-                    }
-                }
-            }
-            catch (CosmosException e)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-CosmosDB异常{e.Message}\n{e.Status}", GroupNames.成都开发測試群組);
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}投票活动异常{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
-            }
-
-        }
-    }
-}

+ 0 - 19
TEAMModelFunction/host.json

@@ -1,19 +0,0 @@
-{
-  "version": "2.0",
-  "cosmosDB": {
-    "connectionMode": "Direct",
-    "protocol": "Tcp"
-  },
-  "logging": {
-    "console": {
-      "isEnabled": "true"
-    },
-    "applicationInsights": {
-      "samplingExcludedTypes": "Request",
-      "samplingSettings": {
-        "isEnabled": true,
-        "ExcludedTypes": "Request"
-      }
-    }
-  }
-}

+ 0 - 21
TEAMModelFunction/local.settings.json

@@ -1,21 +0,0 @@
-{
-  "IsEncrypted": false,
-  "Values": {
-    "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=teammodellog;AccountKey=lxVDrgs+6rKtmASL3k1WrarrEd5Rk42wS1Mu5+sqQlPya1JLSlFDtnZUvMPeHHe7zlESfn/1NY7CZdGviy2UCw==;EndpointSuffix=core.chinacloudapi.cn",
-    "Azure:Storage:ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelstorage;AccountKey=Yq7D4dE6cFuer2d2UZIccTA/i0c3sJ/6ITc8tNOyW+K5f+/lWw9GCos3Mxhj47PyWQgDL8YbVD63B9XcGtrMxQ==;EndpointSuffix=core.chinacloudapi.cn",
-    "Azure:ServiceBus:ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
-    //"Azure:Cosmos:ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;",
-    //"Azure:Redis:ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False",
-    //"Azure:ServiceBus:ActiveTask": "active-task",
-    //"Azure:ServiceBus:NoticeTask": "notice-task",
-    "Azure:Cosmos:ConnectionString": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;",
-    "Azure:Redis:ConnectionString": "106.12.23.251:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240",
-    "Azure:ServiceBus:ActiveTask": "dep-active-task",
-    "Azure:ServiceBus:ItemCondQueue": "dep-itemcond",
-    "Option:Location": "China-Dep",
-    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
-    "HaBookAuth:CoreService:sendnotification": "https://api2.teammodel.net/service/sendnotification",
-    "HaBookAuth:CoreService:clientID": "c7317f88-7cea-4e48-ac57-a16071f7b884",
-    "HaBookAuth:CoreService:clientSecret": "kguxh:V.PLmxBdaI@jnrTrDSth]A3346"
-  }
-}

+ 0 - 35
TEAMModelGrpc/Dockerfile

@@ -1,35 +0,0 @@
-#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
-
-FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
-WORKDIR /app
-EXPOSE 80
-EXPOSE 443
-EXPOSE 5000
-
-FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
-WORKDIR /app
-RUN dotnet dev-certs https --clean
-RUN dotnet dev-certs https -ep TEAMModelGrpc/habook.pfx  -p habook
-#RUN dotnet dev-certs https --trust
-COPY ["TEAMModelGrpc/habook.pfx", "/app"]
-
-WORKDIR /src
-COPY ["TEAMModelGrpc/habook.pfx", "TEAMModelGrpc/"]
-COPY ["TEAMModelGrpc/nuget.config", "TEAMModelGrpc/"]
-COPY ["TEAMModelGrpc/Protos", "TEAMModelGrpc/"]
-COPY ["TEAMModelGrpc/TEAMModelGrpc.csproj", "TEAMModelGrpc/"]
-COPY ["TEAMModelOS.SDK/TEAMModelOS.SDK.csproj", "TEAMModelOS.SDK/"]
-COPY ["TEAMModelOS.Service/TEAMModelOS.Service.csproj", "TEAMModelOS.Service/"]
-RUN dotnet restore "TEAMModelGrpc/TEAMModelGrpc.csproj" --configfile "TEAMModelGrpc/nuget.config"
-COPY . .
-WORKDIR "/src/TEAMModelGrpc"
-RUN dotnet build "TEAMModelGrpc.csproj" -c Release -o /app/build
-
-FROM build AS publish
-RUN dotnet publish "TEAMModelGrpc.csproj" -c Release -o /app/publish
-COPY ["TEAMModelGrpc/habook.pfx", "/app/publish"]
-
-FROM base AS final
-WORKDIR /app
-COPY --from=publish /app/publish .
-ENTRYPOINT ["dotnet", "TEAMModelGrpc.dll"]

+ 0 - 46
TEAMModelGrpc/GrpcHealthCheck/GrpcHealthChecksEndpointRouteBuilderExtensions.cs

@@ -1,46 +0,0 @@
-#region Copyright notice and license
-
-// Copyright 2019 The gRPC Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#endregion
-
-using System;
-using Grpc.HealthCheck;
-using Microsoft.AspNetCore.Routing;
-
-namespace Microsoft.AspNetCore.Builder
-{
-    /// <summary>
-    /// Provides extension methods for <see cref="IEndpointRouteBuilder"/> to add gRPC service endpoints.
-    /// </summary>
-    public static class GrpcHealthChecksEndpointRouteBuilderExtensions
-    {
-        /// <summary>
-        /// Maps incoming requests to the gRPC health checks service.
-        /// This service can be queried to discover the health of the server.
-        /// </summary>
-        /// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
-        /// <returns>An <see cref="GrpcServiceEndpointConventionBuilder"/> for endpoints associated with the service.</returns>
-        public static GrpcServiceEndpointConventionBuilder MapGrpcHealthChecksService(this IEndpointRouteBuilder builder)
-        {
-            if (builder == null)
-            {
-                throw new ArgumentNullException(nameof(builder));
-            }
-
-            return builder.MapGrpcService<HealthServiceImpl>();
-        }
-    }
-}

+ 0 - 56
TEAMModelGrpc/GrpcHealthCheck/GrpcHealthChecksPublisher.cs

@@ -1,56 +0,0 @@
-#region Copyright notice and license
-
-// Copyright 2019 The gRPC Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#endregion
-
-using System.Threading;
-using System.Threading.Tasks;
-using Grpc.Health.V1;
-using Grpc.HealthCheck;
-using Microsoft.Extensions.Diagnostics.HealthChecks;
-
-namespace Grpc.AspNetCore.HealthChecks
-{
-    internal class GrpcHealthChecksPublisher : IHealthCheckPublisher
-    {
-        private readonly HealthServiceImpl _healthService;
-
-        public GrpcHealthChecksPublisher(HealthServiceImpl healthService)
-        {
-            _healthService = healthService;
-        }
-
-        public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
-        {
-            foreach (var entry in report.Entries)
-            {
-                var status = entry.Value.Status;
-
-                _healthService.SetStatus(entry.Key, ResolveStatus(status));
-            }
-
-            return Task.CompletedTask;
-        }
-
-        private static HealthCheckResponse.Types.ServingStatus ResolveStatus(HealthStatus status)
-        {
-            return status == HealthStatus.Unhealthy
-                ? HealthCheckResponse.Types.ServingStatus.NotServing
-                : HealthCheckResponse.Types.ServingStatus.Serving;
-        }
-    }
-
-}

+ 0 - 0
TEAMModelGrpc/GrpcHealthCheck/GrpcHealthChecksServiceExtensions.cs


Some files were not shown because too many files changed in this diff