Browse Source

Merge branch 'develop6.0-tmd' of http://52.130.252.100:10000/TEAMMODEL/TEAMModelOS into develop6.0-tmd

chenmy 3 years ago
parent
commit
3b3068c34d
100 changed files with 2853 additions and 1627 deletions
  1. 10 1
      TEAMModelAPI/Controllers/School/CourseController.cs
  2. 1 1
      TEAMModelAPI/Controllers/School/GroupListController.cs
  3. 1 2
      TEAMModelAPI/Controllers/School/RoomController.cs
  4. 171 1
      TEAMModelAPI/Controllers/School/TeacherController.cs
  5. 14 22
      TEAMModelBI/Controllers/BIHome/HomeStatisController.cs
  6. 9 2
      TEAMModelBI/Controllers/BINormal/AppCompanyController.cs
  7. 182 47
      TEAMModelBI/Controllers/BISchool/SchoolController.cs
  8. 7 2
      TEAMModelBI/Controllers/BITest/TestController.cs
  9. 159 7
      TEAMModelBI/Controllers/Census/ActivitySticsController.cs
  10. 193 28
      TEAMModelBI/Controllers/Census/LessonSticsController.cs
  11. 1 1
      TEAMModelBI/Controllers/Census/SchoolController.cs
  12. 49 11
      TEAMModelBI/Tool/CommonFind.cs
  13. 72 0
      TEAMModelBI/Tool/TimeHelper.cs
  14. 3 3
      TEAMModelOS.FunctionV4/CosmosDB/TriggerCorrect.cs
  15. 3 3
      TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs
  16. 4 3
      TEAMModelOS.FunctionV4/CosmosDB/TriggerExamLite.cs
  17. 4 3
      TEAMModelOS.FunctionV4/CosmosDB/TriggerHomework.cs
  18. 4 3
      TEAMModelOS.FunctionV4/CosmosDB/TriggerStudy.cs
  19. 4 3
      TEAMModelOS.FunctionV4/CosmosDB/TriggerSurvey.cs
  20. 3 3
      TEAMModelOS.FunctionV4/CosmosDB/TriggerVote.cs
  21. 59 13
      TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs
  22. 3 3
      TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj
  23. 1 1
      TEAMModelOS.FunctionV4/local.settings.json
  24. 26 48
      TEAMModelOS.SDK/DI/AzureServiceBus/AzureServiceBusExtensions.cs
  25. 2 0
      TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs
  26. 4 2
      TEAMModelOS.SDK/Models/Cosmos/School/TeacherImport.cs
  27. 4 4
      TEAMModelOS.SDK/Models/Service/LessonService.cs
  28. 5 10
      TEAMModelOS/ClientApp/src/api/spaceAuth.js
  29. 8 0
      TEAMModelOS/ClientApp/src/common/AbilityUpload.vue
  30. 10 10
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  31. 10 1
      TEAMModelOS/ClientApp/src/common/BaseNotification.vue
  32. 1 1
      TEAMModelOS/ClientApp/src/common/BaseSelectSchool.vue
  33. 2 2
      TEAMModelOS/ClientApp/src/common/BaseUserPoptip.vue
  34. 96 0
      TEAMModelOS/ClientApp/src/common/PersonalPhoto.vue
  35. 55 55
      TEAMModelOS/ClientApp/src/components/student-web/EventBasicInfo.vue
  36. 5 5
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContent.vue
  37. 9 0
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.less
  38. 166 119
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue
  39. 35 69
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperView.vue
  40. 3 3
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventList.vue
  41. 27 8
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/CourseListView.vue
  42. 73 1
      TEAMModelOS/ClientApp/src/css/common-style.less
  43. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/ability.js
  44. 9 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/home.js
  45. 6 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/notice.js
  46. 3 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolBaseInfo.js
  47. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/studentWeb.js
  48. 51 45
      TEAMModelOS/ClientApp/src/locale/lang/en-US/teachermgmt.js
  49. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/ability.js
  50. 10 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/home.js
  51. 6 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/notice.js
  52. 3 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/schoolBaseInfo.js
  53. 2 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/studentWeb.js
  54. 13 7
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachermgmt.js
  55. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/ability.js
  56. 9 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/home.js
  57. 6 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/notice.js
  58. 4 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/schoolBaseInfo.js
  59. 2 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/studentWeb.js
  60. 33 27
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/teachermgmt.js
  61. 41 2
      TEAMModelOS/ClientApp/src/router/routes.js
  62. 0 2
      TEAMModelOS/ClientApp/src/store/index.js
  63. 14 1
      TEAMModelOS/ClientApp/src/store/module/answerSheet.js
  64. 2 0
      TEAMModelOS/ClientApp/src/store/module/config.js
  65. 0 185
      TEAMModelOS/ClientApp/src/store/module/spaceAuth.js
  66. 74 318
      TEAMModelOS/ClientApp/src/store/module/user.js
  67. 0 1
      TEAMModelOS/ClientApp/src/utils/js-fn.js
  68. 5 6
      TEAMModelOS/ClientApp/src/view/Home.vue
  69. 1 1
      TEAMModelOS/ClientApp/src/view/ability/Ability.vue
  70. 1 1
      TEAMModelOS/ClientApp/src/view/ability/GroupReview.vue
  71. 6 3
      TEAMModelOS/ClientApp/src/view/ability/Review.vue
  72. 1 1
      TEAMModelOS/ClientApp/src/view/areaMgmt/AreaBase.vue
  73. 1 1
      TEAMModelOS/ClientApp/src/view/areatrain/Create.vue
  74. 1 1
      TEAMModelOS/ClientApp/src/view/forgotPw/Index.vue
  75. 9 9
      TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue
  76. 6 2
      TEAMModelOS/ClientApp/src/view/jyzx/application.vue
  77. 1 1
      TEAMModelOS/ClientApp/src/view/jyzx/index.vue
  78. 1 1
      TEAMModelOS/ClientApp/src/view/jyzx/offline.vue
  79. 19 14
      TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.less
  80. 15 19
      TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.vue
  81. 10 60
      TEAMModelOS/ClientApp/src/view/learnactivity/echarts/CognitineLevel.vue
  82. 7 164
      TEAMModelOS/ClientApp/src/view/learnactivity/echarts/KngPoint.vue
  83. 1 1
      TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkSetting.vue
  84. 35 5
      TEAMModelOS/ClientApp/src/view/learnactivity/tabs/DataView.vue
  85. 3 3
      TEAMModelOS/ClientApp/src/view/login/Index.vue
  86. 3 27
      TEAMModelOS/ClientApp/src/view/login/page/Teacher.vue
  87. 1 1
      TEAMModelOS/ClientApp/src/view/newcourse/NewCusMgt.vue
  88. 1 0
      TEAMModelOS/ClientApp/src/view/newsheet/index.vue
  89. 1 1
      TEAMModelOS/ClientApp/src/view/regist/Index.vue
  90. 514 0
      TEAMModelOS/ClientApp/src/view/research-center/ResearchCenterMock.vue
  91. 22 92
      TEAMModelOS/ClientApp/src/view/schoolmgmt/SystemSetting/SystemSetting.vue
  92. 1 1
      TEAMModelOS/ClientApp/src/view/sso/Index.vue
  93. 9 10
      TEAMModelOS/ClientApp/src/view/student-account/class/ClassMgt.vue
  94. 1 1
      TEAMModelOS/ClientApp/src/view/student-web/App.vue
  95. 12 5
      TEAMModelOS/ClientApp/src/view/teachermgmt/Index.less
  96. 81 93
      TEAMModelOS/ClientApp/src/view/teachermgmt/Index.vue
  97. 7 2
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/group/Group.vue
  98. 88 0
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/import/Import.vue
  99. 199 0
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/mgt/SpaceStatusChart.vue
  100. 0 0
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/mgt/TeacherMgt.less

+ 10 - 1
TEAMModelAPI/Controllers/School/CourseController.cs

@@ -146,7 +146,11 @@ namespace TEAMModelAPI.Controllers
                     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);
@@ -269,7 +273,12 @@ namespace TEAMModelAPI.Controllers
                 if (importCourse != null) {
                     Period period= data.period.Find(x => x.id.Equals(importCourse.periodId));
                     if (period != null) {
-                        Subject subject=   period.subjects.Find(x => x.id.Equals(importCourse.subjectId));
+                        //同名学科
+                        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);

+ 1 - 1
TEAMModelAPI/Controllers/School/GroupListController.cs

@@ -458,7 +458,7 @@ namespace TEAMModelAPI.Controllers
         }
 
         /// <summary>
-        /// 导入教学班学生
+        /// 移除教学班学生
         /// </summary>
         /// <param name="request"></param>
         /// <returns></returns>

+ 1 - 2
TEAMModelAPI/Controllers/School/RoomController.cs

@@ -124,7 +124,7 @@ namespace TEAMModelAPI.Controllers
                 {
                     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));
@@ -158,6 +158,5 @@ namespace TEAMModelAPI.Controllers
             }
             return Ok(new { roomUpdate= db_rooms, roomCreate= roomCreate });
         }
-
     }
 }

+ 171 - 1
TEAMModelAPI/Controllers/School/TeacherController.cs

@@ -28,6 +28,7 @@ using Azure.Storage.Blobs.Models;
 using HTEXLib.COMM.Helpers;
 using Microsoft.AspNetCore.Authorization;
 using System.Net.Http;
+using System.ComponentModel.DataAnnotations;
 
 namespace TEAMModelAPI.Controllers
 {
@@ -105,7 +106,7 @@ namespace TEAMModelAPI.Controllers
             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,x.name,x.picture,x.job,x.subjectIds,x.roles,coreUser.searchKey });
+                    tchs.Add(new {x.id,coreUser.name, coreUser.picture,x.job,x.subjectIds,x.roles,coreUser.searchKey });
                 }
             });
             return Ok(new
@@ -158,5 +159,174 @@ namespace TEAMModelAPI.Controllers
             }
         }
 
+         
+        /// <summary>
+        /// 批量导入教师信息,并加入学校。可以导入学科,但需要填写学段id
+        /// </summary>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("import-school-teacher")]
+        [ApiToken(Auth = "1502", Name = "学校教师信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> ImportSchoolTeacher(JsonElement json) {
+            //如果需要同时导入学科,则需要填写学段
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            if (!json.TryGetProperty("teachers", out JsonElement _teachers) || !_teachers.ValueKind.Equals(JsonValueKind.Array)) { return BadRequest(); }
+            IEnumerable<ImportTech> teachers = _teachers.ToObject<List<ImportTech>>();
+            var result = teachers.Valid();
+            if (!result.isVaild)
+            {
+                return Ok(new { error = 2, msg = result });
+            }
+            List<string> searchKey = teachers.Select(x=>x.id).ToList();
+            var keys = searchKey.Where(x => !string.IsNullOrWhiteSpace(x));
+            var content = new StringContent(keys.ToJsonString(), Encoding.UTF8, "application/json");
+            string 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));
+           
+            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"));
+            //学校学科发生变化。
+            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="join",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 = "join", 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
+                    {
+                        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 = "join", 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 = "join",
+                        code = $"Teacher-{school}",
+                        pk = "Teacher",
+                        createTime = now,
+                    };
+                    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;
+                    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();
+        }
     }
+    public class ImportTech {
+        [Required(ErrorMessage = "教师id必须设置")]
+        public string id { get; set; }
+        public List<ImportTechSubject> subjects { get; set; }
+        [ RegularExpression(@"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}", ErrorMessage = "学段的uuid格式错误!")]
+        public string periodId { get; set; }
+        public string job { get; set; }
+    }
+    public class ImportTechSubject
+    {
+        [RegularExpression(@"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}", ErrorMessage = "科目的uuid格式错误!")]
+        public string id { get; set; }
+        [Required(ErrorMessage = "科目名称 必须设置")]
+        public string name { get; set; }
+    }
+
 }

+ 14 - 22
TEAMModelBI/Controllers/BIHome/HomeStatisController.cs

@@ -698,7 +698,7 @@ namespace TEAMModelBI.Controllers.BIHome
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"BI,{_option.Location} /homestatis/get-sticsbipower  {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+                await _dingDing.SendBotMsg($"BI,{_option.Location} /homestatis/get-sticsbipower  \n {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
                 return BadRequest();
             }
         }
@@ -720,16 +720,10 @@ namespace TEAMModelBI.Controllers.BIHome
 
                 List<string> schoolId = new();
                 var cosmosClient = _azureCosmos.GetCosmosClient();
+
                 //查询学校空间和学校Id
-                await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS,"School").GetItemQueryStreamIterator(queryText:$"select c.id,c.size from c",requestOptions:new QueryRequestOptions() { PartitionKey = new PartitionKey("Base")}))
-                {
-                    var json = await JsonDocument.ParseAsync(item.ContentStream);
-                    foreach (var tempItem in json.RootElement.GetProperty("Documents").EnumerateArray())
-                    {
-                        totalSize += tempItem.GetProperty("size").GetInt64();
-                        schoolId.Add(tempItem.GetProperty("id").GetString());
-                    }
-                }
+                totalSize = await CommonFind.FindTotals(cosmosClient, "select sum(c.size) as totals from c", "School", "Base");
+                schoolId = await CommonFind.FindSchoolIds(cosmosClient, "select c.id,c.size from c", "Base");
 
                 //查询学校已使用空间大小
                 foreach (var itemId in schoolId)
@@ -748,16 +742,13 @@ namespace TEAMModelBI.Controllers.BIHome
                         }
                     }
 
-                    Dictionary<string, double?> schoolStics = new(); //学校空间
                     long blobsize = 0;
                     RedisValue value = default;
                     value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", itemId);
                     if (value != default && !value.IsNullOrEmpty)
                     {
                         JsonElement record = value.ToString().ToObject<JsonElement>();
-                        if (record.TryGetInt64(out blobsize))
-                        {
-                        }
+                        if (record.TryGetInt64(out blobsize)){}
                     }
                     else
                     {
@@ -769,15 +760,16 @@ namespace TEAMModelBI.Controllers.BIHome
                             await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{itemId}", key);
                             await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{itemId}", key, size.Item2[key].HasValue ? size.Item2[key].Value : 0);
                         }
-                        useSize += (long)size.Item1;
-                        schoolStics = size.Item2;
-                        typeStics1 = (from e in typeStics1.Concat(schoolStics) group e by e.Key into g select new { Name = g.Key, Count = g.Sum(kvp => kvp.Value) }).ToDictionary(item => item.Name, item => item.Count);
+                        useSize += size.Item1.Value;
+                        typeStics1 = typeStics1.Concat(size.Item2).GroupBy(g => g.Key).ToDictionary(k => k.Key, k => k.Sum(kvp => kvp.Value));  //lamebda表达式
+                        //typeStics1 = (from e in typeStics1.Concat(schoolStics) group e by e.Key into g select new { Name = g.Key, Count = g.Sum(kvp => kvp.Value) }).ToDictionary(item => item.Name, item => item.Count);
                         continue;
                     }
 
                     SortedSetEntry[] Scores = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Blob:Catalog:{itemId}");
                     if (Scores != null)
                     {
+                        Dictionary<string, double?> schoolStics = new(); //学校空间
                         foreach (var score in Scores)
                         {
                             double val = score.Score;
@@ -786,10 +778,10 @@ namespace TEAMModelBI.Controllers.BIHome
                         }
 
                         useSize += blobsize;
-                        typeStics1 = (from e in typeStics1.Concat(schoolStics) group e by e.Key into g select new { Name = g.Key, Count = g.Sum(kvp => kvp.Value) }).ToDictionary(item => item.Name, item => item.Count);
+                        typeStics1 = typeStics1.Concat(schoolStics).GroupBy(g => g.Key).ToDictionary(k => k.Key, k => k.Sum(kvp => kvp.Value));  //lamebda表达式
+                        //typeStics1 = (from e in typeStics1.Concat(schoolStics) group e by e.Key into g select new { Name = g.Key, Count = g.Sum(kvp => kvp.Value) }).ToDictionary(item => item.Name, item => item.Count);
                         continue;
 
-                        //return Ok(new { size = blobsize, catalog = catalog, teach });
                     }
                     else
                     {
@@ -802,9 +794,9 @@ namespace TEAMModelBI.Controllers.BIHome
                             await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{itemId}", key, size.Item2[key].HasValue ? size.Item2[key].Value : 0);
                         }
 
-                        useSize += (long)size.Item1;
-                        schoolStics = size.Item2;
-                        typeStics1 = (from e in typeStics1.Concat(schoolStics) group e by e.Key into g select new { Name = g.Key, Count = g.Sum(kvp => kvp.Value) }).ToDictionary(item => item.Name, item => item.Count);
+                        useSize += size.Item1.Value;
+                        typeStics1 = typeStics1.Concat(size.Item2).GroupBy(g => g.Key).ToDictionary(k => k.Key, k => k.Sum(kvp => kvp.Value));  //lamebda表达式
+                        //typeStics1 = (from e in typeStics1.Concat(schoolStics) group e by e.Key into g select new { Name = g.Key, Count = g.Sum(kvp => kvp.Value) }).ToDictionary(item => item.Name, item => item.Count);
                         continue;
                     }
 

+ 9 - 2
TEAMModelBI/Controllers/BINormal/AppCompanyController.cs

@@ -10,6 +10,7 @@ using System.Text;
 using System.Text.Json;
 using System.Threading.Tasks;
 using TEAMModelBI.Filter;
+using TEAMModelBI.Models.Extension;
 using TEAMModelBI.Tool.Extension;
 using TEAMModelOS.Models;
 using TEAMModelOS.SDK.DI;
@@ -237,16 +238,18 @@ namespace TEAMModelBI.Controllers.BINormal
                         if (bool.Parse($"{isAudit}") == true)
                         {
                             appCompany.audit = 1;
+                            appCompany.jwtKey = JwtAuth.CreateApplyJwtKeyBI(_option.HostName, _option.JwtSecretKey, appCompany);
                             strMsg.Append("通过。");
                         }
                         else
                         {
                             appCompany.audit = 0;
                             appCompany.refuseDesc = $"{refuseDesc}";
-                            strMsg.Append("失败。");
+                            strMsg.Append("拒绝通过。");
                         }
                         try
                         {
+                            
                             await cosmosClient.GetContainer("TEAMModelOS", "Normal").ReplaceItemAsync<AppCompany>(appCompany, appCompany.id, new PartitionKey(idCode.code));
                         }
                         catch
@@ -342,6 +345,7 @@ namespace TEAMModelBI.Controllers.BINormal
                                         {
                                             appApiState.status = 1;
                                             appApiState.refuseDesc = null;
+                                            appCompany.jwtKey = JwtAuth.CreateApplyJwtKeyBI(_option.HostName, _option.JwtSecretKey, appCompany);
                                             strMsg.Append($"{appApiState.no}通过,");
                                         }
                                         else
@@ -468,6 +472,7 @@ namespace TEAMModelBI.Controllers.BINormal
                                 {
                                     applySchool.status = 1;
                                     applySchool.refuseDesc = null;
+                                    appCompany.jwtKey = JwtAuth.CreateApplyJwtKeyBI(_option.HostName, _option.JwtSecretKey, appCompany);
                                     strMsg.Append($"审核成功。");
                                 }
                                 else
@@ -523,7 +528,6 @@ namespace TEAMModelBI.Controllers.BINormal
             }
         }
 
-
         /// <summary>
         /// 应用申请和审核api信息
         /// </summary>
@@ -543,6 +547,9 @@ namespace TEAMModelBI.Controllers.BINormal
             public string code { get; set; }
         }
 
+        /// <summary>
+        /// 未审核应用
+        /// </summary>
         public record NoAudit 
         { 
             public string id { get; set; }

+ 182 - 47
TEAMModelBI/Controllers/BISchool/SchoolController.cs

@@ -34,7 +34,7 @@ namespace TEAMModelBI.Controllers.BISchool
         private readonly IConfiguration _configuration;
         private readonly NotificationService _notificationService;
 
-        public SchoolController(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option, AzureRedisFactory azureRedis, IConfiguration configuration, NotificationService notificationService) 
+        public SchoolController(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option, AzureRedisFactory azureRedis, IConfiguration configuration, NotificationService notificationService)
         {
             _azureCosmos = azureCosmos;
             _dingDing = dingDing;
@@ -51,14 +51,14 @@ namespace TEAMModelBI.Controllers.BISchool
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-notarea")]
-        public async Task<IActionResult> GetNotAreaSchool() 
+        public async Task<IActionResult> GetNotAreaSchool()
         {
             try
             {
                 var cosmosClient = _azureCosmos.GetCosmosClient();
                 string sqltxt = $"SELECT c.id,c.name,c.schoolCode,c.province,c.city,c.dist,c.picture,c.period FROM c WHERE c.standard=null";
                 List<NotAreaSchool> notAreaSchools = new List<NotAreaSchool>();
-                await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: sqltxt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") })) 
+                await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: sqltxt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
                 {
                     using var json = await JsonDocument.ParseAsync(item.ContentStream);
                     if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
@@ -99,7 +99,7 @@ namespace TEAMModelBI.Controllers.BISchool
         [ProducesDefaultResponseType]
         [AuthToken(Roles = "assist")]
         [HttpPost("set-schooljoinarea")]
-        public async Task<IActionResult> SetSchoolJoinArea(JsonElement jsonElement) 
+        public async Task<IActionResult> SetSchoolJoinArea(JsonElement jsonElement)
         {
             try
             {
@@ -112,13 +112,13 @@ namespace TEAMModelBI.Controllers.BISchool
                 List<string> schoolCodes = _schoolCode.ToObject<List<string>>();
 
                 var cosmosCliet = _azureCosmos.GetCosmosClient();
-                
-                if (schoolCodes.Count > 0) 
+
+                if (schoolCodes.Count > 0)
                 {
-                    foreach (var tempCode in schoolCodes) 
+                    foreach (var tempCode in schoolCodes)
                     {
-                        School school = await cosmosCliet.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(tempCode,new PartitionKey("Base"));
-                        if (school != null) 
+                        School school = await cosmosCliet.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(tempCode, new PartitionKey("Base"));
+                        if (school != null)
                         {
                             school.standard = $"{standard}";
                             school.areaId = $"{_areaId}";
@@ -144,13 +144,13 @@ namespace TEAMModelBI.Controllers.BISchool
         /// </summary>
         /// <param name="jsonElement"></param>
         /// <returns></returns>
-        [HttpPost("get-assustschool")]
+        [HttpPost("get-assistschool")]
         public async Task<IActionResult> GetAssistSchool(JsonElement jsonElement)
         {
             try
             {
                 if (!jsonElement.TryGetProperty("tmdId", out JsonElement tmdId)) return BadRequest();
-              
+
                 List<object> schools = new List<object>();
                 var cosmosClient = _azureCosmos.GetCosmosClient();
                 //List<string> schoolIds = new List<string>();
@@ -182,7 +182,7 @@ namespace TEAMModelBI.Controllers.BISchool
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"BI,{_option.Location}   /schoolcheck/get-assustschool   {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+                await _dingDing.SendBotMsg($"BI,{_option.Location}   /schoolcheck/get-assustschool  \n {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
                 return BadRequest();
             }
         }
@@ -205,7 +205,7 @@ namespace TEAMModelBI.Controllers.BISchool
                 if (rsponse.Status == 200)
                 {
                     using var json = await JsonDocument.ParseAsync(rsponse.ContentStream);
-                    School school  = json.ToObject<School>();
+                    School school = json.ToObject<School>();
 
                     return Ok(new { state = 200, school });
                 }
@@ -215,7 +215,7 @@ namespace TEAMModelBI.Controllers.BISchool
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"BI,{_option.Location}   /schoolcheck/get-schoolid   {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+                await _dingDing.SendBotMsg($"BI,{_option.Location}   /schoolcheck/get-schoolid  \n {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
                 return BadRequest();
             }
         }
@@ -257,8 +257,8 @@ namespace TEAMModelBI.Controllers.BISchool
                         }
                         await cosmosClient.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync(item, item.id, new PartitionKey($"Base"));
                     }
-                    schoolInfo = await cosmosClient.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<School>(school,school.id, new PartitionKey($"Base"));
-                    
+                    schoolInfo = await cosmosClient.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<School>(school, school.id, new PartitionKey($"Base"));
+
                     //保存操作记录
                     await _azureStorage.SaveBILog("school-update", $"{tmdName}【{tmdId}】修改学校信息,学校和ID:{school.name}【{school.id}】", _dingDing, httpContext: HttpContext);
                 }
@@ -309,18 +309,19 @@ namespace TEAMModelBI.Controllers.BISchool
         /// </summary>
         /// <param name="jsonElement"></param>
         /// <returns></returns>
-        [HttpPost("get-space")]
-        public async Task<IActionResult> GetAssistSchoolSpace(JsonElement jsonElement) 
+        [HttpPost("get-assistspace")]
+        public async Task<IActionResult> GetAssistSchoolSpace(JsonElement jsonElement)
         {
             if (!jsonElement.TryGetProperty("tmdId", out JsonElement tmdId)) return BadRequest();
             var cosmosClient = _azureCosmos.GetCosmosClient();
+
             List<string> schools = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
-            List<SchoolSpace> schoolSpaces = new List<SchoolSpace>();
+            List<SchoolSpace> schoolSpaces = new();
             foreach (var sid in schools)
             {
                 School school = new();
                 var response = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(sid, new PartitionKey("Base"));
-                if (response.Status == 200) 
+                if (response.Status == 200)
                 {
                     using var json = await JsonDocument.ParseAsync(response.ContentStream);
                     school = json.ToObject<School>();
@@ -340,7 +341,7 @@ namespace TEAMModelBI.Controllers.BISchool
                     }
                 }
 
-                SchoolSpace schoolSpace = new SchoolSpace() { id = sid, name = school != null ? school.name : sid };
+                SchoolSpace schoolSpace = new() { id = sid, name = school != null ? school.name : sid };
 
                 Space space = new Space();
                 long blobsize = 0; //使用大小                
@@ -354,7 +355,7 @@ namespace TEAMModelBI.Controllers.BISchool
                     {
                     }
                 }
-                else 
+                else
                 {
                     var client = _azureStorage.GetBlobContainerClient(sid);
                     var size = await client.GetBlobsCatalogSize();
@@ -398,8 +399,8 @@ namespace TEAMModelBI.Controllers.BISchool
                         await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{sid}", key, size.Item2[key].HasValue ? size.Item2[key].Value : 0);
                     }
 
-                    space.useSize = (long)size.Item1; 
-                    space.tSize = teach; 
+                    space.useSize = (long)size.Item1;
+                    space.tSize = teach;
                     space.catalogSize = size.Item2;
                     schoolSpace.space = space;
                     schoolSpaces.Add(schoolSpace);
@@ -429,7 +430,7 @@ namespace TEAMModelBI.Controllers.BISchool
             {
                 schoolTeacher.roles.Remove("assist");
                 SchoolTeacher newSchoolTeacher = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemAsync<SchoolTeacher>($"{_shiftTeacher}", new PartitionKey($"Teacher-{_school}"));
-                if (!newSchoolTeacher.roles.Contains("assist")) 
+                if (!newSchoolTeacher.roles.Contains("assist"))
                 {
                     newSchoolTeacher.roles.Add("assist");
                     newSchoolTeacher = await cosmosClient.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<SchoolTeacher>(newSchoolTeacher, $"{_shiftTeacher}", new PartitionKey($"Teacher-{_school}"));
@@ -452,7 +453,7 @@ namespace TEAMModelBI.Controllers.BISchool
                     expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
                 };
 
-                if (notification != null) 
+                if (notification != null)
                 {
                     var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
                     var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
@@ -474,7 +475,7 @@ namespace TEAMModelBI.Controllers.BISchool
         /// <param name="jsonElement"></param>
         /// <returns></returns>
         [HttpPost("get-schoolmanage")]
-        public async Task<IActionResult> GetSchoolManage(JsonElement jsonElement) 
+        public async Task<IActionResult> GetSchoolManage(JsonElement jsonElement)
         {
             if (!jsonElement.TryGetProperty("schoolCode", out JsonElement schoolCode)) return BadRequest();
             if (!jsonElement.TryGetProperty("isAdmin", out JsonElement isAdmin)) return BadRequest();
@@ -512,7 +513,6 @@ namespace TEAMModelBI.Controllers.BISchool
             return Ok(new { state = 200, schoolTeachers });
         }
 
-
         /// <summary>
         /// 设置学校管理员
         /// </summary>
@@ -575,7 +575,7 @@ namespace TEAMModelBI.Controllers.BISchool
                 await _dingDing.SendBotMsg($"BI,{_option.Location}  /batchschool/set-schoolme \n {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
                 return BadRequest();
             }
-            
+
         }
 
         /// <summary>
@@ -610,32 +610,167 @@ namespace TEAMModelBI.Controllers.BISchool
             return Ok(new { state = 200, schools });
         }
 
-
         /// <summary>
-        /// 修改学校的结构
+        /// 依据区域Id查询区域空间统计
         /// </summary>
-        public record ReplaceSchool()
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-spance")]
+        public async Task<IActionResult> GetAreaSpace(JsonElement jsonElement)
         {
-            /// <summary>
-            /// 醍摩豆账户ID
-            /// </summary>
-            public string tmdId { get; set; }
+            jsonElement.TryGetProperty("areaId", out JsonElement areaId);
+            jsonElement.TryGetProperty("schoolId", out JsonElement schoolId);
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+            long allSize = 0;    //全部大小
+            int teacherSpace = 0;  //学校分配给教师的空间
+            long useSize = 0;   //已使用大小 
+            Dictionary<string, double?> useSpaceInfo = new();  //学校使用详情
 
-            /// <summary>
-            /// 醍摩豆账户名称
-            /// </summary>
-            public string tmdName { get; set; }
+            //查询区域所有学校
+            if (!string.IsNullOrEmpty($"{areaId}"))
+            {
+                List<string> schools = new();
+                schools = await CommonFind.FindSchoolIds(cosmosClient, $"select c.id from c where c.areaId='{areaId}'", "Base");
 
-            /// <summary>
-            /// 学校
-            /// </summary>
-            public School school { get; set; }
+                allSize = await CommonFind.FindTotals(cosmosClient, $"select sum(c.size) as totals from c where c.areaId='{areaId}'", new List<string> { "School" }); //区域所有学校空间
+
+                foreach (var school in schools)
+                {
+                    await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: $"SELECT sum(c.size) as size FROM c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school}") }))
+                    {
+                        var json = await JsonDocument.ParseAsync(item.ContentStream);
+                        foreach (var elmt in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            if (elmt.TryGetProperty("size", out JsonElement _size) && _size.ValueKind.Equals(JsonValueKind.Number))
+                            {
+                                teacherSpace += _size.GetInt32();
+                                break;
+                            }
+                        }
+                    }
+
+                    long blobsize = 0;
+                    RedisValue value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", $"{school}");
+                    if (!value.IsNullOrEmpty)
+                    {
+                        JsonElement record = value.ToString().ToObject<JsonElement>();
+                        if (record.TryGetInt64(out blobsize))
+                        {
+                        }
+                    }
+                    else
+                    {
+                        var storageClient = _azureStorage.GetBlobContainerClient("school");
+                        var size = await storageClient.GetBlobsCatalogSize();
+                        await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", $"{school}", size.Item1);
+                        foreach (var key in size.Item2.Keys)
+                        {
+                            await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Bolb:Catalog:{school}", key);
+                            await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Bolb:Catalog:school", key, size.Item2[key].HasValue ? size.Item2[key].Value : 0);
+                        }
+
+                        useSize += size.Item1.Value;
+                        useSpaceInfo = useSpaceInfo.Concat(size.Item2).GroupBy(g => g.Key).ToDictionary(k => k.Key, k => k.Sum(kvp => kvp.Value));   //lamebda表达式
+                        //useSpaceInfo = (from e in useSpaceInfo.Concat(size.Item2) group e by e.Key into g select new { Name = g.Key, value = g.Sum(kvp => kvp.Value) }).ToDictionary(item => item.Name, item => item.value);  //linq 方式合并
+                    }
+
+                    SortedSetEntry[] Scores = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Blob:Catalog:{school}");
+                    if (Scores != null)
+                    {
+                        Dictionary<string, double?> catalog = new();
+                        foreach (var score in Scores)
+                        {
+                            double val = score.Score;
+                            string key = score.Element.ToString();
+                            catalog.Add(key, val);
+                        }
+                        useSpaceInfo = useSpaceInfo.Concat(catalog).GroupBy(g => g.Key).ToDictionary(k => k.Key, k => k.Sum(kvp => kvp.Value));  //lamebda表达式
+                        //useSpaceInfo = (from e in useSpaceInfo.Concat(catalog) group e by e.Key into g select new { Name = g.Key, value = g.Sum(kvp => kvp.Value) }).ToDictionary(item => item.Name, item => item.value);  //linq 方式合并
+                    }
+                    else
+                    {
+                        var client = _azureStorage.GetBlobContainerClient("school");
+                        var size = await client.GetBlobsCatalogSize();
+                        await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", $"{school}", size.Item1);
+                        foreach (var key in size.Item2.Keys)
+                        {
+                            await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{school}", key);
+                            await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{school}", key, size.Item2[key].HasValue ? size.Item2[key].Value : 0);
+                        }
+                        useSize += size.Item1.Value;
+                        useSpaceInfo = useSpaceInfo.Concat(size.Item2).GroupBy(g => g.Key).ToDictionary(k => k.Key, k => k.Sum(kvp => kvp.Value));   //lamebda表达式
+                        //useSpaceInfo = (from e in useSpaceInfo.Concat(size.Item2) group e by e.Key into g select new { Name = g.Key, value = g.Sum(kvp => kvp.Value) }).ToDictionary(item => item.Name, item => item.value);   //linq 方式合并
+                    }
+                }
+            }
+
+            //查询学校
+            if (!string.IsNullOrEmpty($"{schoolId}"))
+            {
+                allSize = await CommonFind.FindTotals(cosmosClient, $"SELECT c.size as totals FROM c where c.id='{schoolId}'", "School", "Base");
+
+                teacherSpace = await CommonFind.FindTotals(cosmosClient, $"SELECT sum(c.size) as totals FROM c", "School", $"Teacher-{schoolId}");
+
+                long blobsize = 0;
+                RedisValue value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", $"{schoolId}");
+                if (!value.IsNullOrEmpty)
+                {
+                    JsonElement record = value.ToString().ToObject<JsonElement>();
+                    if (record.TryGetInt64(out blobsize))
+                    {
+                        useSize = blobsize;
+                    }
+                }
+                else
+                {
+                    var storageClient = _azureStorage.GetBlobContainerClient("school");
+                    var size = await storageClient.GetBlobsCatalogSize();
+                    await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", $"{schoolId}", size.Item1);
+                    foreach (var key in size.Item2.Keys)
+                    {
+                        await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Bolb:Catalog:{schoolId}", key);
+                        await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Bolb:Catalog:school", key, size.Item2[key].HasValue ? size.Item2[key].Value : 0);
+                    }
+                    useSpaceInfo = size.Item2;
+                }
+
+                Dictionary<string, double?> catalog = new();
+                SortedSetEntry[] Scores = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Blob:Catalog:{schoolId}");
+                if (Scores != null)
+                {
+                    foreach (var score in Scores)
+                    {
+                        double val = score.Score;
+                        string key = score.Element.ToString();
+                        catalog.Add(key, val);
+                    }
+
+                    useSpaceInfo = catalog;
+                }
+                else
+                {
+                    var client = _azureStorage.GetBlobContainerClient("school");
+                    var size = await client.GetBlobsCatalogSize();
+                    await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", $"{schoolId}", size.Item1);
+                    foreach (var key in size.Item2.Keys)
+                    {
+                        await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{schoolId}", key);
+                        await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{schoolId}", key, size.Item2[key].HasValue ? size.Item2[key].Value : 0);
+                    }
+
+                    useSize = size.Item1.Value;
+                    useSpaceInfo = size.Item2;
+                }
+            }
+
+            return Ok(new { state = 200, allSize, useSize, teacherSpace, useSpaceInfo });
         }
 
         /// <summary>
         /// 未加入区域的学校
         /// </summary>
-        public record NotAreaSchool 
+        public record NotAreaSchool
         {
             public string id { get; set; }
 
@@ -657,7 +792,7 @@ namespace TEAMModelBI.Controllers.BISchool
         /// <summary>
         /// 学校空间使用情况
         /// </summary>
-        public record SchoolSpace 
+        public record SchoolSpace
         {
             public string id { get; set; }
 
@@ -669,7 +804,7 @@ namespace TEAMModelBI.Controllers.BISchool
         /// <summary>
         /// 空间
         /// </summary>
-        public record Space 
+        public record Space
         {
             /// <summary>
             /// 已使用空间

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

@@ -632,9 +632,14 @@ namespace TEAMModelBI.Controllers.BITest
 
             List<MonthStartEnd> endList = TimeHelper.GetYearMonthlyStartEnd10(DateTimeOffset.UtcNow.Year);
             List<MonthStartEnd> endList1 = TimeHelper.GetYearMonthlyStartEnd13(DateTimeOffset.UtcNow.Year);
-            List<MonthStartEnd> endList2 = TimeHelper.monthsOfYear(DateTimeOffset.UtcNow.ToString());
+            //return Ok(new { strList, dateTime, year, start, end, endList, endList1, endList2 });
 
-            return Ok(new { strList, dateTime, year, start, end, endList, endList1 , endList2 });
+            var (start1, end1) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow);
+            var (start2, end2) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow,"week");
+            var (start3, end3) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow,"month");
+            var (start4, end4) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "year");
+
+            return Ok(new { start1, end1, start2, end2, start3, end3, start4, end4 });
         }
 
         public static List<string> monthsOfYear(string yearMonth)

+ 159 - 7
TEAMModelBI/Controllers/Census/ActivitySticsController.cs

@@ -14,6 +14,7 @@ using TEAMModelBI.Tool;
 using System.Text;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelBI.Models;
+using TEAMModelOS.SDK;
 
 namespace TEAMModelBI.Controllers.Census
 {
@@ -25,14 +26,16 @@ namespace TEAMModelBI.Controllers.Census
         private readonly AzureStorageFactory _azureStorage;
         private readonly DingDing _dingDing;
         private readonly Option _option;
+        private readonly CoreAPIHttpService _coreAPIHttpService;
         public readonly List<string> types = new List<string> { "Exam", "Survey", "Vote", "Homework" };
 
-        public ActivitySticsController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, DingDing dingDing, IOptionsSnapshot<Option> option)
+        public ActivitySticsController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, DingDing dingDing, IOptionsSnapshot<Option> option, CoreAPIHttpService coreAPIHttpService)
         {
             _azureCosmos = azureCosmos;
             _dingDing = dingDing;
             _azureStorage = azureStorage;
             _option = option?.Value;
+            _coreAPIHttpService = coreAPIHttpService;
         }
 
         /// <summary>
@@ -210,7 +213,6 @@ namespace TEAMModelBI.Controllers.Census
                 }
 
                 return Ok(new { state = 200, activityCounts });
-
             }
             else
             {
@@ -226,7 +228,143 @@ namespace TEAMModelBI.Controllers.Census
 
                 return Ok(new { state = 200, typeCount });
             }
+        }
+
+        /// <summary>
+        /// 统计区域的活动
+        /// </summary>
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [HttpPost("get-area")]
+        public async Task<IActionResult> GetAreaActovoty(JsonElement jsonElement) 
+        {
+            if (!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+            List<RecSchool> schools = new();
+
+            await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<RecSchool>(queryText: $"select c.id,c.name,c.picture,c.scale from c where c.areaId='{areaId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
+            {
+                schools.Add(item);
+            }
+
+            long exemAreaCount = 0;
+            long surveyAreaCount = 0;
+            long voteAreaCount = 0;
+            long homeworkAreaCount = 0;
+
+            List<ActivityCount> activityCount = new();
+            foreach (var school in schools)
+            {
+                ActivityCount tempCount = new ActivityCount() { id = school.id, name = school.name != null ? school.name : school.id };
+                foreach (var type in types)
+                {
+                    StringBuilder sqlTxt = new StringBuilder($"select COUNT(c.id) AS totals from c where c.pk='{type}' and c.school='{school.id}' ");                
+                    long totals = await CommonFind.FindTotals(cosmosClient, sqlTxt.ToString(), new List<string>() { "Common" });
+
+                    switch (type)
+                    {
+                        case "Exam":
+                            exemAreaCount += totals;
+                            break;
+                        case "Survey":
+                             surveyAreaCount += totals;
+                            break;
+                        case "Vote":
+                             voteAreaCount += totals;
+                            break;
+                        case "Homework":
+                             homeworkAreaCount += totals;
+                            break;
+                    }
+
+                    tempCount.census.Add(new KeyValuePair<object, long>(type, totals));
+                }
+                activityCount.Add(tempCount);
+            }
+
+            return Ok(new { state = 200, exemAreaCount, surveyAreaCount, voteAreaCount, homeworkAreaCount, activityCount });
+        }
+
+        /// <summary>
+        /// 依据区统计区级相关信息包括活动统计
+        /// </summary>
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [HttpPost("get-areastics")]
+        public async Task<IActionResult> GetAreaStics(JsonElement jsonElement) 
+        {
+            if (!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
+
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+            List<RecSchool> schools = new();
+            await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<RecSchool>(queryText: $"select c.id,c.name,c.picture,c.scale from c where c.areaId='{areaId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
+            {
+                schools.Add(item);
+            }
+            //区级人员
+            int countArea = 0;
+            //区级评审人员
+            int appraiseArea = 0;
+            long examAreaCount = 0;   //试卷活动
+            long surveyAreaCount = 0;  //问卷活动
+            long voteAreaCount = 0;   //投票活动
+            long homeworkAreaCount = 0;  //作业活动
+            List<SchoolInfos> schoolInfos = new();
+            List<ActivityCount> activityCount = new();
+
+            int totalTime = 0;
+            foreach (var school in schools)
+            {
+                int count = 0;
+                int appraise = 0;
+                await foreach (var info in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<bool>(queryText: $"select value(array_contains(c.permissions,'train-appraise')) from c", requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Teacher-{school.id}") }))
+                {
+                    if (info)
+                    {
+                        appraise += 1;
+                        appraiseArea += 1;
+                    }
+                    countArea += 1;
+                    count += 1;
+                }
 
+                //查询学校的总学时
+                totalTime += await CommonFind.FindTotals(cosmosClient, "SELECT sum(c.totalTime) as totals FROM c", "Teacher", $"TeacherTrain-{school.id}");
+                //查询学校参训人数
+                int tempCount = await CommonFind.FindTotals(cosmosClient, $"select array_length(c.members) as totals from c where c.type='yxtrain'", "School", $"GroupList-{school.id}");
+                //学校学生人数
+                long stuCount = await CommonFind.FindTotals(cosmosClient, $"select count(c.id) as totals from c", "Student", $"Base-{school.id}");
+
+                schoolInfos.Add(new SchoolInfos { schoolId = school.id, schoolName = school.name, picture = school.picture, scale = school.scale, teacherCount = count, studentCount = stuCount, appraiseCount = appraise, trainCount = tempCount });
+
+                ActivityCount tempActivity = new ActivityCount() { id = school.id, name = school.name != null ? school.name : school.id };
+                foreach (var type in types)
+                {
+                    StringBuilder sqlTxt = new StringBuilder($"select COUNT(c.id) AS totals from c where c.pk='{type}' and c.school='{school.id}' ");
+                    long totals = await CommonFind.FindTotals(cosmosClient, sqlTxt.ToString(), new List<string>() { "Common" });
+
+                    switch (type)
+                    {
+                        case "Exam":
+                            examAreaCount += totals;
+                            break;
+                        case "Survey":
+                            surveyAreaCount += totals;
+                            break;
+                        case "Vote":
+                            voteAreaCount += totals;
+                            break;
+                        case "Homework":
+                            homeworkAreaCount += totals;
+                            break;
+                    }
+
+                    tempActivity.census.Add(new KeyValuePair<object, long>(type, totals));
+                }
+                activityCount.Add(tempActivity);
+            }
+
+            return Ok(new { state = 200, schoolCount = schools.Count, countArea, totalTime, appraiseArea, examAreaCount, surveyAreaCount, voteAreaCount, homeworkAreaCount, schools = schoolInfos, schoolActivity = activityCount });
         }
 
         /// <summary>
@@ -275,22 +413,36 @@ namespace TEAMModelBI.Controllers.Census
         }
 
 
-
-        public record SchoolActivity 
+        public record RecSchool
         {
             public string id { get; set; }
             public string name { get; set; }
+            public string picture { get; set; }
+            public int scale { get; set; }
+        }
 
-            public long total { get; set; }
+        private class SchoolInfos
+        {
+            public string schoolId { get; set; }
+            public string schoolName { get; set; }
+            public string picture { get; set; }
+            //规模
+            public int scale { get; set; }
+            //教师人数
+            public int teacherCount { get; set; }
+            //学生人数
+            public long studentCount { get; set; }
+            //评审人数
+            public int appraiseCount { get; set; }
+            //参训人数
+            public int trainCount { get; set; }
         }
 
         public record ActivityCount 
         {
             public string id { get; set; }
             public string name { get; set; }
-
             public List<KeyValuePair<object, long>> census { get; set; } = new List<KeyValuePair<object, long>>();
-
         }
     }
 }

+ 193 - 28
TEAMModelBI/Controllers/Census/LessonSticsController.cs

@@ -28,12 +28,12 @@ namespace TEAMModelBI.Controllers.Census
         private readonly DingDing _dingDing;
         private readonly Option _option;
 
-        public LessonSticsController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureFactory, DingDing dingDing, IOptionsSnapshot<Option> option) 
+        public LessonSticsController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureFactory, DingDing dingDing, IOptionsSnapshot<Option> option)
         {
             _azureCosmos = azureCosmos;
             _azureStorage = azureFactory;
             _dingDing = dingDing;
-            _option = option?.Value;        
+            _option = option?.Value;
         }
 
         /// <summary>
@@ -48,15 +48,16 @@ namespace TEAMModelBI.Controllers.Census
             if (!jsonElement.TryGetProperty("term", out JsonElement term)) return BadRequest();
             var cosmosClient = _azureCosmos.GetCosmosClient();
             var (start, end) = TimeHelper.GetTermStartOrEnd(DateTime.Now);
-            object totals = new object();
+            object totals = new();
+            StringBuilder sqlTxt = new($"select COUNT(c.id) AS totals  from c where c.pk='LessonRecord'");
             if (!string.IsNullOrEmpty($"{tmdId}"))
             {
-                List<SchoolLen> schoolLens = new List<SchoolLen>();
+                List<SchoolLen> schoolLens = new();
 
                 List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
 
                 foreach (var itemId in schoolIds)
-                {                    
+                {
                     School school = new();
                     var response = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(itemId, new PartitionKey("Base"));
                     if (response.Status == 200)
@@ -65,11 +66,11 @@ namespace TEAMModelBI.Controllers.Census
                         school = json.ToObject<School>();
                     }
 
-                    SchoolLen schoolLen = new SchoolLen() { id = itemId, name = school.name != null ? school.name : itemId };
+                    SchoolLen schoolLen = new() { id = itemId, name = school.name != null ? school.name : itemId };
 
                     //string sqlTxt = $"SELECT COUNT(c.id) AS totals FROM c WHERE c.code='LessonRecord-{itemId}'";
-                    StringBuilder sqlTxt = new StringBuilder($"SELECT COUNT(c.id) AS totals FROM c WHERE c.code='LessonRecord-{itemId}'");
-                    if (bool.Parse($"{term}") == true) 
+                    sqlTxt.Append($" WHERE c.code='LessonRecord-{itemId}'");
+                    if (bool.Parse($"{term}") == true)
                     {
                         sqlTxt.Append($" and c.startTime >= {start} and c.startTime <= {end}");
                     }
@@ -80,9 +81,9 @@ namespace TEAMModelBI.Controllers.Census
                 }
                 totals = schoolLens;
             }
-            else 
+            else
             {
-                StringBuilder sqlTxt = new StringBuilder($"select COUNT(c.id) AS totals  from c where c.pk='LessonRecord'");
+                sqlTxt.Append($" where c.pk='LessonRecord'");
                 if (bool.Parse($"{term}") == true)
                 {
                     sqlTxt.Append($" and c.startTime >= {start} and c.startTime <= {end}");
@@ -111,7 +112,7 @@ namespace TEAMModelBI.Controllers.Census
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"BI,{_option.Location}  /lesson/get-total  {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+                await _dingDing.SendBotMsg($"BI,{_option.Location}  /lesson/get-total \n {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
                 return BadRequest();
             }
         }
@@ -123,16 +124,16 @@ namespace TEAMModelBI.Controllers.Census
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-assiist")]
-        public async Task<IActionResult> GetAssiist(JsonElement jsonElement) 
+        public async Task<IActionResult> GetAssiist(JsonElement jsonElement)
         {
             try
             {
                 if (!jsonElement.TryGetProperty("tmdId", out JsonElement tmdId)) return BadRequest();
                 var cosmosClient = _azureCosmos.GetCosmosClient();
-                List<SchoolLen> schoolLens = new List<SchoolLen>();
+                List<SchoolLen> schoolLens = new();
 
                 List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
-                
+
                 foreach (var itemId in schoolIds)
                 {
                     School school = new();
@@ -143,7 +144,7 @@ namespace TEAMModelBI.Controllers.Census
                         school = json.ToObject<School>();
                     }
 
-                    SchoolLen schoolLen = new SchoolLen() { id = itemId, name = school != null ? school.name : itemId };
+                    SchoolLen schoolLen = new() { id = itemId, name = school != null ? school.name : itemId };
                     string sqlTxt = $"SELECT COUNT(c.id) AS totals FROM c WHERE c.code='LessonRecord-{itemId}'";
                     schoolLen.totals = await CommonFind.FindTotals(cosmosClient, sqlTxt, new List<string>() { "School" });
 
@@ -173,12 +174,12 @@ namespace TEAMModelBI.Controllers.Census
             {
                 jsonElement.TryGetProperty("years", out JsonElement _years);
                 int years = DateTime.UtcNow.Year;
-                if (!string.IsNullOrEmpty($"{_years}")) 
+                if (!string.IsNullOrEmpty($"{_years}"))
                 {
                     years = _years.GetInt32();
                 }
 
-                List<SchoolLen> schoolLens = new List<SchoolLen>();
+                List<SchoolLen> schoolLens = new();
                 List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
                 foreach (string schoolId in schoolIds)
                 {
@@ -190,7 +191,7 @@ namespace TEAMModelBI.Controllers.Census
                         school = json.ToObject<School>();
                     }
 
-                    SchoolLen schoolLen = new SchoolLen() { id = schoolId, name = school != null ? school.name : schoolId };
+                    SchoolLen schoolLen = new() { id = schoolId, name = school != null ? school.name : schoolId };
 
                     List<List<double>> begin = new();
                     await foreach (var lcount in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<LessonCount>(queryText: "select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{schoolId}-{years}") }))
@@ -225,9 +226,9 @@ namespace TEAMModelBI.Controllers.Census
         [HttpPost("get-termcount")]
         public async Task<IActionResult> GetTermCount(JsonElement jsonElement) 
         {
-            if(jsonElement.TryGetProperty("tmdId", out JsonElement tmdId)) BadRequest();
+            if (jsonElement.TryGetProperty("tmdId", out JsonElement tmdId)) BadRequest();
             var cosmosClient = _azureCosmos.GetCosmosClient();
-            List<SchoolLen> schoolLens = new List<SchoolLen>();
+            List<SchoolLen> schoolLens = new();
             List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
             foreach (var scid in schoolIds)
             {
@@ -239,7 +240,7 @@ namespace TEAMModelBI.Controllers.Census
                     school = json.ToObject<School>();
                 }
 
-                SchoolLen schoolLen = new SchoolLen() { id = scid, name = !string.IsNullOrEmpty(school.name) ? school.name : scid };
+                SchoolLen schoolLen = new() { id = scid, name = !string.IsNullOrEmpty(school.name) ? school.name : scid };
 
                 DateTimeOffset dateTime = DateTimeOffset.UtcNow;
                 int year = (dateTime.Month <= 8 && dateTime.Month >= 3) ? dateTime.Year : dateTime.Year - 1;
@@ -259,15 +260,13 @@ namespace TEAMModelBI.Controllers.Census
                 List<LessonCount> tcount = new();
                 DenseMatrix dense = null;
                 var queryClass = $"select value(c) from c ";
-                await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LessonCount>(
-                            queryText: queryClass,
-                            requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{scid}-{syear}") }))
+                await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LessonCount>(queryText: queryClass, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{scid}-{syear}") }))
                 {
                     scount.Add(item);
                 }
                 if (tyear > syear)
                 {
-                    await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LessonCount>(queryText: queryClass,  requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{scid}-{tyear}") }))
+                    await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LessonCount>(queryText: queryClass, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{scid}-{tyear}") }))
                     {
                         tcount.Add(item);
                     }
@@ -283,7 +282,7 @@ namespace TEAMModelBI.Controllers.Census
                 }
                 if (scount.Count > 0)
                 {
-                    List<List<double>> begin = new List<List<double>>();
+                    List<List<double>> begin = new();
                     foreach (LessonCount lesson in scount)
                     {
                         begin.Add(lesson.beginCount);
@@ -317,6 +316,168 @@ namespace TEAMModelBI.Controllers.Census
             return Ok(new { state = 200, schoolLens });
         }
 
+        /// <summary>
+        /// 统计区级课例
+        /// </summary>
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-areacount")]
+        public async Task<IActionResult> GetAreaCount(JsonElement jsonElement) 
+        {
+            if (!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
+            List<string> schools = new();
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+
+            schools = await CommonFind.FindSchoolIds(cosmosClient, $"select c.id from c where c.areaId='{areaId}'", "Base");
+
+            //所有的课程记录
+            List<LessonRecord> records = new();
+            List<string> tecIds = new();
+
+            foreach (var school in schools)
+            {
+                string sqlTxt = $"select value(c) from c where c.code='LessonRecord-{school}'";
+                await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LessonRecord>(queryText: sqlTxt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonRecord-{school}") }))
+                {
+                    records.Add(item);
+                }
+            }
+
+            tecIds = await CommonFind.FindRolesId(cosmosClient, schools);
+            foreach (var tecId in tecIds)
+            {
+                string sqlTxt = $"select value(c) from c";
+                await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<LessonRecord>(queryText: sqlTxt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonRecord-{tecId}") }))
+                {
+                    records.Add(item);
+                }
+            }
+
+            int dayCount = 0;
+            var (dayStart, dayEnd) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow);
+            records.ForEach(x => { if (x.startTime >= dayStart && x.startTime <= dayEnd) dayCount += 1; });
+
+            int weekCount = 0;
+            var (weekStart, weekEnd) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "week");
+            records.ForEach(x => { if (x.startTime >= weekStart && x.startTime <= weekEnd) weekCount += 1; });
+
+            int monthCount = 0;
+            var (monthStart, monthEnd) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "month");
+            records.ForEach(x => { if (x.startTime >= monthStart && x.startTime <= monthEnd) monthCount += 1; });
+
+            int termCount = 0;
+            var (termStart, termEnd) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "term");
+            records.ForEach(x => { if (x.startTime >= termStart && x.startTime <= termEnd) termCount += 1; });
+
+
+            double teachCount = records.Where(r => r.tmdid != null).Where((x, i) => records.FindIndex(z => z.tmdid == x.tmdid) == i).ToList().Count;
+
+            return Ok(new { state = 200, lessonCount = records.Count, teachCount, dayCount, weekCount, monthCount, termCount });
+        }
+
+        /// <summary>
+        /// 统计区级一年每周的课例数据趋势
+        /// </summary>
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-weekcount")]
+        public async Task<IActionResult> GetWeekCount(JsonElement jsonElement) 
+        {
+            if (!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
+
+            Dictionary<int, double> weeks = new();
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+
+            int year = DateTimeOffset.UtcNow.Year;
+            int dayOfweek = (int)DateTimeOffset.Parse($"{year}-1-1").DayOfWeek;
+            var sqlTxts = "select value(c) from c";
+            List<LessonCount> scount = new();
+            List<LessonCount> tcount = new();
+
+            List<string> schools = await CommonFind.FindSchoolIds(cosmosClient, $"select c.id from c where c.areaId='{areaId}'", "Base");
+            foreach (var sId in schools)
+            {
+                await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<LessonCount>(queryText:sqlTxts,requestOptions:new QueryRequestOptions() { PartitionKey =new PartitionKey($"LessonCount-{sId}-{year}")}))
+                {
+                    scount.Add(item);
+                }
+            }
+
+            List<string> teacIds = await CommonFind.FindRolesId(cosmosClient, schools);            
+            foreach (var tId in teacIds)
+            {
+                var sqlTxtt = $"select value(c) from c where c.id='{tId}'";
+                await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<LessonCount>(queryText: sqlTxtt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{year}") }))
+                {
+                    tcount.Add(item);
+                }
+            }
+
+            int days = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? days = 366 : days = 365;
+
+            List<List<double>> lessons = new();
+            if (scount.Count > 0)
+            {
+                foreach (LessonCount item in scount)
+                {
+                    lessons.Add(item.beginCount);
+                }
+            }
+            if (tcount.Count > 0)
+            {
+                foreach (LessonCount item in tcount)
+                {
+                    lessons.Add(item.beginCount);
+                }
+            }
+
+            if (lessons.Count > 0) 
+            { 
+                var bmatrix = DenseMatrix.OfColumns(lessons);
+
+                //开学第一周周内开课                   
+                if (dayOfweek == 0)
+                {
+                    dayOfweek = 7;
+                }
+                //第一周多少天
+                var dd = 7 - dayOfweek + 1;
+                //一年有几周
+                int sweeks = days / 7;
+                //查询天数
+                int dayYear = 0;
+                if (sweeks > 0)
+                {
+                    for (int i = 1; i <= sweeks; i++)
+                    {
+                        if (i == 1)
+                        {
+                            var bsum = bmatrix.SubMatrix(dayYear, dd, 0, bmatrix.ColumnCount).ColumnSums().Sum();
+                            dayYear += dd;
+                            weeks.Add(i, bsum);
+                        }
+                        else
+                        {
+                            var bsum = bmatrix.SubMatrix(dayYear, 7, 0, bmatrix.ColumnCount).ColumnSums().Sum();
+                            dayYear += 7;
+                            weeks.Add(i, bsum);
+                        }
+                    }
+                }
+                //最后一周是否有余
+                int stary = days - dayYear;
+                if (stary > 0 && stary < 7)
+                {
+                    var bsum = bmatrix.SubMatrix(dayYear, stary - 1, 0, bmatrix.ColumnCount).ColumnSums().Sum();
+                    weeks.Add((sweeks + 1), bsum);
+                }
+            }
+
+            return Ok(new { state = 200, weeks });
+        }
+
         /// <summary>
         /// 依据课例Id获取课例详情   数据管理工具——查询工具
         /// </summary>
@@ -327,7 +488,7 @@ namespace TEAMModelBI.Controllers.Census
         {
             if (!jsonElement.TryGetProperty("lessonId", out JsonElement lessonId)) return BadRequest();
             var cosmosClient = _azureCosmos.GetCosmosClient();
-            List<object> lessons = new List<object>();
+            List<object> lessons = new();
             string sqlTxt = $"select * from c where c.id='{lessonId}'";
             await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: sqlTxt, requestOptions: new QueryRequestOptions() { })) 
             {
@@ -341,6 +502,11 @@ namespace TEAMModelBI.Controllers.Census
             return Ok(new { state = 200, lessons });
         }
 
+
+
+
+
+
         public record SchoolLen 
         {
             public string id { get; set; }
@@ -349,6 +515,5 @@ namespace TEAMModelBI.Controllers.Census
 
             public long totals { get; set; }
         }
-
     }
 }

+ 1 - 1
TEAMModelBI/Controllers/Census/SchoolController.cs

@@ -42,7 +42,7 @@ namespace TEAMModelBI.Controllers.Census
             var cosmosClient = _azureCosmos.GetCosmosClient();
             List<object> infos = new List<object>();
 
-            string sqlTxt = $"";
+            string sqlTxt = $"select value(c) from c where c.id='{id}'";
             await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: sqlTxt, requestOptions: new QueryRequestOptions() { }))
             {
                 using var json = await JsonDocument.ParseAsync(item.ContentStream);

+ 49 - 11
TEAMModelBI/Tool/CommonFind.cs

@@ -75,23 +75,30 @@ namespace TEAMModelBI.Tool
         public static async Task<List<SchoolTeacherRoles>> FindSchoolRoles(CosmosClient cosmosClient,string schoolId,string roles)
         {
             List<SchoolTeacherRoles> strs = new();
-            string managerSql = $"SELECT DISTINCT REPLACE(c.code, 'Teacher-', '') AS schoolId, c.id, c.name FROM c WHERE ARRAY_CONTAINS(c.roles, '{roles}', true) AND c.pk = 'Teacher' AND c.status = 'join' AND c.code = 'Teacher-{schoolId}'";
-            await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: managerSql, requestOptions: new QueryRequestOptions() { }))
+            try
             {
-                using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                string managerSql = $"SELECT DISTINCT REPLACE(c.code, 'Teacher-', '') AS schoolId, c.id, c.name FROM c WHERE ARRAY_CONTAINS(c.roles, '{roles}', true) AND c.pk = 'Teacher' AND c.status = 'join' AND c.code = 'Teacher-{schoolId}'";
+                await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: managerSql, requestOptions: new QueryRequestOptions() { }))
                 {
-                    SchoolTeacherRoles str = new SchoolTeacherRoles
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
                     {
-                        tmdId = obj.GetProperty("id").GetString(),
-                        tmdName = obj.GetProperty("name").GetString()
-                    };
+                        SchoolTeacherRoles str = new()
+                        {
+                            tmdId = obj.GetProperty("id").GetString(),
+                            tmdName = obj.GetProperty("name").GetString()
+                        };
 
-                    strs.Add(str);
+                        strs.Add(str);
+                    }
                 }
+                return strs;
+            }
+            catch
+            {
+                return strs;
             }
 
-            return strs;
         }
 
         /// <summary>
@@ -169,11 +176,42 @@ namespace TEAMModelBI.Tool
                     school.hard = json.RootElement.GetProperty("hard").GetArrayLength();
                 }
 
-                school.assists = await CommonFind.FindSchoolRoles(cosmosClient, school.id, "assist");
+                school.assists = await FindSchoolRoles(cosmosClient, school.id, "assist");
             }
             
             return assistSchools;
         }
 
+
+        /// <summary>
+        /// 依据学校查询教师列表
+        /// </summary>
+        /// <param name="cosmosClient"></param>
+        /// <param name="schools"></param>
+        /// <returns></returns>
+        public static async Task<List<string>> FindRolesId(CosmosClient cosmosClient, List<string> schools, string roles = null)
+        {
+            string rolesName = "teacher";
+            if (roles != null) 
+            {
+                rolesName = roles;
+            }
+
+            List<string> teachers = new();
+            foreach (var school in schools) 
+            {
+                string sqlTxt = $"select c.id from c where ARRAY_CONTAINS(c.roles,'{rolesName}',true) and c.status = 'join'";
+                await foreach (var itemTeac in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: sqlTxt, requestOptions: new QueryRequestOptions() {PartitionKey =new PartitionKey($"Teacher-{school}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(itemTeac.ContentStream);
+                    foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                    {
+                        teachers.Add(obj.GetProperty("id").GetString());
+                    }
+                }
+            }
+            return teachers;
+        }
+
     }
 }

+ 72 - 0
TEAMModelBI/Tool/TimeHelper.cs

@@ -173,5 +173,77 @@ namespace TEAMModelBI.Tool
         }
 
 
+        /// <summary>
+        /// 开始时间和结束时间戳
+        /// </summary>
+        /// <param name="dateTime"></param>
+        /// <param name="type"></param>
+        /// <param name="dateLenth"></param>
+        /// <returns></returns>
+        public static (long start, long end) GetStartOrEnd(DateTimeOffset dateTime, string type = "", bool dateLenth = true)
+        {
+            long start = 0;
+            long end = 0;
+            DateTimeOffset tempStrart = new();
+            DateTimeOffset tempEnt = new();
+            switch (type) 
+            {
+                case "year":
+                    tempStrart = new DateTime(dateTime.Year,1, 1);
+                    tempEnt = new DateTime(dateTime.Year, 12, DateTime.DaysInMonth(dateTime.Year, 12), 23, 59, 59);
+                    break;
+
+                case "term":
+                    int year = dateTime.Year;
+                    int month = dateTime.Month;
+                    if (month <= 8 && month >= 3)
+                    {
+                        tempStrart = new DateTime(year, 3, 1);
+                        tempEnt = new DateTime(year, 8, 31, 23, 59, 59);
+                    }
+                    else
+                    {
+                        //计算当前月份
+                        int days = 0;
+                        if (month >= 9)
+                        {
+                            tempStrart = new DateTime(dateTime.Year, 9, 1);
+                            tempEnt = new DateTime(dateTime.Year + 1, 2, (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? days = 29 : days = 28, 23, 59, 59);                        }
+                        else
+                        {
+                            tempStrart = new DateTime(dateTime.Year - 1, 9, 1);
+                            tempEnt = new DateTime(dateTime.Year, 2, (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? days = 29 : days = 28, 23, 59, 59);
+                        }
+                    }
+
+                    break;
+                case "month":
+                    tempStrart = new DateTime(dateTime.Year, dateTime.Month, 1);
+                    tempEnt = new DateTime(dateTime.Year, dateTime.Month, DateTime.DaysInMonth(dateTime.Year, dateTime.Month), 23, 59, 59);
+                    break;
+                case "week":
+                    DateTimeOffset weekStrart = dateTime.AddDays(-(int)(dateTime.DayOfWeek) + 1);
+                    DateTimeOffset weekEnd  = dateTime.AddDays(7-(int)(dateTime.DayOfWeek));
+                    tempStrart = new DateTime(weekStrart.Year, weekStrart.Month, weekStrart.Day);
+                    tempEnt = new DateTime(weekEnd.Year, weekEnd.Month, weekEnd.Day, 23, 59, 59); 
+
+
+                    break;
+                default:
+                    tempStrart = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day);
+                    tempEnt = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59);
+                    //start = dateLenth ? DateTimeOffset.Parse($"{dayStart}").ToUnixTimeMilliseconds() : DateTimeOffset.Parse($"{dayStart}").ToUnixTimeSeconds();
+                    //end = dateLenth ? DateTimeOffset.Parse($"{dayEnd}").ToUnixTimeMilliseconds() : DateTimeOffset.Parse($"{dayEnd}").ToUnixTimeSeconds();
+                    break;            
+            }
+
+            start = dateLenth ? DateTimeOffset.Parse($"{tempStrart}").ToUnixTimeMilliseconds() : DateTimeOffset.Parse($"{tempStrart}").ToUnixTimeSeconds();
+            end = dateLenth ? DateTimeOffset.Parse($"{tempEnt}").ToUnixTimeMilliseconds() : DateTimeOffset.Parse($"{tempEnt}").ToUnixTimeSeconds();
+
+            return (start, end);
+
+        }
+
+
     }
 }

+ 3 - 3
TEAMModelOS.FunctionV4/CosmosDB/TriggerCorrect.cs

@@ -34,8 +34,8 @@ namespace TEAMModelOS.FunctionV4
                 {
                     try
                     {
-                        await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
                         await table_cancel.DeleteSingle<ChangeRecord>(record.PartitionKey, record.RowKey);
+                        await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
                     }
                     catch (Exception)
                     {
@@ -77,7 +77,7 @@ namespace TEAMModelOS.FunctionV4
                                 long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageCorrect, DateTimeOffset.FromUnixTimeMilliseconds(tdata.startTime));
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), correctRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), correctRecords[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {
@@ -366,7 +366,7 @@ namespace TEAMModelOS.FunctionV4
                                 long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageCorrectEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.endTime));
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), correctRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), correctRecords[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {

+ 3 - 3
TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs

@@ -38,8 +38,8 @@ namespace TEAMModelOS.FunctionV4
                     {
                         try
                         {
-                            await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
                             await table_cancel.DeleteSingle<ChangeRecord>(record.PartitionKey, record.RowKey);
+                            await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
                         }
                         catch (Exception)
                         {
@@ -100,7 +100,7 @@ namespace TEAMModelOS.FunctionV4
                             {
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {
@@ -362,7 +362,7 @@ namespace TEAMModelOS.FunctionV4
                                     long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(data.endTime));
                                     try
                                     {
-                                        await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
+                                        await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
                                     }
                                     catch (Exception)
                                     {

+ 4 - 3
TEAMModelOS.FunctionV4/CosmosDB/TriggerExamLite.cs

@@ -36,8 +36,9 @@ namespace TEAMModelOS.FunctionV4
                     {
                         try
                         {
-                            await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
                             await table_cancel.DeleteSingle<ChangeRecord>(record.PartitionKey, record.RowKey);
+                            await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
+                           
                         }
                         catch (Exception)
                         {
@@ -75,7 +76,7 @@ namespace TEAMModelOS.FunctionV4
                             {
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {
@@ -158,7 +159,7 @@ namespace TEAMModelOS.FunctionV4
                                 long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWorkEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.endTime));
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {

+ 4 - 3
TEAMModelOS.FunctionV4/CosmosDB/TriggerHomework.cs

@@ -36,8 +36,9 @@ namespace TEAMModelOS.FunctionV4
                     {
                         try
                         {
-                            await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
                             await table_cancel.DeleteSingle<ChangeRecord>(record.PartitionKey, record.RowKey);
+                            await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
+                          
                         }
                         catch (Exception)
                         {
@@ -75,7 +76,7 @@ namespace TEAMModelOS.FunctionV4
                             {
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {
@@ -107,7 +108,7 @@ namespace TEAMModelOS.FunctionV4
                                 long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWorkEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.endTime));
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {

+ 4 - 3
TEAMModelOS.FunctionV4/CosmosDB/TriggerStudy.cs

@@ -36,8 +36,9 @@ namespace TEAMModelOS.FunctionV4
                     {
                         try
                         {
-                            await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
                             await table_cancel.DeleteSingle<ChangeRecord>(record.PartitionKey, record.RowKey);
+                            await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
+                          
                         }
                         catch (Exception ) {
                             continue;
@@ -75,7 +76,7 @@ namespace TEAMModelOS.FunctionV4
                             {
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {
@@ -164,7 +165,7 @@ namespace TEAMModelOS.FunctionV4
                                     long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageWorkEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.endTime));
                                     try
                                     {
-                                        await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
+                                        await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
                                     }
                                     catch (Exception)
                                     {

+ 4 - 3
TEAMModelOS.FunctionV4/CosmosDB/TriggerSurvey.cs

@@ -44,8 +44,9 @@ namespace TEAMModelOS.FunctionV4
                     {
                         try
                         {
-                            await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
                             await table_cancel.DeleteSingle<ChangeRecord>(record.PartitionKey, record.RowKey);
+                            await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
+                         
                         }
                         catch (Exception)
                         {
@@ -83,7 +84,7 @@ namespace TEAMModelOS.FunctionV4
                             {
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {
@@ -278,7 +279,7 @@ namespace TEAMModelOS.FunctionV4
                                 long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageSurveyEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.endTime));
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {

+ 3 - 3
TEAMModelOS.FunctionV4/CosmosDB/TriggerVote.cs

@@ -41,8 +41,8 @@ namespace TEAMModelOS.FunctionV4
                     {
                         try
                         {
-                            await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
                             await table_cancel.DeleteSingle<ChangeRecord>(record.PartitionKey, record.RowKey);
+                            await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
                         }
                         catch (Exception)
                         {
@@ -81,7 +81,7 @@ namespace TEAMModelOS.FunctionV4
                             {
                                 long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageVote, DateTimeOffset.FromUnixTimeMilliseconds(tdata.startTime));
                                 try {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), voteRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), voteRecords[0].sequenceNumber);
                                 } catch (Exception) { 
                                 }
                                 voteRecords[0].sequenceNumber = start;
@@ -282,7 +282,7 @@ namespace TEAMModelOS.FunctionV4
                                 long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageVoteEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.endTime));
                                 try
                                 {
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), voteRecords[0].sequenceNumber);
+                                    await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), voteRecords[0].sequenceNumber);
                                 }
                                 catch (Exception)
                                 {

+ 59 - 13
TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs

@@ -1013,7 +1013,6 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                     await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}课程读取base.json,{_lessonId}\n{ex.Message}\n{ex.StackTrace}\n{lessonRecord.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
                                 }
                                 break;
-
                             //更新 时间线
                             case "up-TimeLine":
                                 //BlobDownloadResult TimeLineblobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/{_lessonId}/IES/TimeLine.json").DownloadContentAsync();
@@ -1026,21 +1025,51 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                 //var activityInfos = ActivityInfoblobDownload.Content.ToObjectFromJson<List<LessonActivityInfo>>();
                                 msgs.Add(update);
                                 break;
-                                ///更新基础信息,名称科目,年级,分类等。
-                            case "up-baseinfo":
-                                if (updates.Count > 1)
-                                {
-                                    isReplace = true;
-                                }
-                                else
-                                {
-                                    isReplace = false;
+                            case "up-baseinfo":///更新基础信息,名称科目,年级,分类等,不能删除 ,由update-lesson-baseinfo 触发。
+                                isReplace = true;
+                                msgs.Add(update);
+                                break;
+                            case "up-expire"://消除过期时间,消除后需要取消已经排程的通知订阅
+                                try {
+                                    var table = _azureStorage.GetCloudTableClient().GetTableReference("ChangeRecord");
+                                    List<ChangeRecord> records = await table.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", lessonRecord.id } });
+                                    foreach (var record in records)
+                                    {
+                                        try
+                                        {
+                                            await table.DeleteSingle<ChangeRecord>(record.PartitionKey, record.RowKey);
+                                            await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
+                                        }
+                                        catch (Exception)
+                                        {
+                                            continue;
+                                        }
+                                    }
+                                } catch (Exception) {
+                                    break;
                                 }
+                                isReplace = true;
                                 msgs.Add(update);
                                 break;
                             case "delete":
                                 try
                                 {
+                                    if (lessonRecord.expire > 0) {
+                                        var table = _azureStorage.GetCloudTableClient().GetTableReference("ChangeRecord");
+                                        List<ChangeRecord> records = await table.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", lessonRecord.id } });
+                                        foreach (var record in records)
+                                        {
+                                            try
+                                            {
+                                                await table.DeleteSingle<ChangeRecord>(record.PartitionKey, record.RowKey);
+                                                await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber);
+                                            }
+                                            catch (Exception)
+                                            {
+                                                continue;
+                                            }
+                                        }
+                                    }
                                     await client.GetContainer(Constant.TEAMModelOS, tbname).DeleteItemAsync<LessonRecord>(lessonId, new PartitionKey(code));
                                     await _azureStorage.GetBlobServiceClient().DeleteBlobs(_dingDing, blobname, new List<string> { $"records/{_lessonId}" });
                                     await client.GetContainer(Constant.TEAMModelOS, tbname).DeleteItemStreamAsync(lessonRecord.id,new PartitionKey ($"Bloblog-{blobname}"));
@@ -1122,14 +1151,32 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                             int? Count = period?.grades?.Count;
                                             if (Count.HasValue)
                                             {
+                                                int Day = DateTimeOffset.UtcNow.Day;
                                                 int Month = DateTimeOffset.UtcNow.Month;
                                                 int Year = DateTimeOffset.UtcNow.Year;
+                                                int start = int.Parse($"{Year}0901");
+                                                var se = period.semesters.Find(x => x.start == 1);
+                                                if (se == null)
+                                                {
+                                                    se = period.semesters.First();
+                                                }
+                                                if (se != null)
+                                                {
+                                                    string sm = se.month >= 10 ? $"{se.month}" : $"0{se.month}";
+                                                    string sd = se.day >= 10 ? $"{se.day}" : $"0{se.day}";
+                                                    start = int.Parse($"{Year}{sm}{sd}");
+                                                }
+                                                int curr = int.Parse(DateTimeOffset.UtcNow.ToString("yyyyMMdd"));
+                                                //新学年开学时间大于当前时间,计算年级需要减1   20220901-20220408 > 0 则当前20220408是2021年入学的,
+                                                //当前时间大于新学年开学时间,计算年级则不需要  20220901-20221203 < 1 则当前20221203是2022年入学的,
+                                                //20230901-20230101 > 0 则当前20230101是2022年入学的,         
+                                                int dis = start - curr;
                                                 foreach (int year in gplist.Select(x => x.year))
                                                 {
                                                     int grade;
-                                                    if (Month >= 1 && Month <= 6)
+                                                    if (dis > 0)
                                                     {
-                                                        grade = (Year - year -1) % Count.Value;
+                                                        grade = (Year - year - 1) % Count.Value;
                                                     }
                                                     else
                                                     {
@@ -1264,7 +1311,6 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                 } catch (Exception e) {
                                     await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-处理课堂记录的-CosmosDB异常{e.Message}\n{e.StackTrace}\n{lessonRecord.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
                                 }
-                                    
                                 
                                 msgs.Add(update);
                                 break;

+ 3 - 3
TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj

@@ -5,9 +5,9 @@
 		<OutputType>Exe</OutputType>
 		<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
 		<SignAssembly>true</SignAssembly>
-		<AssemblyVersion>5.2204.6.1</AssemblyVersion>
-		<FileVersion>5.2204.6.1</FileVersion>
-		<Version>5.2204.6</Version>
+		<AssemblyVersion>5.2204.8.1</AssemblyVersion>
+		<FileVersion>5.2204.8.1</FileVersion>
+		<Version>5.2204.8</Version>
 		<PackageId>TEAMModelOS.FunctionV4</PackageId>
 		<Authors>teammodel</Authors>
 		<Company>醍摩豆(成都)信息技术有限公司</Company>

+ 1 - 1
TEAMModelOS.FunctionV4/local.settings.json

@@ -11,7 +11,7 @@
     "Azure:ServiceBus:ActiveTask": "dep-active-task",
     "Azure:ServiceBus:ItemCondQueue": "dep-itemcond",
     "Option:Location": "China-Dep",
-    "HaBookAuth:CoreService:sendnotification": "https://api2.teammodel.net/service/sendnotification",
+    "HaBookAuth:CoreService:sendnotification": "https://api2.teammodel.cn/service/sendnotification",
     "HaBookAuth:CoreAPI": "https://api2.teammodel.cn",
     "HaBookAuth:CoreService:clientID": "c7317f88-7cea-4e48-ac57-a16071f7b884",
     "HaBookAuth:CoreService:clientSecret": "kguxh:V.PLmxBdaI@jnrTrDSth]A3346"

+ 26 - 48
TEAMModelOS.SDK/DI/AzureServiceBus/AzureServiceBusExtensions.cs

@@ -10,29 +10,26 @@ using System.Linq;
 using Azure.Messaging.ServiceBus;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.Extension;
+using System.Collections.Concurrent;
 
 namespace TEAMModelOS.SDK.DI
 {
     public static class AzureServiceBusExtensions
     {
-
+        private static ConcurrentDictionary<string, ServiceBusSender> ServiceBusSenders { get; } = new ConcurrentDictionary<string, ServiceBusSender>();
+        
         /// <summary>
         /// 發送信息至對列或主題
         /// </summary>       
-        /// <param name="pathName">QueueName or TopicName</param>
+        /// <param name="name">QueueName or TopicName</param>
         /// <param name="message">訊息</param>
         /// <returns></returns>
-        public static async Task SendMessageAsync(this ServiceBusClient client, string pathName, ServiceBusMessage message)
+        public static async Task SendMessageAsync(this ServiceBusClient client, string name, ServiceBusMessage message)
         {
             try
             {
-                ServiceBusSender sender = client.CreateSender(pathName);
-                await sender.SendMessageAsync(message);
-                if (!sender.IsClosed)
-                {
-                    await sender.CloseAsync();
-                    await sender.DisposeAsync();
-                }
+                ServiceBusSender sender = ServiceBusSenders.GetOrAdd(name, x => client.CreateSender(name));                
+                await sender.SendMessageAsync(message);                
             }
             catch
             {
@@ -43,25 +40,20 @@ namespace TEAMModelOS.SDK.DI
         /// <summary>
         /// 批量發送訊息至對列或主題,如果批量失敗返回False
         /// </summary>       
-        /// <param name="pathName">QueueName or TopicName</param>
+        /// <param name="name">QueueName or TopicName</param>
         /// <param name="messages">批量訊息</param>
         /// <returns></returns>
-        public static async Task<bool> SendBatchMessageAsync(this ServiceBusClient client, string pathName, IList<ServiceBusMessage> messages)
+        public static async Task<bool> SendBatchMessageAsync(this ServiceBusClient client, string name, IList<ServiceBusMessage> messages)
         {
             try
             {
-                ServiceBusSender sender = client.CreateSender(pathName);
+                ServiceBusSender sender = ServiceBusSenders.GetOrAdd(name, x => client.CreateSender(name));
                 ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();
                 foreach (var msg in messages)
                 {
                     if (!messageBatch.TryAddMessage(msg)) return false;
                 }
-                await sender.SendMessagesAsync(messageBatch);
-                if (!sender.IsClosed)
-                {
-                    await sender.CloseAsync();
-                    await sender.DisposeAsync();
-                }
+                await sender.SendMessagesAsync(messageBatch);                
                 return true;
             }
             catch
@@ -73,19 +65,15 @@ namespace TEAMModelOS.SDK.DI
         /// <summary>
         /// 發送信息至對列或主題(指定時間排程)
         /// </summary>       
-        /// <param name="pathName">QueueName or TopicName</param>
+        /// <param name="name">QueueName or TopicName</param>
         /// <param name="message">訊息</param>
         /// <returns>排程訊息的序列號。</returns>
-        public static async Task<long> SendScheduleMessageAsync(this ServiceBusClient client, string pathName, ServiceBusMessage message, DateTimeOffset scheduleTime)
+        public static async Task<long> SendScheduleMessageAsync(this ServiceBusClient client, string name, ServiceBusMessage message, DateTimeOffset scheduleTime)
         {
             try
             {
-                ServiceBusSender sender = client.CreateSender(pathName);
-                long num= await sender.ScheduleMessageAsync(message, scheduleTime);
-                if (!sender.IsClosed) {
-                    await sender.CloseAsync();
-                    await sender.DisposeAsync();
-                }
+                ServiceBusSender sender = ServiceBusSenders.GetOrAdd(name, x => client.CreateSender(name));
+                long num= await sender.ScheduleMessageAsync(message, scheduleTime);                
                 return num;
             }
             catch
@@ -97,25 +85,20 @@ namespace TEAMModelOS.SDK.DI
         /// <summary>
         /// 批量發送訊息至對列或主題(指定時間排程),如果批量失敗返回False
         /// </summary>       
-        /// <param name="pathName">QueueName or TopicName</param>
+        /// <param name="name">QueueName or TopicName</param>
         /// <param name="messages">批量訊息</param>
         /// <returns>排程訊息的序列號</returns>
-        public static async Task<IReadOnlyList<long>> SendScheduleMessagesAsync(this ServiceBusClient client, string pathName, IList<ServiceBusMessage> messages, DateTimeOffset scheduleTime)
+        public static async Task<IReadOnlyList<long>> SendScheduleMessagesAsync(this ServiceBusClient client, string name, IList<ServiceBusMessage> messages, DateTimeOffset scheduleTime)
         {
             try
             {
-                ServiceBusSender sender = client.CreateSender(pathName);
-                List<ServiceBusMessage> msgs = new List<ServiceBusMessage>() { };
+                ServiceBusSender sender = ServiceBusSenders.GetOrAdd(name, x => client.CreateSender(name));
+                List<ServiceBusMessage> msgs = new() { };
                 foreach (var msg in messages)
                 {
                     msgs.Add(msg);
                 }
-                var nums= await sender.ScheduleMessagesAsync(msgs, scheduleTime);
-                if (!sender.IsClosed)
-                {
-                    await sender.CloseAsync();
-                    await sender.DisposeAsync();
-                }
+                var nums= await sender.ScheduleMessagesAsync(msgs, scheduleTime);                
                 return nums;
             }
             catch
@@ -125,7 +108,7 @@ namespace TEAMModelOS.SDK.DI
         }
 
 
-        public static async Task<long> SendLeamMessage<T>(this ServiceBusClient client, string TopicName, string id, string pk, long startTime)
+        public static async Task<long> SendLeamMessage<T>(this ServiceBusClient client, string name, string id, string pk, long startTime)
         {
             //微調代碼
             var timer = DateTimeOffset.FromUnixTimeMilliseconds(startTime);
@@ -146,7 +129,7 @@ namespace TEAMModelOS.SDK.DI
             
             
             //设定开始时间
-            Dictionary<string, object> dict = new Dictionary<string, object>() {
+            Dictionary<string, object> dict = new() {
                     { "name",typeof(T).Name},
                     { "id",id},
                     { "code",pk}
@@ -154,22 +137,17 @@ namespace TEAMModelOS.SDK.DI
             //var msgId = "1";
             string messageBody = $"Message {dict}";
 
-            long SequenceNumber = await client.SendScheduleMessageAsync(TopicName, new ServiceBusMessage(dict.ToJsonString()), timer);
+            long SequenceNumber = await client.SendScheduleMessageAsync(name, new ServiceBusMessage(dict.ToJsonString()), timer);
 
             return SequenceNumber;
         }
 
-        public static async Task cancelMessage(this ServiceBusClient client, string TopicName, long number)
+        public static async Task CancelMessageAsync(this ServiceBusClient client, string name, long number)
         {
             try
             {
-                ServiceBusSender sender = client.CreateSender(TopicName);
-                await sender.CancelScheduledMessageAsync(number);
-                if (!sender.IsClosed)
-                {
-                    await sender.CloseAsync();
-                    await sender.DisposeAsync();
-                }
+                ServiceBusSender sender = ServiceBusSenders.GetOrAdd(name, x => client.CreateSender(name));
+                await sender.CancelScheduledMessageAsync(number);                
             }
             catch
             {

+ 2 - 0
TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs

@@ -148,6 +148,8 @@ namespace TEAMModelOS.SDK.Models
         public List<int> field { get; set; } = new List<int>();
         public  string  sheet { get; set; }        //public long sequenceNumber { get; set; }
         public string sheetNo { get; set; }        //public long sequenceNumber { get; set; }
+
+        public string mode { get; set; }
         //记录试卷作答时间
         public int time { get; set; } = 0;
 

+ 4 - 2
TEAMModelOS.SDK/Models/Cosmos/School/TeacherImport.cs

@@ -19,7 +19,9 @@ namespace TEAMModelOS.SDK.Models
         public string name { get; set; }
         public string status { get; set; }
         public long time { get; set; }
-        //导入时的key
-        public string key { get; set; }
+        public string tmdid { get; set; }
+        public string phone { get; set; }
+        public string email { get; set; }
+        public string note { get; set; }
     }
 }

+ 4 - 4
TEAMModelOS.SDK/Models/Service/LessonService.cs

@@ -201,10 +201,10 @@ namespace TEAMModelOS.SDK.Models.Service
                         ttl = -1
                     };
                     double[] da = new double[days];
-                    List<double> list = new List<double>(da);
-                    List<double> listT = new List<double>(da);
-                    List<double> listP = new List<double>(da);
-                    List<double> listPT = new List<double>(da);
+                    List<double> list = new (da);
+                    List<double> listT = new (da);
+                    List<double> listP = new (da);
+                    List<double> listPT = new (da);
 
                     list[day - 1] += lessonDis.record;
                     listT[day - 1] += lessonDis.disTCount;

+ 5 - 10
TEAMModelOS/ClientApp/src/api/spaceAuth.js

@@ -2,15 +2,10 @@ import { post } from '@/api/http'
 
 export default {
   //設定老師空間API,有三種動作如註解
-  teacherSpace: function(data, action, teachers) {
-   
-    //console.log(data, action, teachers)
-    return post('/school/init/teacher-space', {
-      school_code: data,
-      action: action, // baseSpace: 目前教師可設定的總空間,
-      // upd: 修改教師雲端空間
-      // retract: 收回全部的教師空間
-      teachers: teachers
-    })
+  // baseSpace: 目前教師可設定的總空間,
+  // upd: 修改教師雲端空間
+  // retract: 收回全部的教師空間
+  teacherSpace: function (data) {
+    return post('/school/init/teacher-space', data)
   }
 }

+ 8 - 0
TEAMModelOS/ClientApp/src/common/AbilityUpload.vue

@@ -58,6 +58,10 @@
 				type: Number,
 				default: -1
 			},
+			limit: {
+				type: Number,
+				default: 9999
+			},
 			acceptTypes: {
 				type: Array,
 				default: () => []
@@ -103,6 +107,10 @@
 				console.log(this.acceptTypes);
 				console.log(file);
 				console.log(file.type);
+				if(this.fileArr.length >= this.limit && this.mode === 'modal'){
+					this.$Message.warning(`当前任务目前只能提交${ this.limit }个文件!`);
+					return false
+				}
 
 				let nameType = file.name.split('.')[file.name.split('.').length - 1]
 				if (this.maxSize > 0 && file.size > this.maxSize) {

+ 10 - 10
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -335,11 +335,11 @@ export default {
                     child: [{
                         icon: 'iconfont icon-test',
                         name: this.$t('system.menu.scEv'),
-                        router: '/home/schoolEvaluation',
+                        router: '/home/schoolExam',
                         tag: '',
                         role: 'admin',
                         permission: 'schoolAc-read|schoolAc-upd',
-                        menuName: 'schoolEvaluation',
+                        menuName: 'schoolExam',
                         isShow: true
                     },
                     {
@@ -364,12 +364,12 @@ export default {
                     },
                     ]
                 },
-                // 教研中心
+                // 课例中心
                 {
                     icon: 'iconfont icon-research-center',
                     name: this.$t('system.menu.research'),
                     router: '',
-                    role: 'teacher|admin',
+                    role: 'admin',
                     tag: this.$t('system.preview'),
                     permission: '',
                     subName: 'research',
@@ -380,8 +380,8 @@ export default {
                             name: this.$t('system.menu.cusVideos'),
                             router: '/home/courseCenter',
                             tag: this.$t('system.preview'),
-                            role: 'teacher|admin',
-                            permission: '',
+                            role: 'admin',
+                            permission: 'research-read|research-upd',
                             menuName: 'courseCenter',
                             isShow: this.$store.state.config.srvAdrType != 'product'
                         },
@@ -390,8 +390,8 @@ export default {
                             name: this.$t('system.menu.cusVideoMgt'),
                             router: '/home/ResearchMgt',
                             tag: '',
-                            role: 'teacher|admin',
-                            permission: '',
+                            role: 'admin',
+                            permission: 'research-read|research-upd',
                             menuName: 'ResearchMgt',
                             isShow: true
                         }
@@ -689,11 +689,11 @@ export default {
                     child: [{
                         icon: 'iconfont icon-test',
                         name: this.$t('system.menu.prtEv'),
-                        router: '/home/privateEvaluation',
+                        router: '/home/privExam',
                         tag: '',
                         role: 'teacher|admin',
                         permission: '',
-                        menuName: 'privateEvaluation',
+                        menuName: 'privExam',
                         isShow: true
                     },
                     {

+ 10 - 1
TEAMModelOS/ClientApp/src/common/BaseNotification.vue

@@ -82,6 +82,7 @@
 					'scan-join_groupList': vm.$t('notice.type7'), // 普通阅卷任务分配通知
 					'scan-join_school': vm.$t('notice.type7'), // 普通阅卷任务分配通知
 					'submitanswer_homework': vm.$t('notice.type8'), // 作业提交通知
+					'expire_lessonRecord': vm.$t('notice.type9'), // 课例过期通知
 				}
 			}
 		},
@@ -163,6 +164,9 @@
 						break;	
 					case 'submitanswer_homework':
 						return `${body.tmdname} ${this.$t('notice.tip15')}  【${body.sname}】${this.$t('notice.tip16')}`
+						break;
+					case 'expire_lessonRecord':
+						return `${this.$t('notice.tip17')}【${this.$tools.formatTime(body.stime)}】${this.$t('notice.tip18')}【${body.sname}】${this.$t('notice.tip19')} 【${this.$tools.formatTime(body.expire)}】${this.$t('notice.tip20')}`
 						break;		
 					default:
 						break;
@@ -241,7 +245,12 @@
 								}
 							}
 						}
-						break;		
+						break;
+					case 'expire_lessonRecord':
+						routerInfo = {
+							name: "myCourse",
+						}
+						break;				
 					default:
 						break;
 				}

+ 1 - 1
TEAMModelOS/ClientApp/src/common/BaseSelectSchool.vue

@@ -184,7 +184,7 @@
 					setTimeout(() => {
 						this.$EventBus.$emit('onGlobalLoading', false)
 					}, 1500)
-					routerInfo = routerInfo || { name: localStorage.getItem('srvAdr') == 'Global' ? 'myCourse' : 'homePage' }					
+					routerInfo = routerInfo || { name: 'homePage' }
 					// console.error(routerInfo.name);
 					// console.error(this.$route);
 					this.$router.push(routerInfo)

+ 2 - 2
TEAMModelOS/ClientApp/src/common/BaseUserPoptip.vue

@@ -116,7 +116,7 @@ export default {
         /* 切换校级平台或区级平台 */
         changePlatform() {
             let goPlatform = this.curPlatform === 'area' ? 'school' : 'area'
-            let homePath = this.$store.state.config.srvAdr == 'China' ? 'home' : 'myCourse'
+            let homePath = 'home'
             this.$router.push({
                 name: goPlatform === 'area' ? 'area' : homePath
             })
@@ -163,7 +163,7 @@ export default {
         onRoleSelect(val) {
             if (sessionStorage.getItem('identity') != val) {
                 this.curRole = val
-                let homePath = this.$store.state.config.srvAdr == 'China' ? 'home' : 'myCourse'
+                let homePath = 'home'
                 let path = val === 'student' ? 'studentWeb' : homePath
                 sessionStorage.setItem('identity', val)
                 this.$router.push({ path: path })

+ 96 - 0
TEAMModelOS/ClientApp/src/common/PersonalPhoto.vue

@@ -0,0 +1,96 @@
+<style lang="less" scoped>
+#personalPhoto {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    .avatar {
+        display: flex;
+        width: 32px;
+        height: 32px;
+        border-radius: 50%;
+        align-items: center;
+        justify-content: center;
+        overflow: hidden;
+    }
+    .fakeAvatar {
+        display: flex;
+        width: 36px;
+        border-radius: 50%;
+        align-items: center;
+        justify-content: center;
+        // background-color: antiquewhite;
+        height: 36px;
+        color: white;
+        font-size: 1.25rem;
+    }
+}
+</style>
+
+<template>
+    <div id="personalPhoto">
+        <div v-if="picture">
+            <img class="avatar" :src="picture">
+        </div>
+        <div v-else style="display: flex;align-items: center;justify-content: center;">
+            <div class="fakeAvatar" :style="{backgroundColor: randomColor, width: width, height: height, fontSize: fontSize}">
+                {{  getChinese(name) }}
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+
+export default {
+    props: {
+        name: String,
+        picture: String,
+        color: String,
+        fontSize: {
+            type: String,
+            default: '14px'
+        },
+        width: {
+            type: String,
+            default: '32px'
+        },
+        height: {
+            type: String,
+            default: '32px'
+        }
+    },
+    data() {
+        return {
+
+        }
+    },
+    created() {
+    },
+    computed: {
+        randomColor: function () {
+            if (!this.color) {
+                let r = Math.floor(Math.random() * 255);
+                let g = Math.floor(Math.random() * 255);
+                let b = Math.floor(Math.random() * 255);
+                return 'rgba(' + r + ',' + g + ',' + b + ',0.8)';
+            } else {
+                return this.color;
+            }
+        }
+    },
+    methods: {
+        getChinese(strValue) {
+            if (!strValue) return ''
+            var reg = /[\u4e00-\u9fa5]/g;
+            var names = strValue.match(reg);
+            if (names) {
+                return names.join("").substring(names.length - 2)
+            } else {
+                return strValue.substr(0, 2)
+            }
+        }
+    },
+    mounted() {
+    }
+}
+</script>

+ 55 - 55
TEAMModelOS/ClientApp/src/components/student-web/EventBasicInfo.vue

@@ -1,74 +1,71 @@
 <template>
-    <div v-if="info" style="margin-top: 20px; margin-bottom: 50px;">
+    <div v-if="info" style="margin-top: 20px;">
         <Row :gutter="30">
-            <i-col :xs="24" :sm="24" :md="24" :lg="getCurrentLang() == 'tw' ? 12 : 24" class="title-part">
+            <i-col :xs="24" :sm="24" :md="24" :lg="getCurrentLaguage === 'en-us' ? 24 : 12" :xl="12" :xxl="12" class="title-part">
                 <h2 class="event-title">
-                    <span class="title-mark" v-show="info.type == 'Exam'" >{{$t("studentWeb.home.exam")}}</span>
-                    <span class="title-mark" v-show="info.type == 'Vote'" >{{$t("studentWeb.home.vote")}}</span>
-                    <span class="title-mark" v-show="info.type == 'Survey'" >{{$t("studentWeb.home.survey")}}</span>
-                    <span class="title-mark" v-show="info.type == 'Homework'" >{{$t("studentWeb.home.homework")}}</span>
+                    <span class="title-mark" v-show="info.type === 'Exam'" >{{$t("studentWeb.home.exam")}}</span>
+                    <span class="title-mark" v-show="info.type === 'Vote'" >{{$t("studentWeb.home.vote")}}</span>
+                    <span class="title-mark" v-show="info.type === 'Survey'" >{{$t("studentWeb.home.survey")}}</span>
+                    <span class="title-mark" v-show="info.type === 'Homework'" >{{$t("studentWeb.home.homework")}}</span>
                     <span class="title-mark" v-show="from === 'hiteach'" >{{$t("studentWeb.hiteachview-title")}}</span>
                     {{ info.name }}
                 </h2>
             </i-col>
-            <i-col :xs="24" :sm="24" :md="24" :lg="getCurrentLang() == 'tw' ? 12 : 24" class="info-part">
-                <ul class="base-info" :class="{'base-infoEn': getCurrentLang() == 'en'}">
-                    <li v-if="info.type === 'Exam'">
-                        <span v-if="paper.length !== 0 && $store.getters.getItemTitle.owner === 'school'">
+            <i-col :xs="24" :sm="24" :md="24" :lg="getCurrentLaguage === 'en-us' ? 24 : 12" :xl="12" :xxl="12" class="info-part">
+                <div class="base-info" :class="{'base-infoEn': getCurrentLaguage === 'en-us'}">
+                    <template v-if="info.type === 'Exam'">
+                        <p v-if="paper.length !== 0 && $store.getters.getItemTitle.owner === 'school'">
                             <Icon type="ios-bookmarks-outline" style="font-weight: bold; margin-right: 5px;" />
-                            <!-- <svg-icon icon-class="subject" class="base-info-icon" /> -->{{ $t('studentWeb.baseInfo.subject')}}
-                            <!-- <span class="base-info-text">{{paper.length > 1 ? $t('studentWeb.event.allSubject') : paper[0].subject.name }}</span> -->
+                            {{ $t('studentWeb.baseInfo.subject')}}
                             <span class="base-info-text" v-for="(item, index) in paper" :key="index">
                                 {{ item.subject.name }}
                             </span>
-                            <!-- <span class="base-info-text" v-if="getCurrentLang()=='en'">{{ transSubjecttoEn(info.eventSubject) }}</span> -->
-                        </span>
-                    </li>
-                    <li v-if="info.type === 'Exam'">
-                        <span v-if="info.creatorName">
-                            <Icon type="ios-contact-outline" style="font-weight: bold; margin-right: 5px;" />{{ $t('studentWeb.baseInfo.teacher') }}
+                        </p>
+                        <p v-if="info.creatorName">
+                            <Icon type="ios-contact-outline" style="font-weight: bold; margin-right: 5px;" />
+                            {{ $t('studentWeb.baseInfo.teacher') }}
                             <span class="base-info-text">{{ info.creatorName }}</span>
-                        </span>
-                    </li>
-                    <li v-if="info.type === 'Exam'">
-                        <span v-if="info.className">
-                            <Icon custom="iconfont icon-mingdan" size="14" style="margin-right: 5px;" />{{ $t('studentWeb.baseInfo.stuList') }}
+                        </p>
+                        <p v-if="info.className">
+                            <Icon custom="iconfont icon-mingdan" size="14" style="margin-right: 5px;" />
+                            {{ $t('studentWeb.baseInfo.stuList') }}
                             <span class="base-info-text" v-for="(claNa, indexSub) in info.className" :key="indexSub">
                                 {{ claNa }}
                             </span>
-                        </span>
-                    </li>
-                    <li>
-                        <Icon type="ios-contact-outline" style="font-weight: bold; margin-right: 5px;" />{{ $t('studentWeb.baseInfo.nowStu') }}
-                        <span class="base-info-text">{{ $store.state.userInfo.name }}</span>
-                    </li>
-                    <li v-if="info.type == 'Vote'">
-                        <svg-icon icon-class="teacher" class="base-info-icon" style="right: 0; margin-right: 5px;" />{{ $t('studentWeb.baseInfo.voteType') }}
+                        </p>
+                    </template>
+                    <p v-if="info.type === 'Vote'">
+                        <svg-icon icon-class="teacher" class="base-info-icon" style="right: 0; margin-right: 5px;" />
+                        {{ $t('studentWeb.baseInfo.voteType') }}
                         <span class="base-info-text">{{ times }}</span>
-                    </li>
-                    <li v-if="from === 'hiteach'">
-                        <Icon type="md-timer" class="base-info-icon" />{{ $t('studentWeb.baseInfo.timeLong') }}
-                        <span class="base-info-text">{{ info.time }}</span>
-                    </li>
-                    <li v-if="from != '通知' && from != 'hiteach'">
-                        <!-- <svg-icon icon-class="time" class="base-info-icon" /> -->
+                    </p>
+                    <p>
+                        <Icon type="ios-contact-outline" style="font-weight: bold; margin-right: 5px;" />
+                        {{ $t('studentWeb.baseInfo.nowStu') }}
+                        <span class="base-info-text">{{ $store.state.userInfo.name }}</span>
+                    </p>
+                    <template v-if="from === 'hiteach'">
+                        <p>
+                            <Icon type="md-timer" class="base-info-icon" />
+                            {{ $t('studentWeb.baseInfo.timeLong') }}
+                            <span class="base-info-text">{{ info.time }}</span>
+                        </p>
+                        <p>
+                            <svg-icon icon-class="time" class="base-info-icon" />
+                            {{$t('studentWeb.baseInfo.classTime')}}:
+                            <span class="base-info-text">{{ dateFormat(info.startTime) }}</span>
+                        </p>
+                    </template>
+                    <p v-if="from != '通知' && from != 'hiteach'">
                         <Icon type="ios-time-outline" style="font-weight: bold; margin-right: 5px;" />
-                        <span>{{ !eventType ? $t('studentWeb.baseInfo.period') : $t('studentWeb.baseInfo.postTime') }}</span>
+                        {{ !eventType ? $t('studentWeb.baseInfo.period') : $t('studentWeb.baseInfo.postTime') }}
                         <span class="base-info-text">
                             <span>
                                 {{ !eventType ? dateFormat(info.startTime) + "~" : ""}}
                             </span>
                             {{ dateFormat(info.endTime) }}
                         </span>
-                        <!--<span
-                        class="base-info-text"
-                        v-if="from == '通知'||from == 'hiteach'"
-                        >{{ info.endTime + " 14:20" }}54345</span>-->
-                    </li>
-                    <li v-if="from === 'hiteach'">
-                        <svg-icon icon-class="time" class="base-info-icon" />{{$t('studentWeb.baseInfo.classTime')}}:
-                        <span class="base-info-text">{{ dateFormat(info.startTime) }}</span>
-                    </li>
+                    </p>
                     <!--<li v-if="finishedCondition && !eventType && from != '通知'&&from!='hiteach'">
                         <svg-icon icon-class="done" class="base-info-icon" />
                         <span class="base-info-text">{{ $t('studentWeb.baseInfo.Fineshed')}}</span>
@@ -77,13 +74,14 @@
                         <svg-icon icon-class="undone" class="base-info-icon" />
                         <span class="base-info-text">{{ $t('studentWeb.baseInfo.unFinished')}}</span>
                     </li>-->
-                </ul>
+                </div>
             </i-col>
         </Row>
     </div>
 </template>
 
 <script>
+import { mapGetters } from 'vuex';
 export default {
     name: "EventBasicInfo",
     props: [
@@ -125,10 +123,10 @@ export default {
             var S = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()) + " "
             return Y + M + D + H + Min;
         },
-        getCurrentLang() {
-            return localStorage.getItem('lang');
-        },
     },
+    computed: {
+        ...mapGetters(["getCurrentLaguage"])
+    }
 };
 </script>
 
@@ -137,16 +135,18 @@ export default {
     margin-right: 5px;
 }
 
-.info-part .base-info li {
+.info-part .base-info p {
     margin-bottom: 5px;
 }
 
 .info-part .base-info {
-    display: flex;
+    /* display: flex;
     flex-direction: column;
     align-items: flex-start;
     position: absolute;
     top: -30px;
-    right: 0;
+    right: 0; */
+    text-align: left;
+    float: right;
 }
 </style>

+ 5 - 5
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContent.vue

@@ -7,16 +7,16 @@
             <!--<div v-if="getItemTitle.eventType=='preview'">
               <PreviewMission/>
             </div>-->
-            <div v-if="getItemTitle.eventType=='Homework'">
-              <Homework />
+            <div v-if="getItemTitle.eventType === 'Homework'">
+                <Homework />
             </div>
-            <div v-if="getItemTitle.eventType == 'Exam'">
+            <div v-if="getItemTitle.eventType === 'Exam'">
                 <PaperView />
             </div>
-            <div v-if="getItemTitle.eventType == 'Vote'">
+            <div v-if="getItemTitle.eventType === 'Vote'">
                 <Vote />
             </div>
-            <div v-if="getItemTitle.eventType == 'Survey'">
+            <div v-if="getItemTitle.eventType === 'Survey'">
                 <QuesNaire />
             </div>
         </template>

+ 9 - 0
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.less

@@ -176,6 +176,15 @@
     .que-item {
         margin-bottom: 15px;
     }
+
+    .left-img {
+        margin-left: 10px;
+        text-align: center;
+
+        & > img {
+            max-width: 100%;
+        }
+    }
 }
 
 .qcol {

+ 166 - 119
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue

@@ -125,7 +125,7 @@
                         ({{`${$t("studentWeb.exam.info.total1")}${item.exam.length}${$t("studentWeb.exam.info.num")},${$t("studentWeb.exam.info.total2")}${item.score}${$t("studentWeb.exam.score111")}`}})
                     </p>
                     <div v-for="(exam, indexs) in item.exam" :key="indexs" style="display: flex; margin-bottom: 40px;"
-                        v-show="checkedAnsFilter(index, indexs) || (exam.type === 'compose' && ((checkedAns.includes('right') && exam.rightNum) || (checkedAns.includes('wrong') && !exam.rightNum)))"
+                        v-show="checkedAnsFilter(true, index, indexs) || (exam.type === 'compose' && ((checkedAns.includes('right') && exam.rightNum) || (checkedAns.includes('wrong') && !exam.rightNum)))"
                     >
                         <div style="width: 6%;" v-if="testState === 3 && getItemTitle.progress === 'finish'">
                             <p>
@@ -152,7 +152,7 @@
                             <div style="margin-top: 20px;">
                                 <div v-for="(children, indexC) in exam.children" :key="indexC"
                                     style="margin-bottom: 40px; margin-left: 20px; display: flex;"
-                                    v-show="checkedAnsFilter(index, indexs, indexC)"
+                                    v-show="checkedAnsFilter(true, index, indexs, indexC)"
                                 >
                                     <div style="margin-right: 5px;" v-if="testState === 3 && getItemTitle.progress === 'finish'">
                                         <Icon type="md-close-circle" color="#FF5508" size="25" v-show="children.getScore != children.score" />
@@ -361,117 +361,137 @@
             <div class="qcontent img-question" ref="qcontent" v-if="paperData.length && examInfo.qamode">
                 <div style="display: flex;">
                     <div style="width: 50%;">
-                        <Carousel v-model="CarouselIndex" loop>
-                            <CarouselItem v-for="(exam, indexs) in paperData" :key="indexs">
-                                <!-- 不是综合题 -->
-                                <div v-if="exam.type != 'compose'" style="margin-left: 10px; text-align: center;" class="left-img">
-                                    <div class="que-item" v-html="exam.question"></div>
-                                    <!-- <p v-if="!paperInfo.attachments" style="margin-bottom: 10px;">当前题目没有图片</p> -->
-                                </div>
-                            </CarouselItem>
-                        </Carousel>
-                    </div>
-                    <div style="width: 50%; margin-left: 20px;">
-                        <div>
-                            <div style="float: right;">
-                                <span style="font-size: 20px; color:#00ad6c;">{{ paperData[CarouselIndex].getScore }}</span>
-                                    / <span style="font-size: 12px;">{{ paperData[CarouselIndex].score }}{{ $t("studentWeb.exam.score111") }}</span>
-                            </div>
-                            <div style="display: flex; font-size: 16px; margin-bottom: 10px;">
-                                <span style="margin-right: 10px;">
-                                    <Icon type="md-close-circle" color="#FF5508" size="25"
-                                          v-show="paperData[CarouselIndex].getScore != paperData[CarouselIndex].score"
-                                    />
-                                    <Icon type="md-checkmark-circle" color="#00AD6C" size="25"
-                                          v-show="paperData[CarouselIndex].getScore === paperData[CarouselIndex].score"
-                                    />
-                                </span>
-                                <p style="max-width:75px;font-weight:600">{{ CarouselIndex + 1 }}.</p>
-                                <span class="tag-style">{{ getTestType(paperData[CarouselIndex].type) }}</span>
-                                <!-- <div class="que-item" v-html="paperData[CarouselIndex].question"></div> -->
-                            </div>
-                        </div>
-                        <div>
-                            <div class="item-explain">
-                                <span class="explain-title">【{{ $t("studentWeb.exam.report.ansRes") }}】</span>
-                                <div v-if="paperData[CarouselIndex].stuAns.length" class="item-explain-details">
-                                    <span v-for="(stuAns, indexA) in paperData[CarouselIndex].stuAns" :key="indexA" v-html="stuAns"></span>
-                                </div>
-                                <div v-if="!paperData[CarouselIndex].stuAns.length" class="item-explain-details">
-                                    <span>{{ $t('studentWeb.exam.report.noAns') }}</span>
-                                </div>
-                            </div>
-                            <!-- 批注 -->
-                            <!-- <div class="item-explain" v-if="paperData[CarouselIndex].type != 'single' && paperData[CarouselIndex].type != 'multiply' && paperData[CarouselIndex].type != 'judge'">
-                                <span class="explain-title">【{{ $t("studentWeb.exam.report.mark") }}】</span>
-                                <div v-if="paperData[CarouselIndex].mark.length" class="item-explain-details">
-                                    <img :src="paperData[CarouselIndex].mark[0].imgUrl" alt="" v-if="paperData[CarouselIndex].mark.length === 1">
-                                    <Tabs v-else type="card">
-                                        <TabPane :label="$t('studentWeb.exam.report.mark') + (mIndex + 1)" v-for="(mDate, mIndex) in paperData[CarouselIndex].mark" :key="mIndex">
-                                            <img :src="mDate.imgUrl" alt="">
-                                        </TabPane>
-                                    </Tabs>
-                                </div>
-                                <div v-else class="item-explain-details">{{ $t("studentWeb.exam.report.noMark") }}</div>
-                            </div> -->
-                            <!-- 参考答案 -->
-                            <div class="item-explain">
-                                <span class="explain-title">【{{ $t("studentWeb.exam.report.testAns") }}】</span>
-                                <div v-if="paperData[CarouselIndex].answer.length" class="item-explain-details">
-                                    <div v-for="(answerC, indexCA) in paperData[CarouselIndex].answer" :key="indexCA" v-html="answerC"></div>
-                                </div>
-                                <div v-if="!paperData[CarouselIndex].answer.length" class="item-explain-details">
-                                    <span>{{ $t('studentWeb.exam.report.noAns') }}</span>
-                                </div>
+                        <template v-if="!imgList.length">
+                            <p style="margin-bottom: 10px; text-align: center;font-size: 18px;">
+                                {{ $t("studentWeb.exam.message.noQamode") }}
+                            </p>
+                        </template>
+                        <template v-else-if="imgList.length === 1">
+                            <div class="left-img" @click="$hevueImgPreview(imgList[0])">
+                                <img :src="imgList[0]" alt="">
                             </div>
-                            <!-- 解析 -->
-                            <!-- <div class="item-explain">
-                                <span class="explain-title">【{{ $t("studentWeb.exam.report.testAnalyse") }}】</span>
-                                <div class="item-explain-details">
-                                    <div v-html="paperData[CarouselIndex].explain ? paperData[CarouselIndex].explain : $t('studentWeb.exam.report.noAnalyse')"></div>
-                                </div>
-                            </div> -->
-                            <!-- 知识点 -->
-                            <!-- <div class="item-explain">
-                                <span class="explain-title">【{{ $t("studentWeb.exam.report.knowledge") }}】</span>
-                                <div v-if="paperData[CarouselIndex].knowledge && paperData[CarouselIndex].knowledge.length" class="item-explain-details">
-                                    <span v-for="(knowledgeC, indexKC) in paperData[CarouselIndex].knowledge" :key="indexKC" class="knowledge-style">
-                                        {{ knowledgeC }}
-                                    </span>
-                                </div>
-                                <div v-else class="item-explain-details">
-                                    {{ $t("studentWeb.exam.report.noKnowledge") }}
-                                </div>
-                            </div> -->
-                            <!-- 认知层次 -->
-                            <div class="item-explain">
-                                <span class="explain-title">【{{ $t("studentWeb.exam.report.filed") }}】</span>
-                                <div class="item-explain-details">
-                                    <div>{{ levelList[paperData[CarouselIndex].field - 1] }}</div>
+                        </template>
+                        <template v-else-if="imgList.length > 1">
+                            <Carousel v-model="CarouselIndex" loop>
+                                <CarouselItem v-for="(img, indexs) in imgList" :key="indexs">
+                                    <!-- 不是综合题 -->
+                                    <div class="left-img" @click="$hevueImgPreview(img)">
+                                        <!-- <div class="que-item"> -->
+                                            <img :src="img" alt="">
+                                        <!-- </div> -->
+                                        <!-- <p v-if="!paperInfo.attachments" style="margin-bottom: 10px;">当前题目没有图片</p> -->
+                                    </div>
+                                </CarouselItem>
+                            </Carousel>
+                        </template>
+                    </div>
+                    <div style="width: 50%; margin-left: 20px; height: 500px;">
+                        <vuescroll>
+                            <div v-for="(exam, indexs) in paperData" :key="indexs" style="margin-bottom: 40px;"
+                                v-show="checkedAnsFilter(false, indexs) || (exam.type === 'compose' && ((checkedAns.includes('right') && exam.rightNum) || (checkedAns.includes('wrong') && !exam.rightNum)))"
+                            >
+                                <div>
+                                    <div style="float: right;">
+                                        <span style="font-size: 20px; color:#00ad6c;">{{ exam.getScore }}</span>
+                                            / <span style="font-size: 12px;">{{ exam.score }}{{ $t("studentWeb.exam.score111") }}</span>
+                                    </div>
+                                    <div style="display: flex; font-size: 16px; margin-bottom: 10px;">
+                                        <span style="margin-right: 10px;">
+                                            <Icon type="md-close-circle" color="#FF5508" size="25"
+                                                v-show="exam.getScore != exam.score"
+                                            />
+                                            <Icon type="md-checkmark-circle" color="#00AD6C" size="25"
+                                                v-show="exam.getScore === exam.score"
+                                            />
+                                        </span>
+                                        <p style="max-width:75px;font-weight:600">{{ indexs + 1 }}.</p>
+                                        <span class="tag-style">{{ getTestType(exam.type) }}</span>
+                                        <!-- <div class="que-item" v-html="exam.question"></div> -->
+                                    </div>
                                 </div>
-                            </div>
-                            <!-- 补救资源 -->
-                            <!-- <div class="item-explain">
-                                <span class="explain-title">【{{ $t("studentWeb.exam.report.repairSource") }}】</span>
-                                <div class="item-explain-details">
-                                    <span v-if="!paperData[CarouselIndex].repair.length">{{$t("studentWeb.exam.report.noSource")}}</span>
-                                    <div v-if="paperData[CarouselIndex].repair && paperData[CarouselIndex].repair.length" class="repair-box">
-                                        <div v-for="(repairSource, normalIndex) in paperData[CarouselIndex].repair" :key="normalIndex" class="repair-link-wrap-item-box">
-                                            <div class="file-icon">
-                                                <img :src="$tools.getFileThum(repairSource.type, repairSource.name)"/>
-                                            </div>
-                                            <div class="file-info">
-                                                <p class="file-name">{{ repairSource.name }}</p>
-                                                <div>
-                                                    <span @click="onPreview(repairSource)" v-if="repairSource.type !== 'other'">{{ $t('ability.review.preview')}}</span>
-                                                    <span @click="onDownload(repairSource)" v-if="repairSource.type !== 'link'">{{ $t('ability.review.download')}}</span>
+                                <div>
+                                    <div class="item-explain">
+                                        <span class="explain-title">【{{ $t("studentWeb.exam.report.ansRes") }}】</span>
+                                        <div v-if="exam.stuAns.length" class="item-explain-details">
+                                            <span v-for="(stuAns, indexA) in exam.stuAns" :key="indexA" v-html="stuAns"></span>
+                                        </div>
+                                        <div v-if="!exam.stuAns.length" class="item-explain-details">
+                                            <span>{{ $t('studentWeb.exam.report.noAns') }}</span>
+                                        </div>
+                                    </div>
+                                    <!-- 批注 -->
+                                    <!-- <div class="item-explain" v-if="exam.type != 'single' && exam.type != 'multiply' && exam.type != 'judge'">
+                                        <span class="explain-title">【{{ $t("studentWeb.exam.report.mark") }}】</span>
+                                        <div v-if="exam.mark.length" class="item-explain-details">
+                                            <img :src="exam.mark[0].imgUrl" alt="" v-if="exam.mark.length === 1">
+                                            <Tabs v-else type="card">
+                                                <TabPane :label="$t('studentWeb.exam.report.mark') + (mIndex + 1)" v-for="(mDate, mIndex) in exam.mark" :key="mIndex">
+                                                    <img :src="mDate.imgUrl" alt="">
+                                                </TabPane>
+                                            </Tabs>
+                                        </div>
+                                        <div v-else class="item-explain-details">{{ $t("studentWeb.exam.report.noMark") }}</div>
+                                    </div> -->
+                                    <!-- 参考答案 -->
+                                    <div class="item-explain">
+                                        <span class="explain-title">【{{ $t("studentWeb.exam.report.testAns") }}】</span>
+                                        <div v-if="exam.answer.length" class="item-explain-details">
+                                            <div v-for="(answerC, indexCA) in exam.answer" :key="indexCA" v-html="answerC"></div>
+                                        </div>
+                                        <div v-if="!exam.answer.length" class="item-explain-details">
+                                            <span>{{ $t('studentWeb.exam.report.noAns') }}</span>
+                                        </div>
+                                    </div>
+                                    <!-- 解析 -->
+                                    <!-- <div class="item-explain">
+                                        <span class="explain-title">【{{ $t("studentWeb.exam.report.testAnalyse") }}】</span>
+                                        <div class="item-explain-details">
+                                            <div v-html="exam.explain ? exam.explain : $t('studentWeb.exam.report.noAnalyse')"></div>
+                                        </div>
+                                    </div> -->
+                                    <!-- 知识点 -->
+                                    <!-- <div class="item-explain">
+                                        <span class="explain-title">【{{ $t("studentWeb.exam.report.knowledge") }}】</span>
+                                        <div v-if="exam.knowledge && exam.knowledge.length" class="item-explain-details">
+                                            <span v-for="(knowledgeC, indexKC) in exam.knowledge" :key="indexKC" class="knowledge-style">
+                                                {{ knowledgeC }}
+                                            </span>
+                                        </div>
+                                        <div v-else class="item-explain-details">
+                                            {{ $t("studentWeb.exam.report.noKnowledge") }}
+                                        </div>
+                                    </div> -->
+                                    <!-- 认知层次 -->
+                                    <div class="item-explain">
+                                        <span class="explain-title">【{{ $t("studentWeb.exam.report.filed") }}】</span>
+                                        <div class="item-explain-details">
+                                            <div>{{ levelList[exam.field - 1] }}</div>
+                                        </div>
+                                    </div>
+                                    <!-- 补救资源 -->
+                                    <!-- <div class="item-explain">
+                                        <span class="explain-title">【{{ $t("studentWeb.exam.report.repairSource") }}】</span>
+                                        <div class="item-explain-details">
+                                            <span v-if="!exam.repair.length">{{$t("studentWeb.exam.report.noSource")}}</span>
+                                            <div v-if="exam.repair && exam.repair.length" class="repair-box">
+                                                <div v-for="(repairSource, normalIndex) in exam.repair" :key="normalIndex" class="repair-link-wrap-item-box">
+                                                    <div class="file-icon">
+                                                        <img :src="$tools.getFileThum(repairSource.type, repairSource.name)"/>
+                                                    </div>
+                                                    <div class="file-info">
+                                                        <p class="file-name">{{ repairSource.name }}</p>
+                                                        <div>
+                                                            <span @click="onPreview(repairSource)" v-if="repairSource.type !== 'other'">{{ $t('ability.review.preview')}}</span>
+                                                            <span @click="onDownload(repairSource)" v-if="repairSource.type !== 'link'">{{ $t('ability.review.download')}}</span>
+                                                        </div>
+                                                    </div>
                                                 </div>
                                             </div>
                                         </div>
-                                    </div>
+                                    </div> -->
                                 </div>
-                            </div> -->
-                        </div>
+                            </div>
+                        </vuescroll>
                     </div>
                 </div>
             </div>
@@ -586,9 +606,13 @@
                 previewStatus: false,
                 previewFile: null,
                 CarouselIndex: 0,
+                imgList: [],
             };
         },
         mounted() {
+            if(this.examInfo.qamode) {
+                this.getImgList()
+            }
             this.testState = 0
             this.testJudge()
         },
@@ -900,25 +924,36 @@
                 a = `${blobHost}/${data.code}/exam/${data.blob}`
                 return a
             },
-            checkedAnsFilter(index, indexE, indexC) {
-                if(indexC === undefined) {
-                    if (this.checkedAns.includes("right") && this.newPaperData[index].exam[indexE].getScore === this.newPaperData[index].exam[indexE].score) {
+            checkedAnsFilter(typeExam, index, indexE, indexC) {
+                if(!typeExam) {
+                    if (this.checkedAns.includes("right") && this.examInfo.stuScore[index] == this.paperData[index].score) {
                         return true;
-                    } else if (this.checkedAns.includes("wrong") && this.newPaperData[index].exam[indexE].getScore != this.newPaperData[index].exam[indexE].score)
+                    } else if (this.checkedAns.includes("wrong") && this.examInfo.stuScore[index] != -1 && this.examInfo.stuScore[index] != this.paperData[index].score)
                     {
                         return true;
+                    } else if (this.checkedAns.includes("noAns") && this.examInfo.stuScore[index] == -1) {
+                        return true;
                     }
                     else return false;
                 } else {
-                    if (this.checkedAns.includes("right") && this.newPaperData[index].exam[indexE].children[indexC].getScore === this.newPaperData[index].exam[indexE].children[indexC].score) {
-                        return true;
-                    } else if (this.checkedAns.includes("wrong") && this.newPaperData[index].exam[indexE].children[indexC].getScore != this.newPaperData[index].exam[indexE].children[indexC].score)
-                    {
-                        return true;
+                    if(indexC === undefined) {
+                        if (this.checkedAns.includes("right") && this.newPaperData[index].exam[indexE].getScore === this.newPaperData[index].exam[indexE].score) {
+                            return true;
+                        } else if (this.checkedAns.includes("wrong") && this.newPaperData[index].exam[indexE].getScore != this.newPaperData[index].exam[indexE].score)
+                        {
+                            return true;
+                        }
+                        else return false;
+                    } else {
+                        if (this.checkedAns.includes("right") && this.newPaperData[index].exam[indexE].children[indexC].getScore === this.newPaperData[index].exam[indexE].children[indexC].score) {
+                            return true;
+                        } else if (this.checkedAns.includes("wrong") && this.newPaperData[index].exam[indexE].children[indexC].getScore != this.newPaperData[index].exam[indexE].children[indexC].score)
+                        {
+                            return true;
+                        }
+                        else return false;
                     }
-                    else return false;
                 }
-
             },
             // 控制收缩试卷的按钮
             closeDetail(typeIndex, parentIndex, childIndex) {
@@ -984,6 +1019,18 @@
             async onDownload(item) {
                 this.$tools.doDownloadByUrl(item.blobUrl, item.name)
             },
+            async getImgList() {
+                if(!this.getPaperInfo.attachments) {
+                    return
+                }
+                let codes = this.getItemTitle.scope === 'school' ? this.getItemTitle.school : this.getItemTitle.creatorId
+                let sas = await this.$tools.getBlobSas(codes)
+                let blob = this.examInfo.blob
+                this.imgList = this.getPaperInfo.attachments.map(item => {
+                    let url = sas.url + "/" + codes + blob + '/' + item + '?' + sas.sas
+                    return url
+                })
+            },
         },
         computed: {
             ...mapGetters([
@@ -1044,7 +1091,7 @@
                 return name => {
                     return name.substr(name.lastIndexOf(".") + 1)
                 }
-            }
+            },
         },
         watch: {
             examInfo: {

+ 35 - 69
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperView.vue

@@ -2,18 +2,10 @@
     <div class="lesson-test" id="paperView">
         <!-- <PaperTest :papers="selectData" v-if="getisOpenLessonTestPopNow" />  -->
             <Loading v-show="isLoad" bgColor="rgba(0, 0, 0, 0.3)"></Loading>
-            <!-- <div class="load-box">
-                <load :active.sync="isLoad"
-                      background-color="#000">
-                    <template slot="default">
-                        <svg-icon icon-class="loader" class="loader-icon" />
-                    </template>
-                </load>
-            </div> -->
         <!-- <div> -->
                 <EventBasicInfo :info="nowActive" :paper="paperData" />
                 <!--多學科試卷-->
-                <div v-if="paperData.length ">
+                <div v-if="paperData.length">
                     <div class="item-box" style="margin-bottom: 25px">
                         <div v-for="(item, index) in paperData"
                             :key="index"
@@ -35,12 +27,12 @@
                             <div v-else :class="['paper-item', index === activeIndex ? 'paper-choose' : '']">
                                 <svg-icon icon-class="test" class="title-icon" />
                                 <span style="margin-top:5px">{{ item.subject.name }}</span>
-                                <div v-show="item.stuAns != undefined && item.stuAns.length != 0">
-                                    <div style="margin-left: 10px; margin-top: 5px; margin-right: 10px;">
+                                <div v-show="item.stuAns != undefined && item.stuAns.length != 0" style="margin-left: 10px; margin-top: 5px; margin-right: 10px;">
+                                    <!-- <div> -->
                                     <!-- <div :class="{ unfinished: item.stuAns.length === 0 ,finished: item.stuAns.length != 0 }"> -->
                                         <Icon type="md-checkmark-circle-outline" size="23" />
                                         <!-- <Icon style="margin-top: -10px; margin-left: -8px;" type="ios-checkmark" size="36" /> -->
-                                    </div>
+                                    <!-- </div> -->
                                 </div>
                             </div>
                         </div>
@@ -61,15 +53,14 @@
                         </div>
                     </TabPane>
                     <!-- 成绩分析 -->
-                    <TabPane :label="$t('studentWeb.exam.gradeReport')" v-if="isTestOver && getItemTitle.owner == 'school'" name="analyse">
+                    <!-- <TabPane :label="$t('studentWeb.exam.gradeReport')" v-if="isTestOver && getItemTitle.owner == 'school'" name="analyse">
                         <div class="title-rect-group">
-                            <!-- <div class="title-rect" /> -->
                             <h2 class="title-rect-name">{{$t("studentWeb.exam.gradeAnalyse")}}</h2>
                         </div>
                         <div class="student-score">
                             <StudentScore :examData="paperData" :stuData="stuData"></StudentScore>
                         </div>
-                    </TabPane>
+                    </TabPane> -->
                 </Tabs>
         <!-- </div> -->
         <div class="top-icon" @click="gotoTop">
@@ -106,19 +97,13 @@
         },
         data() {
             return {
-                unhintNextItem: false,
                 ishideHint: false,
                 //提示下一個
-                mockdata: "",
-                nextItem: "", //存放下個活動預告
-                isHintNextItem: false,
-                showHint: false,
-                paperData: [], //试卷信息
-                openEva: false,
-                selectData: {}, // 存放完整试卷接口的返回值
+                paperData: [], //试卷信息:学生作答记录、批注、知识点等
+                selectData: {}, // 存放当前科目试题接口的返回值
                 isExamDown: false,
                 chooseData: {},
-                examData: [],
+                examData: [], //试卷基础信息
                 isLoad: false,
                 stuData: {}, //当前评测的所有信息:classId、学科、试卷、作答答案
                 isTestOver: false,
@@ -129,7 +114,6 @@
                 chartsData: undefined, //单科知识点、认知层次等
                 allCharts: undefined, //知识点、认知层次等
                 average: [], //班级平均分
-                btnFlag: false,
             };
         },
         methods: {
@@ -140,7 +124,7 @@
                 this.isTestOver = false
                 this.isLoad = true
                 this.activeIndex = null
-                if (this.getItemTitle.name !== undefined && this.getItemTitle) {
+                if (this.getItemTitle && this.getItemTitle.name !== undefined) {
                     let paper = this.getItemTitle
                     let codes = paper.scope == 'school' ? paper.school : paper.creatorId
                     let req = {
@@ -163,37 +147,36 @@
                                     knowledge: res.knowledge,
                                     total: res.total
                                 }
-                                let resData = res
-                                for (let item of resData.papers) {
+                                res.papers.forEach(item => {
                                     if (item.scope) {
                                         item.source = null
                                         item.source = this.getItemTitle.source
                                         item.qamode = this.getItemTitle.qamode
                                         this.paperData.push(item)
                                     }
-                                }
+                                })
                                 for (let i = 0; i < this.paperData.length; i++) {
-                                    this.paperData[i].subject = resData.subjects[i]
-                                    this.paperData[i].allClass = resData.claId
-                                    if(resData.stuAns.length) {
-                                        if (resData.stuAns[i].length == 0) {
-                                            console.log(resData.stuAns[i]);
+                                    this.paperData[i].subject = res.subjects[i]
+                                    this.paperData[i].allClass = res.claId
+                                    if(res.stuAns.length) {
+                                        if (res.stuAns[i].length == 0) {
+                                            console.log(res.stuAns[i]);
                                             this.paperData[i].stuAns = []
                                             this.paperData[i].stuScore = []
                                         } else {
-                                            this.paperData[i].stuAns = resData.stuAns[i]
+                                            this.paperData[i].stuAns = res.stuAns[i]
                                             // 批注
-                                            this.paperData[i].mark = resData.mark[i]
-                                            /* if (resData.mark[i].length != 0) {
-                                                this.paperData[i].stuAns = [resData.mark[i]]
+                                            this.paperData[i].mark = res.mark[i]
+                                            /* if (res.mark[i].length != 0) {
+                                                this.paperData[i].stuAns = [res.mark[i]]
                                             } else {
-                                                console.log(resData.stuAns[i]);
-                                                this.paperData[i].stuAns = resData.stuAns[i]
+                                                console.log(res.stuAns[i]);
+                                                this.paperData[i].stuAns = res.stuAns[i]
                                             } */
-                                            this.paperData[i].stuScore = resData.stuScore[i]
-                                            if (resData.stuAns[i].length) {
+                                            this.paperData[i].stuScore = res.stuScore[i]
+                                            if (res.stuAns[i].length) {
                                                 let k = 0
-                                                for (let item of resData.stuScore[i]) {
+                                                for (let item of res.stuScore[i]) {
                                                     if (item == -1) {   //有未打分
                                                         k++ // 没有打分+1
                                                     }
@@ -245,7 +228,7 @@
 						if(res.status == 200) {
 							this.$Message.success(this.$t('studentWeb.vote.delSuccess'))
 							this.$EventBus.$emit('delNotFound', this.getItemTitle.id)
-                            this.$store.commit("ChangeItemName", {})
+                            this.$store.commit("ChangeItemName", null)
 						} else {
                             this.$Message.warning(this.$t('studentWeb.vote.delError'))
                         }
@@ -280,22 +263,17 @@
                         blob: data.blob,
                         examId: codes
                     }
-                    let exam = {}
-                    for (let item of this.examData) {
-                        if (data.paperId == item.id) {
-                            exam = item
-                        }
-                    }
-                    if (exam.id == undefined) {
+                    // 最开始不存在,就存进去getStuPaper 的值,方便后续再次查找,不用再调用api
+                    this.selectData = this.examData.find(item => {
+                        return data.paperId === item.id
+                    })
+                    if(!this.selectData) {
                         try {
                             this.selectData = await this.getStuPaper(code)
                             this.examData.push(this.selectData)
                         } catch (error) {
                             this.$Message.error(this.$t("studentWeb.exam.examError"))
                         }
-                        
-                    } else {
-                        this.selectData = exam
                     }
                     if(data.stuScore != undefined) {
                         if (data.stuScore[0] == undefined) {
@@ -331,6 +309,9 @@
                     }
                 })
             },
+            gotoTop() {
+                document.getElementsByClassName("lesson-test")[0].scrollIntoView()
+            },
             /* =====未调用===== */
             dateFormat(timestamp) {
                 var date = new Date(timestamp)
@@ -345,12 +326,6 @@
             opentest: function () {
                 this.$store.commit("ToggleLessonTestPop");
             },
-            gotoTop() {
-                // this.$refs["train-info"].scrollIntoView('paperView', 500)
-                document.getElementsByClassName("lesson-test")[0].scrollIntoView()
-                // document.getElementsByClassName("lesson-test")[0].scrollTop = 0
-                // document.documentElement.scrollIntoView
-            },
         },
         computed: {
             ...mapGetters([
@@ -369,15 +344,6 @@
             }
         },
         watch: {
-            /* $route: {
-                handler() {
-                    this.isExamDown = false
-                    this.examData = []
-                    this.getPaperData()
-                },
-                // 深度观察监听
-                deep: true
-            }, */
             nowActive: {
                 handler() {
                     this.isExamDown = false

+ 3 - 3
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventList.vue

@@ -115,17 +115,17 @@
                                         </span>
                                     </template>
                                     <span v-if="item.ext.type === 'regular'" class="paper-extType"
-                                            style="color: #dc8f57;"
+                                          :style="{'border-color': item.owner === 'school' ? '#88a1d8' :'#ababab', color: '#dc8f57'}"
                                     >
                                         {{ $t('totalAnalysis.ti_text6') }}
                                     </span>
                                     <span v-if="item.ext.type === 'simulation'" class="paper-extType"
-                                            style="color: #76ae38;"
+                                          :style="{'border-color': item.owner === 'school' ? '#88a1d8' :'#ababab', color: '#76ae38'}"
                                     >
                                         {{ $t('totalAnalysis.ti_text7') }}
                                     </span>
                                     <span v-if="item.ext.type === 'normal'" class="paper-extType"
-                                            style="color: #a69b17;"
+                                          :style="{'border-color': item.owner === 'school' ? '#88a1d8' :'#ababab', color: '#a69b17'}"
                                     >
                                         {{ $t('totalAnalysis.ti_text8') }}
                                     </span>

+ 27 - 8
TEAMModelOS/ClientApp/src/components/student-web/HomeView/CourseListView.vue

@@ -270,7 +270,8 @@
                 <TabPane :label="$t('studentWeb.courseContent.classRecord')" name="tab5">
                         <div class="list-block-box">
                             <template v-if="recordList.length">
-                                <vuescroll>
+                                <!-- <vuescroll> -->
+                                <Scroll :on-reach-bottom="handleReachTop" :height="550">
                                     <div v-for="(item, index) in recordList" :key="index" @click="toClassRecord(item, index)"
                                         :class="['list-item', ]">
                                         <ul>
@@ -289,7 +290,8 @@
                                             </li>
                                         </ul>
                                     </div>
-                                </vuescroll>
+                                </Scroll>
+                                <!-- </vuescroll> -->
                             </template>
                             <div v-else style="margin-top: 15px; font-size: 15px; text-align: center;">{{ $t('studentWeb.courseContent.noClassRecord') }}</div>
                         </div>
@@ -317,7 +319,9 @@
                 <!-- 同学名单 -->
                 <TabPane :label="$t('studentWeb.courseContent.classmates')" name="tab3">
                     <div v-if="isChangeGroupView == false">
-                        <Table :columns="stuCol" :data="stuList"></Table>
+                        <!-- <vuescroll> -->
+                            <Table :columns="stuCol" :data="stuList" :height="650"></Table>
+                        <!-- </vuescroll> -->
                     </div>
                     <!--小組模式-->
                     <div v-if="isChangeGroupView == true">
@@ -651,7 +655,8 @@ export default {
             showStuList: false,
             list: "stuList",
             needParam: undefined,
-            showFixList: []
+            showFixList: [],
+            continuationToken: null,
         };
     },
 
@@ -1002,6 +1007,7 @@ export default {
                 this.findStuInfor(this.courseNow)
                 this.needParam.classes = [this.courseNow.stuList]
             }
+            this.recordList = []
             this.getRecordList()
             // 螢幕寬度<767px時,直接關掉sidebar
             if (window.innerWidth <= 991) {
@@ -1023,8 +1029,20 @@ export default {
             var S = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()) + " "
             return Y + M + D + H + Min;
         },
+        handleReachTop () {
+            return new Promise(resolve => {
+                setTimeout(() => {
+                    if(this.continuationToken) {
+                        this.getRecordList()
+                    } else {
+                        this.$Message.warning("没有更多数据")
+                    }
+                    resolve()
+                }, 2000);
+            });
+        },
         getRecordList() {
-            this.recordList = []
+            // this.recordList = []
             let param = {
                 tmdid: this.courseNow.teaId,
                 scope: this.courseNow.scope, //school:传school,private:传tmdid
@@ -1036,9 +1054,9 @@ export default {
                 doubleGreen: false,
                 quality: false,
                 DESC: "startTime",
-                pageCount: 6, //返回六条数据(分页)
+                pageCount: 10, //返回六条数据(分页)
                 today: false,
-                continuationToken: null, //返回的有值的话,下次查询就要用这个值
+                continuationToken: this.continuationToken, //返回的有值的话,下次查询就要用这个值
             }
             param.scope === "school" ? param.school = this.userInfo.azp : param.tmdid = this.courseNow.creatorId
             this.$api.studentWeb.getClassRecord(param).then(res => {
@@ -1051,7 +1069,8 @@ export default {
                         let hour = parseInt(min / 60)
                         item.time = `${hour < 10 ? ('0' + hour) : hour}:${mins < 10 ? ('0' + mins) : mins}:${sec < 10 ? ('0' + sec) : sec}`
                     })
-                    this.recordList = res.lessonRecords
+                    this.recordList.push.apply(this.recordList, res.lessonRecords)
+                    this.continuationToken = res.continuationToken
                 }
             })
         },

+ 73 - 1
TEAMModelOS/ClientApp/src/css/common-style.less

@@ -56,6 +56,7 @@
 .ivu-table:before{
     height: 0px !important;
 }
+//自定义check-box style
 .custom-check-box {
     user-select: none;
 
@@ -104,6 +105,77 @@
         }
     }
 }
+//自定义radio-box
+.custom-radio-box{
+    .ivu-select-selection {
+        background: transparent;
+        border-color: #363738;
+        color: #a6a6a6;
+    }
+
+    .ivu-radio-wrapper {
+        margin-right: 20px;
+        color: #303030;
+    }
+
+    .ivu-radio-inner {
+        width: 18px;
+        height: 18px;
+        border-radius: 4px;
+        border-color: #c3c3c3;
+        border-width: 1px;
+        margin-right: 5px;
+        &::after {
+            content: "";
+            display: block;
+            width: 10px;
+            height: 16px;
+            border-right: #ffffff solid 3px;
+            border-bottom: #ffffff solid 3px;
+            transform: rotate(35deg) !important;
+            position: absolute;
+            top: -4px;
+            left: 4px;
+            border-radius: 0;
+            background-color: transparent;
+            border-color: #0094ff;
+        }
+    }
+    .ivu-checkbox-inner {
+        width: 18px;
+        height: 18px;
+        border-radius: 4px;
+        border-color: var(--border-color);
+        border-width: 1px;
+        margin-right: 5px;
+    }
+
+    .ivu-checkbox-checked .ivu-checkbox-inner {
+        width: 18px;
+        height: 18px;
+        border-radius: 4px;
+        background-color: #fff;
+        border-color: #4d4d4d;
+        border-width: 1px;
+        margin-right: 5px;
+        &::after {
+            content: "";
+            display: block;
+            width: 10px;
+            height: 16px;
+            border-right: #ffffff solid 3px;
+            border-bottom: #ffffff solid 3px;
+            transform: rotate(35deg);
+            transition: all 0.1s;
+            position: absolute;
+            top: -4px;
+            left: 4px;
+            border-radius: 0;
+            background-color: transparent;
+            border-color: #0094ff;
+        }
+    }
+}
 
 .tab-box {
     display: inline-block;
@@ -157,7 +229,7 @@
     .confirm-btn{
         background: #70B1E7;
         color: white;
-        margin: 40px 0px 45px 0px;
+        margin: 40px 0px 35px 0px;
         height: 40px;
         border: none;
     }

+ 1 - 1
TEAMModelOS/ClientApp/src/locale/lang/en-US/ability.js

@@ -182,7 +182,7 @@ export default {
 		comment: '評論內容',
 		tip1: '評論內容不能為空!',
 		commentSuc: '評論成功!',
-		tip2: '只有專家或管理員身份才能進行評審操作!',
+		tip2: '您暫無課堂實錄評審權限!',
 		submitSuc: '提交成功!',
 		xAxis: '視頻進度',
 		yAxis: '專家點評數',

+ 9 - 1
TEAMModelOS/ClientApp/src/locale/lang/en-US/home.js

@@ -75,5 +75,13 @@ export default{
     semesterCount: "This semester's lesson",
     weekCount: "This week's lesson",
     dayCount: "Today's lesson",
-    cusTableErr: 'Failed to get the class schedule'
+    cusTableErr: 'Failed to get the class schedule',
+    count1:'學校課程',
+    count2:'任教班級',
+    count3:'個人課程',
+    count4:'個人名單',
+    count5:'課綱數量',
+    count6:'試卷數量',
+    count7:'題目數量',
+    count8:'資源數量',
 }

+ 6 - 1
TEAMModelOS/ClientApp/src/locale/lang/en-US/notice.js

@@ -8,6 +8,7 @@ export default {
 	type6: 'Marking Test Assignment Notification',
 	type7: 'Scan Code Join Notification',
 	type8: 'Homework Submission Notification',
+	type9:'課例過期通知',
 	tip1: 'applies to join',
 	tip2: 'has invited you to join',
 	tip3: 'has granted your request to join',
@@ -23,5 +24,9 @@ export default {
 	tip13: 'scanned the code to join',
 	tip14: 'scanned the code to join the list',
 	tip15: 'completed the homework submission of',
-	tip16: ''
+	tip16: '',
+	tip17:'您於',
+	tip18:'教學的課堂',
+	tip19:',由於超過課例最大保存數量,將於',
+	tip20:'失效'
 }

+ 3 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolBaseInfo.js

@@ -138,6 +138,7 @@ export default {
   codeSearchHolder: 'Search',
   classroomCodeHolder: 'eg: 1',
   classroomNameHolder: 'eg: 101',
+  classNameHolder:'eg:202201',
   headmasterHolder: 'Can search by name...',
   hiTeachHolder: 'Please select the available serial number from the list on the right...',
   noHiTeachTips: 'No available serial number',
@@ -241,6 +242,8 @@ export default {
   graduated:'Graduated',
   classLabel:'Class ID',
   profession:'Professional Subject',
+  professionLabel: '專業名稱/類型名稱',
+  professionLabel1: '班級專業名稱/班級類型名稱',
   noProfession:'No professional subject set yet',
   all:'All',
   noSet:'Not set',

+ 1 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/studentWeb.js

@@ -653,6 +653,7 @@ export default {
             noWrong: "This assessment does not have incorrectly answered questions!",
             noStar: "This assessment does not have starred questions!",
             nojoin: "You did not join this activity",
+            noQamode: "此次紙本測驗沒有圖片示例",
         }
     },
     queNaire: {

+ 51 - 45
TEAMModelOS/ClientApp/src/locale/lang/en-US/teachermgmt.js

@@ -63,59 +63,65 @@ export default {
         info19: "Can't find this teacher's information",
         info20: 'This user has already been invited!',
         info21: 'The invited user has already joined the school!',
-        noIdCol: 'There is no id column in the imported form, please check the form data! '
+        noIdCol: 'There is no id column in the imported form, please check the form data! ',
+        spaceTips1:'請設置每人分配的空間大小',
+        spaceTips2:'請選擇需要分配空間的教師職稱',
+        spaceTips3:'請勾選需要分配空間的教師',
+        saveOk:'保存成功'
     },
     job: {
         'jobTitle': 'Add Title',
         'teacher':'Teacher'
     },
     authority:{
-        'classroom':'Classroom Settings',
-        'system':'School Basic Data Management',
-        'studentAccount':'Student Account Management',
-        'teachermgmt':'Teacher Account Management',
-        'classroom-read':'View Classroom Information',
-        'classroom-upd':'Change Classroom Settings',
-        'schoolSetting-read':'View School Basic Settings',
-        'schoolSetting-upd':'Change School Basic Settings',
-        'student-read':'View Student Account',
-        'student-upd':'Change Student Account',
-        'teacher-checkTeacher':'Check if the teacher can view',
-        'teacher-read':'View Teacher Account',
-        'teacher-upd': 'Change Teacher Account',
-        'manageCourse': ' Course Setting Management',
-        'course-read': 'View Course Setting Information',
-        'course-upd': 'Modify Course Setting Information',
-        'newCoursePlan': 'Course Scheduling Management',
-        'coursePlan-read': 'View Course Scheduling Information',
-        'coursePlan-upd': 'Modify Course Scheduling Information',
-        'serviceDriveAuth': 'Authorization Management',
-        'auth-read': 'View Authorization Management Information',
-        'auth-upd': 'Modify Authorization Management Information',
-        'syllabus': 'School Syllabus Management',
-        'syllabus-read': 'View School Syllabus Information',
-        'syllabus-upd': 'Modify School Syllabus Information',
-        'schoolContent': 'School Content Management',
-        'content-read': 'View School Content Information',
-        'content-upd': 'Modify School Content Information',
-        'schoolBank': 'School Question Bank Management ',
-        'exercise-read': 'View School Question Bank Information',
-        'exercise-upd': 'Modify School Question Bank Information',
-        'knowledge': 'Key Concept Bank Management ',
-        'knowledge-read': 'View Key Concept Bank Information',
-        'knowledge-upd': 'Modify knowledge Key Concept Bank Information',
-        'analysis': 'Learning Status Analysis',
-        'analysis-read': 'View School Learning Status Analysis',
-        'scboard': 'Statistical Data',
-        'scboard-read': 'View Statistical Data',
-        'schoolAc': 'School Activity',
-        'schoolAc-read': 'View School Activity',
-        'schoolAc-upd': 'Start School Activity',
-        'trainAll':'Seminar Center',
-        'train-read':'View Seminar Center Data',
-        'train-upd':'Manage Seminar Center Data',
+        'classroom': '教室管理',
+        'classroom-read': '檢視教室資料',
+        'classroom-upd': '變更教室設定',
+        'schoolSetting': '學校基礎數據管理',
+        'schoolSetting-read': '檢視學校基礎設定',
+        'schoolSetting-upd': '變更學校基礎設定',
+        'student': '學生賬號管理',
+        'student-read': '檢視學生賬號',
+        'student-upd': '變更學生賬號',
+        'teacher': '教師賬號管理',
+        'teacher-read': '檢視教師賬號',
+        'teacher-upd': '變更教師賬號',
+        'course': '課程設置管理',
+        'course-read': '查看課程設置信息',
+        'course-upd': '修改課程設置信息',
+        'newCoursePlan': '排課管理',
+        'coursePlan-read': '查看排課信息',
+        'coursePlan-upd': '修改排課信息',
+        'serviceDriveAuth': '授權管理',
+        'auth-read': '查看授權管理信息',
+        'auth-upd': '修改授權管理信息',
+        'syllabus': '學校課綱管理',
+        'syllabus-read': '查看學校課綱信息',
+        'syllabus-upd': '修改學校課綱信息',
+        'schoolContent': '學校內容管理',
+        'content-read': '查看學校內容信息',
+        'content-upd': '修改學校內容信息',
+        'schoolBank': '學校題庫管理',
+        'exercise-read': '查看學校題庫信息',
+        'exercise-upd': '修改學校題庫信息',
+        'knowledge': '知識點庫管理',
+        'knowledge-read': '查看知識點庫信息',
+        'knowledge-upd': '修改知識點庫信息',
+        'analysis': '學情分析',
+        'analysis-read': '查看學校學情分析',
+        'scboard': '統計分析',
+        'scboard-read': '查看統計分析',
+        'schoolAc': '學校活動',
+        'schoolAc-read': '查看學校活動',
+        'schoolAc-upd': '發布學校活動',
+        'train': '研修中心',
+        'train-read': '查看研修中心數據',
+        'train-upd': '管理研修中心數據',
         'dashboard':'數據看板',
         'dashboard-read':'數據看板查看權限',
+        'research':'課例中心模塊',
+        'research-read':'課例中心查看權限',
+        'research-upd':'課例中心管理(修改)權限'
     },
     modal:{
         text1: 'The authorization of this account has been changed, do you want to give this account a more appropriate title?',

+ 1 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/ability.js

@@ -182,7 +182,7 @@ export default {
 		comment:'评论内容',
 		tip1:'评论内容不能为空!',
 		commentSuc:'评论成功!',
-		tip2:'只有专家或管理员身份才能进行评审操作!',
+		tip2:'您暂无课堂实录评审权限!',
 		submitSuc:'提交成功!',
 		xAxis:'视频进度',
 		yAxis:'专家点评数',

+ 10 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/home.js

@@ -75,5 +75,14 @@ export default{
     semesterCount:'本学期课例',
     weekCount:'本周课例',
     dayCount:'今日课例',
-    cusTableErr:'获取课表失败'
+    cusTableErr:'获取课表失败',
+    count1:'学校课程',
+    count2:'任教班级',
+    count3:'个人课程',
+    count4:'个人名单',
+    count5:'课纲数量',
+    count6:'试卷数量',
+    count7:'题目数量',
+    count8:'资源数量',
+
 }

+ 6 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/notice.js

@@ -8,6 +8,7 @@ export default {
 	type6:'阅卷任务分配通知',
 	type7:'扫码加入通知',
 	type8:'作业提交通知',
+	type9:'课例过期通知',
 	tip1:'申请加入',
 	tip2:'邀请您加入',
 	tip3:'已同意您的加入请求',
@@ -23,5 +24,9 @@ export default {
 	tip13:'通过扫码加入',
 	tip14:'通过扫码加入名单',
 	tip15:'在活动',
-	tip16:'中完成了作业提交'
+	tip16:'中完成了作业提交',
+	tip17:'您于',
+	tip18:'教学的课堂',
+	tip19:',由于超过课例最大保存数量,将于',
+	tip20:'失效'
 }

+ 3 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/schoolBaseInfo.js

@@ -138,6 +138,7 @@ export default {
   codeSearchHolder: '请输入关键字搜索',
   classroomCodeHolder: 'eg: 1',
   classroomNameHolder: 'eg: 一年级一班',
+  classNameHolder:'eg:2022级1班',
   headmasterHolder: '可通过名字搜索...',
   hiTeachHolder: '请在右侧列表选择可用序号...',
   noHiTeachTips: '没有可用序号',
@@ -241,6 +242,8 @@ export default {
   graduated: '已毕业',
   classLabel: '班级',
   profession: '专业',
+  professionLabel: '专业名称/类型名称',
+  professionLabel1: '班级专业名称/班级类型名称',
   noProfession: '暂未设置专业',
   all: '全部',
   noSet: '未设置',

+ 2 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/studentWeb.js

@@ -292,7 +292,7 @@ export default {
     makeupHW: '可补交',
     empty: '目前无资料 ~',
     baseInfo: {
-        subject: '学科:',
+        subject: '评测学科:',
         teacher: '课程教师:',
         stuList: "课程名单:",
         nowStu: "学生姓名:",
@@ -653,6 +653,7 @@ export default {
             noWrong: "当前评量无错题可进行练习!",
             noStar: "当前评量无标星题目!",
             nojoin: "您没有加入该活动",
+            noQamode: "此次纸本测验没有图片示例",
         }
     },
     queNaire: {

+ 13 - 7
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachermgmt.js

@@ -63,7 +63,11 @@ export default {
         info19: '找不到此教师的资料',
         info20: '用户已被邀请,请勿重复邀请!',
         info21: '邀请对象已加入学校!无法再次邀请!',
-        noIdCol: '导入表格没有id栏位,请检查表格数据!'
+        noIdCol: '导入表格没有id栏位,请检查表格数据!',
+        spaceTips1:'请设置每人分配的空间大小',
+        spaceTips2:'请选择需要分配空间的教师职称',
+        spaceTips3:'请勾选需要分配空间的教师',
+        saveOk:'保存成功'
     },
     job: {
         'jobTitle': '添加职称',
@@ -71,19 +75,18 @@ export default {
     },
     authority: {
         'classroom': '教室管理',
-        'system': '学校基础数据管理',
-        'studentAccount': '学生账号管理',
-        'teachermgmt': '教师账号管理',
         'classroom-read': '检视教室资料',
         'classroom-upd': '变更教室设定',
+        'schoolSetting': '学校基础数据管理',
         'schoolSetting-read': '检视学校基础设定',
         'schoolSetting-upd': '变更学校基础设定',
+        'student': '学生账号管理',
         'student-read': '检视学生账号',
         'student-upd': '变更学生账号',
-        'teacher-checkTeacher': '检查老师可否看',
+        'teacher': '教师账号管理',
         'teacher-read': '检视教师账号',
         'teacher-upd': '变更教师账号',
-        'manageCourse': '课程设置管理',
+        'course': '课程设置管理',
         'course-read': '查看课程设置信息',
         'course-upd': '修改课程设置信息',
         'newCoursePlan': '排课管理',
@@ -111,11 +114,14 @@ export default {
         'schoolAc': '学校活动',
         'schoolAc-read': '查看学校活动',
         'schoolAc-upd': '发布学校活动',
-        'trainAll': '研修中心',
+        'train': '研修中心',
         'train-read': '查看研修中心数据',
         'train-upd': '管理研修中心数据',
         'dashboard':'数据看板',
         'dashboard-read':'数据看板查看权限',
+        'research':'课例中心模块',
+        'research-read':'课例中心查看权限',
+        'research-upd':'课例中心管理(修改)权限'
     },
     modal: {
         text1: '此账号权限已变更,是否要给此账号更加合适的职称',

+ 1 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/ability.js

@@ -182,7 +182,7 @@ export default {
 		comment: '評論內容',
 		tip1: '評論內容不能為空!',
 		commentSuc: '評論成功!',
-		tip2: '只有專家或管理員身份才能進行評審操作!',
+		tip2: '您暫無課堂實錄評審權限!',
 		submitSuc: '提交成功!',
 		xAxis: '影片進度',
 		yAxis: '專家點評數',

+ 9 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/home.js

@@ -75,5 +75,13 @@ export default {
     semesterCount:'本學期課例',
     weekCount:'本週課例',
     dayCount:'今日課例',
-    cusTableErr:'獲取課表失敗'
+    cusTableErr:'獲取課表失敗',
+    count1:'學校課程',
+    count2:'任教班級',
+    count3:'個人課程',
+    count4:'個人名單',
+    count5:'課綱數量',
+    count6:'試卷數量',
+    count7:'題目數量',
+    count8:'資源數量',
 }

+ 6 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/notice.js

@@ -8,6 +8,7 @@ export default {
 	type6:'閱卷任務分配通知',
 	type7:'掃碼加入通知',
 	type8:'作業提交通知',
+	type9:'課例過期通知',
 	tip1: '申請加入',
 	tip2: '邀請您加入',
 	tip3: '已同意您的加入請求',
@@ -23,5 +24,9 @@ export default {
 	tip13:'通過掃碼加入',
 	tip14:'通過掃碼加入名單',
 	tip15:'在活動',
-	tip16:'中完成了作業提交'
+	tip16:'中完成了作業提交',
+	tip17:'您於',
+	tip18:'教學的課堂',
+	tip19:',由於超過課例最大保存數量,將於',
+	tip20:'失效'
 }

+ 4 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/schoolBaseInfo.js

@@ -138,6 +138,7 @@ export default {
   codeSearchHolder: '請輸入關鍵字搜尋',
   classroomCodeHolder: 'eg: 1',
   classroomNameHolder: 'eg:一年級一班',
+  classNameHolder:'eg:2022級1班',
   headmasterHolder: '可通過名字搜尋…',
   hiTeachHolder: '請在右側清單選擇可用序號…',
   noHiTeachTips: '沒有可用序號',
@@ -239,8 +240,10 @@ export default {
   yearGrade: '學級/年級',
   untimed: '未到入學時間',
   graduated: '已畢業',
-  classLabel: '班級編',
+  classLabel: '班級編',
   profession: '專業學科',
+  professionLabel: '專業名稱/類型名稱',
+  professionLabel1: '班級專業名稱/班級類型名稱',
   noProfession: '暫未設置專業',
   all: '全部',
   noSet:'未設置',

+ 2 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/studentWeb.js

@@ -292,7 +292,7 @@ export default {
     makeupHW: '可補交',
     empty: '目前無資料 ~',
     baseInfo: {
-        subject: '學科:',
+        subject: '評量學科:',
         teacher: '課程教師:',
         stuList: "學生名單:",
         nowStu: "學生姓名:",
@@ -653,6 +653,7 @@ export default {
             noWrong: "當前評量無錯題可進行練習!",
             noStar: "當前評量無標星題目!",
             nojoin: "您沒有加入該活動",
+            noQamode: "此次紙本測驗沒有圖片示例",
         }
     },
     queNaire: {

+ 33 - 27
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/teachermgmt.js

@@ -63,7 +63,11 @@ export default {
         info19: '找不到此教師的資料',
         info20: '用戶已被邀請,請勿重複邀請!',
         info21: '邀請對象已加入學校!無法再次邀請!',
-        noIdCol: '導入表格沒有id欄位,請檢查表格數據! '
+        noIdCol: '導入表格沒有id欄位,請檢查表格數據! ',
+        spaceTips1:'請設置每人分配的空間大小',
+        spaceTips2:'請選擇需要分配空間的教師職稱',
+        spaceTips3:'請勾選需要分配空間的教師',
+        saveOk:'保存成功'
     },
     job: {
         'jobTitle': '加入職稱',
@@ -71,51 +75,53 @@ export default {
     },
     authority: {
         'classroom': '教室管理',
-        'system': '學校基礎數據管理',
-        'studentAccount': '學生帳號管理',
-        'teachermgmt': '教師帳號管理',
         'classroom-read': '檢視教室資料',
         'classroom-upd': '變更教室設定',
+        'schoolSetting': '學校基礎數據管理',
         'schoolSetting-read': '檢視學校基礎設定',
         'schoolSetting-upd': '變更學校基礎設定',
-        'student-read': '檢視學生帳號',
-        'student-upd': '變更學生帳號',
-        'teacher-checkTeacher': '檢查老師是否可看',
-        'teacher-read': '檢視教師帳號',
-        'teacher-upd': '變更教師帳號',
-        'manageCourse': '課程設置管理',
-        'course-read': '查看課程設置資訊',
-        'course-upd': '修改課程設置資訊',
+        'student': '學生賬號管理',
+        'student-read': '檢視學生賬號',
+        'student-upd': '變更學生賬號',
+        'teacher': '教師賬號管理',
+        'teacher-read': '檢視教師賬號',
+        'teacher-upd': '變更教師賬號',
+        'course': '課程設置管理',
+        'course-read': '查看課程設置信息',
+        'course-upd': '修改課程設置信息',
         'newCoursePlan': '排課管理',
-        'coursePlan-read': '查看排課資訊',
-        'coursePlan-upd': '修改排課資訊',
+        'coursePlan-read': '查看排課信息',
+        'coursePlan-upd': '修改排課信息',
         'serviceDriveAuth': '授權管理',
-        'auth-read': '查看授權管理資訊',
-        'auth-upd': '修改授權管理資訊',
+        'auth-read': '查看授權管理信息',
+        'auth-upd': '修改授權管理信息',
         'syllabus': '學校課綱管理',
-        'syllabus-read': '查看學校課綱資訊',
-        'syllabus-upd': '修改學校課綱資訊',
+        'syllabus-read': '查看學校課綱信息',
+        'syllabus-upd': '修改學校課綱信息',
         'schoolContent': '學校內容管理',
-        'content-read': '查看學校內容資訊',
-        'content-upd': '修改學校內容資訊',
+        'content-read': '查看學校內容信息',
+        'content-upd': '修改學校內容信息',
         'schoolBank': '學校題庫管理',
-        'exercise-read': '查看學校題庫資訊',
-        'exercise-upd': '修改學校題庫資訊',
+        'exercise-read': '查看學校題庫信息',
+        'exercise-upd': '修改學校題庫信息',
         'knowledge': '知識點庫管理',
-        'knowledge-read': '查看知識點庫資訊',
-        'knowledge-upd': '修改知識點庫資訊',
+        'knowledge-read': '查看知識點庫信息',
+        'knowledge-upd': '修改知識點庫信息',
         'analysis': '學情分析',
         'analysis-read': '查看學校學情分析',
-        'scboard': '統計數據',
-        'scboard': '查看統計數據',
+        'scboard': '統計分析',
+        'scboard-read': '查看統計分析',
         'schoolAc': '學校活動',
         'schoolAc-read': '查看學校活動',
         'schoolAc-upd': '發布學校活動',
-        'trainAll': '研修中心',
+        'train': '研修中心',
         'train-read': '查看研修中心數據',
         'train-upd': '管理研修中心數據',
         'dashboard':'數據看板',
         'dashboard-read':'數據看板查看權限',
+        'research':'課例中心模塊',
+        'research-read':'課例中心查看權限',
+        'research-upd':'課例中心管理(修改)權限'
     },
     modal: {
         text1: '此帳號權限已變更,是否要給此帳號更加合適的職稱',

+ 41 - 2
TEAMModelOS/ClientApp/src/router/routes.js

@@ -361,6 +361,7 @@ export const routes = [{
 	{
 		path: 'teachermgmt',
 		name: 'teachermgmt',
+		redirect:'/home/teachermgmt/mgt',
 		meta: {
 			middleware: ['login', 'ability:admin,teacher-read|teacher-upd']
 		},
@@ -368,6 +369,44 @@ export const routes = [{
 		meta: {
 			activeName: 'teachermgmt'
 		},
+		children: [
+			{
+				path: 'add',
+				name: 'add',
+				component: resolve => require(['@/view/teachermgmt/components/personnel/Index.vue'],
+					resolve),
+				meta: {
+					activeName: 'teachermgmt'
+				},
+			},
+			{
+				path: 'group',
+				name: 'group',
+				component: resolve => require(['@/view/teachermgmt/components/group/Group.vue'],
+					resolve),
+				meta: {
+					activeName: 'teachermgmt'
+				},
+			},
+			{
+				path: 'mgt',
+				name: 'mgt',
+				component: resolve => require(['@/view/teachermgmt/components/mgt/TeacherMgt.vue'],
+					resolve),
+				meta: {
+					activeName: 'teachermgmt'
+				},
+			},
+			{
+				path: 'import',
+				name: 'import',
+				component: resolve => require(['@/view/teachermgmt/components/import/Import.vue'],
+					resolve),
+				meta: {
+					activeName: 'teachermgmt'
+				},
+			}
+		]
 	},
 	{
 		path: 'evaluation',
@@ -636,7 +675,7 @@ export const routes = [{
 		component: resolve => require(['@/view/learnactivity/ExamMgt.vue'], resolve),
 		meta: {
 			// isKeep: true,
-			activeName: 'schoolExam'
+			activeName: 'privExam'
 		}
 	},
 	//管理评测页面(个人)
@@ -1001,7 +1040,7 @@ export const routes = [{
 	{
 		path: 'courseCenter',
 		name: 'courseCenter',
-		component: resolve => require(['@/view/research-center/ResearchCenter.vue'], resolve),
+		component: resolve => require(['@/view/research-center/ResearchCenterMock.vue'], resolve),
 		meta: {
 			activeName: 'courseCenter'
 		}

+ 0 - 2
TEAMModelOS/ClientApp/src/store/index.js

@@ -7,7 +7,6 @@ import config from './module/config'
 import studentWeb from './module/studentWeb'
 import scboard from './module/scboard'
 import { GLOBAL } from '@/static/Global.js'
-import spaceAuth from './module/spaceAuth'
 import answerSheet from './module/answerSheet'
 import dashboard from './module/dashboard'
 import student from './module/student'
@@ -118,7 +117,6 @@ export default new Vuex.Store({
         config,
         studentWeb,
         scboard,
-        spaceAuth,
         answerSheet,
 		dashboard,
         student

+ 14 - 1
TEAMModelOS/ClientApp/src/store/module/answerSheet.js

@@ -109,6 +109,7 @@ export default {
 
 		/* 添加填空题数据 */
 		addCompleteContent(state, val) {
+			console.error('往newContents放填空题框',val)
 			state.config.newContents.push(val)
 		},
 
@@ -256,7 +257,7 @@ export default {
 			console.error('error',val)
 			let newContents = state.config.newContents
 			state.pages++
-			
+			// 跨页添加简答题大框
 			let hasType3 = newContents.find(i => i.type === 3)
 			/* 如果已经存在type为3的初始化大框 则不需要push新的 避免与题型初始化冲突 */
 			if(!(hasType3 && !hasType3.points.length)){
@@ -268,6 +269,18 @@ export default {
 					"points": []
 				})
 			}
+			// 跨页添加填空题大框
+			let hasType4 = newContents.find(i => i.type === 4)
+			/* 如果已经存在type为4的初始化大框 则不需要push新的 避免与题型初始化冲突 */
+			if(!(hasType4 && !hasType4.points.length)){
+				newContents.push({
+					"type": val,
+					"pageNum": state.pages,
+					"count": 0,
+					"pos": [],
+					"points": []
+				})
+			}
 			/* 如果已经有简答题的 并且插入的是填空题的数据 则要把填空题在newContents里面 排到 简答题前面 */
 			if (val === 4 && hasType3) {
 				newContents[newContents.length - 1] = newContents.splice(newContents.indexOf(hasType3), 1, newContents[

+ 2 - 0
TEAMModelOS/ClientApp/src/store/module/config.js

@@ -10,6 +10,7 @@ export default {
             accAPIUrl: 'https://account.teammodel.cn',
             coreAPIUrl: 'https://api2.teammodel.cn',
             irsUrl: 'https://irs5.teammodel.cn',
+			docUrl:'http://doc.teammodel.cn:4999/web/#/7/34',
             domainUrl: [
                 {
                     station: 'product',
@@ -32,6 +33,7 @@ export default {
             accAPIUrl: 'https://account.teammodel.net',
             coreAPIUrl: 'https://api2.teammodel.net',
             irsUrl: 'https://irs5.teammodel.net',
+			docUrl:'http://doc.teammodel.cn:4999/web/#/9/37',
             domainUrl: [
                 {
                     station: 'product',

+ 0 - 185
TEAMModelOS/ClientApp/src/store/module/spaceAuth.js

@@ -1,185 +0,0 @@
-import apiTools from '@/api'
-import i18n from '@/locale'
-export default {
-  namespaced: true,
-  state: {
-    showMessageNum: 0, //1.回收成功, 2.更新成功, 3.要設定的空間>目前學校有的 4.有不存在老師的ID
-    isLoading: false,
-    originalSpace: 0,
-    schoolUsedSpace: 0, //學校其他已經使用的空間
-    teacherUsedSpaceNum: 0, //目前老師已使用空間,
-    maxFixedAssignedValue: 0, //資料進來,可分的最大值
-
-    teacherSpaceData: [], //存放目前所有老師的資料狀態,讓前臺能及時給予更新回饋
-    currentSelectedTeacherId: [], //目前所選存放的老師的id,勾選給空間用
-
-    pieNumData: [
-      { value: 0, name: i18n.t("teachermgmt.usedSpace") },
-      { value: 0, name: i18n.t("teachermgmt.allocatedSpace") },
-      { value: 0, name: i18n.t("teachermgmt.remainingSpace") }
-    ],
-    isKeyInSpace: false //存放是否有進行手動輸入
-  },
-  getters: {
-    getIsKeyInSpace(state) {
-      return state.isKeyInSpace
-    },
-    getMsgNum(state) {
-      return state.showMessageNum
-    },
-    getIsLoading(state) {
-      return state.isLoading
-    },
-    getPieNumData(state) {
-      return state.pieNumData
-    },
-    getOriginalSpace(state) {
-      return state.originalSpace
-    },
-    getMaxFixedAssignedValue(state) {
-      return state.maxFixedAssignedValue
-    },
-    getTeacherSpaceData(state) {
-      return state.teacherSpaceData
-    },
-    getCurrentSelectedTeacherId(state) {
-      return state.currentSelectedTeacherId
-    }
-  },
-  mutations: {
-    setIsKeyInSpace(state, status) {
-      /*if(status==true)console.log('有進行手動輸入')
-      else console.log('沒有進行手動輸入')*/
-      state.isKeyInSpace = status
-    },
-    setCurrentSelectedTeacherId(state, data) {
-      state.currentSelectedTeacherId = data
-      //console.log(data)
-    },
-    setMsgNum(state, no) {
-      state.showMessageNum = no
-    },
-    //回收時直接設為0
-    setIsLoading(state, status) {
-      state.isLoading = status
-    },
-    setTeacherUsedSpaceZero(state) {
-      state.teacherUsedSpaceNum = 0
-    },
-    //存放DB初值,使用者未保存的時候使用
-
-    setTeacherUsedSpaceNum(state, data) {
-      let teacherUsedSpaceNum = 0
-      data.forEach(element => {
-        if (element.size != '-') teacherUsedSpaceNum += parseInt(element.size)
-        else {
-          teacherUsedSpaceNum += 0
-        }
-      })
-      state.teacherUsedSpaceNum = teacherUsedSpaceNum
-    },
-
-    //處理介面上的即時數據
-
-    resetTeacherSpaceUIData(state) {
-      state.teacherSpaceData.forEach(element => {
-        element.size = element.initSize
-      })
-    },
-
-    setTeacherSpaceUIData(state, data) {
-      state.teacherSpaceData = data
-    },
-    setTeacherSpaceUIDataZero(state) {
-      state.teacherSpaceData.forEach(element => {
-        element.size = 0
-      })
-    },
-    updateTeacherSpaceUIData(state, data) {
-      state.teacherSpaceData.forEach(element => {
-        data.forEach(item => {
-          if (element.id == item.id) {
-            element.size = item.size
-          }
-        })
-      })
-    },
-
-    setPieNumData(state, data) {
-      state.originalSpace = data.avaliable
-      state.schoolUsedSpace = data.usedSpace
-      state.pieNumData = [
-        { value: state.schoolUsedSpace, name: i18n.t("teachermgmt.usedSpace") },
-        { value: state.teacherUsedSpaceNum, name: i18n.t("teachermgmt.allocatedSpace") },
-        { value: state.originalSpace - state.schoolUsedSpace - state.teacherUsedSpaceNum, name: i18n.t("teachermgmt.remainingSpace") }
-      ]
-      state.maxFixedAssignedValue = state.originalSpace - state.schoolUsedSpace
-    },
-    updatePieNumData(state) {
-      state.pieNumData = [
-        { value: state.schoolUsedSpace, name: i18n.t("teachermgmt.usedSpace") },
-        { value: state.teacherUsedSpaceNum, name: i18n.t("teachermgmt.allocatedSpace") },
-        { value: state.originalSpace - state.schoolUsedSpace - state.teacherUsedSpaceNum, name: i18n.t("teachermgmt.remainingSpace") }
-      ]
-    }
-    //處理介面上的即時數據
-  },
-  actions: {
-    //初始化空間
-    getInitialSpace(context, params) {
-      let schoolCode = params.schoolCode
-      //console.log(params)
-      apiTools.spaceAuth.teacherSpace(schoolCode, 'baseSpace').then(
-        res => {
-          //console.log(res)
-          context.commit('setTeacherUsedSpaceNum', params.originalTeachers)
-          context.commit('setPieNumData', res)
-          context.commit('setIsLoading', false)
-        },
-        err => {
-          console.log(err)
-        }
-      )
-    },
-    //回收空間
-    resetAllSpace(context, schoolCode) {
-      apiTools.spaceAuth.teacherSpace(schoolCode, 'retract').then(
-        res => {
-          //console.log(res)
-          context.commit('setTeacherUsedSpaceZero')
-          context.commit('setTeacherSpaceUIDataZero')
-          context.commit('updatePieNumData')
-          context.commit('setIsLoading', false)
-          context.commit('setMsgNum', 1)
-        },
-        err => {
-          console.log(err)
-        }
-      )
-    },
-    //更新空間分配
-    setTeacherSpace(context, params) {
-      let schoolCode = params.schoolCode
-      let teachers = params.teachers
-      apiTools.spaceAuth.teacherSpace(schoolCode, 'upd', teachers).then(
-        res => {
-          //console.log(res)
-          context.commit('updateTeacherSpaceUIData', teachers)
-          context.commit('setTeacherUsedSpaceNum', context.state.teacherSpaceData)
-          context.commit('updatePieNumData')
-          context.commit('setIsLoading', false)
-          context.commit('setMsgNum', 2)
-          if (res.status == '1') {
-            context.commit('setMsgNum', 3)
-          }
-          if (res.status == '2') {
-            context.commit('setMsgNum', 4)
-          }
-        },
-        err => {
-          console.log(err)
-        }
-      )
-    }
-  }
-}

+ 74 - 318
TEAMModelOS/ClientApp/src/store/module/user.js

@@ -8,8 +8,7 @@ export default {
         schoolCode: undefined,         //HBCN 學校代碼 (現在先寫死)
         userCourses: [], //当前教师的所有个人课程及学校安排的课程
         userDetails: [],            // 使用者詳細資訊[]
-        schoolUserList: undefined,  //學校所有使用者
-        userList: undefined,        //從Core.ID取得的使用者
+        teachers: undefined, //学校老师
         schoolSettingAuthList: undefined,   //所有權限總列表
         userProfile: { // 老師個人設定黨
             defaultschool: undefined, // 老師預設的登入學校
@@ -37,117 +36,52 @@ export default {
             classinfo: undefined,
             courses: undefined
         },
-        authStatus: undefined, //(單數)老師權限總設定值
-        authStatusMulti: undefined, //(複數)老師權限總設定值
         curPeriod: undefined
     },
     getters: {
-        getSchoolUserAll: state => {
-            if (state.schoolUserList !== undefined) {
-                return state.schoolUserList
+        getTeacherAll: state => {
+            if (state.teachers !== undefined) {
+                return state.teachers
             } else {
                 return []
             }
         },
-        getSchoolUserJoined: state => {
-            if (state.schoolUserList !== undefined) {
-                return state.schoolUserList.filter(
+        getTeacherJoined: state => {
+            if (state.teachers !== undefined) {
+                return state.teachers.filter(
                     user => user.status == 'join'
                 )
             } else {
                 return []
             }
         },
-        getSchoolUserInvited: state => {
-            if (state.schoolUserList !== undefined) {
-                return state.schoolUserList.filter(
+        getTeacherInvited: state => {
+            if (state.teachers !== undefined) {
+                return state.teachers.filter(
                     user => user.status == 'invite'
                 )
             } else {
                 return []
             }
         },
-        getSchoolUserRequested: state => {
-            if (state.schoolUserList !== undefined) {
-                return state.schoolUserList.filter(
+        getTeacherRequested: state => {
+            if (state.teachers !== undefined) {
+                return state.teachers.filter(
                     user => user.status == 'request'
                 )
             } else {
                 return []
             }
         },
-        getSchoolUserRequestedCount: state => {
-            if (state.schoolUserList !== undefined) {
-                return state.schoolUserList.filter(
-                    user => user.status == 'request'
-                ).length
-            } else {
-                return 0
-            }
-        },
-        getSchoolUserInvitedOrRequested: state => {
-            if (state.schoolUserList !== undefined) {
-                return state.schoolUserList.filter(
+        getTeacherInvitedOrRequested: state => {
+            if (state.teachers !== undefined) {
+                return state.teachers.filter(
                     user => user.status == 'invite' || user.status == 'request'
                 )
             } else {
                 return []
             }
         },
-        getSchoolUserByID: state => ID => {
-            if (state.schoolUserList !== undefined) {
-                return state.schoolUserList.filter(
-                    user => user.id === ID
-                )
-            } else {
-                return []
-            }
-        },
-        getschoolSettingAuthList: state => {
-            let result = new Object();
-            let authListFormed = new Object();
-            let authDisable = new Object();
-            let authIdToPath = new Object();
-
-            if (state.schoolSettingAuthList !== undefined) {
-                //整形 
-                state.schoolSettingAuthList.forEach(function (item) {
-                    //第一層 (read)
-                    if (typeof authListFormed[item.path] == 'undefined') {
-                        authListFormed[item.path] = new Object();
-                        authDisable[item.path] = true;
-                    }
-                    if (item.root) {
-                        authListFormed[item.path]['rowKey'] = item.rowKey;
-                        authListFormed[item.path]['mode'] = item.mode;
-                        authListFormed[item.path]['category'] = item.category;
-                        authIdToPath[item.rowKey] = item.path;
-                    }
-                    //第二層 (非read)
-                    else {
-                        if (typeof authListFormed[item.path]['subitem'] == 'undefined') {
-                            authListFormed[item.path]['subitem'] = new Object();
-                        }
-                        if (typeof authListFormed[item.path]['subitem'][item.rowKey] == 'undefined') {
-                            authListFormed[item.path]['subitem'][item.rowKey] = new Object();
-                        }
-                        authListFormed[item.path]['subitem'][item.rowKey]['rowKey'] = item.rowKey;
-                        authListFormed[item.path]['subitem'][item.rowKey]['mode'] = item.mode;
-                        authListFormed[item.path]['subitem'][item.rowKey]['category'] = item.category;
-                    }
-                });
-            }
-            result.authListFormed = authListFormed;
-            result.authDisable = authDisable;
-            result.authIdToPath = authIdToPath;
-            return result
-        },
-        getTeacherAuthStatus: state => {
-            return state.authStatus
-        },
-        getTeacherAuthStatusMulti: state => {
-            return state.authStatusMulti
-        },
         getLoginSchooCode: state => state.schoolCode,
         getPeriods: state => {
             return state.schoolProfile.periods
@@ -159,7 +93,6 @@ export default {
             return state.schoolProfile.school_classes
         },
         getRooms: state => {
-            console.log('获取数据', state)
             return state.schoolProfile.school_rooms
         },
         getSchoolBase: state => {
@@ -174,11 +107,9 @@ export default {
         },
         //更新userProfile schools
         setSchoolsInfo(state, data) {
-            console.log('111', state, data)
             let schoolCode = data.school_base.id
             let schoolName = data.school_base.name
             let schoolPicture = data.school_base.picture
-            //更新vuex
             if (schoolCode && state.userProfile && state.userProfile.schools) {
                 let schoolInfo = state.userProfile.schools.find(item => {
                     return item.schoolId == schoolCode
@@ -202,9 +133,6 @@ export default {
                 }
             }
         },
-        setSchoolUserList(state, data) {
-            state.schoolUserList = data
-        },
         setUserCourses(state, data) {
             state.userCourses = data
         },
@@ -222,13 +150,6 @@ export default {
             //更新vuex
             state.schoolProfile.school_base = data
         },
-
-        setUserList(state, data) {
-            state.userList = data
-        },
-        resetSchoolUserList(state) {
-            state.schoolUserList = undefined
-        },
         resetSchoolProfile(state) {
             state.schoolCode = undefined
             state.schoolProfile.blob_sas = undefined // 老師在學校的Blob金鑰,讀寫
@@ -243,9 +164,6 @@ export default {
             state.schoolProfile.svcStatus = undefined //学校购买服务模组状态
             state.schoolProfile.productSum = undefined //学校购买服务模组信息
         },
-        setSchoolSettingAuthList(state, data) {
-            state.schoolSettingAuthList = data
-        },
         setUserProfile(state, data) {
             state.userProfile.blob_sas = data.blob_sas // 老師Blob金鑰,讀寫
             state.userProfile.blob_uri = data.blob_uri // 老師Blob網址
@@ -279,12 +197,6 @@ export default {
             state.studentProfile.classinfo = data.classinfo // 學生在學校的的個人課程
             state.studentProfile.courses = data.courses // 學生在學校的的個人課綱
         },
-        setAuthStatus(state, data) {
-            state.authStatus = data;
-        },
-        setAuthStatusMulti(state, data) {
-            state.authStatusMulti = data;
-        },
         setSchoolCode(state, data) {
             state.schoolCode = data
         },
@@ -353,6 +265,41 @@ export default {
                 localStorage.setItem('school_profile', encodeURIComponent(JSON.stringify(schoolProfile), "utf-8"))
             }
         },
+        setTeachers(state, data) {
+            state.teachers = data
+        },
+        delTeacher(state, ids) {
+            if (ids && ids.length) {
+                let teachers = state.teachers
+                let count = teachers.length - 1 
+                for (let i = count; i >= 0; i--) {
+                    if (ids.includes(teachers[i].id)) {
+                        teachers.splice(i, 1)
+                    }
+                }
+                state.teachers = teachers
+            }
+        },
+        updTeacher(state, teachers) {
+            if (teachers && teachers.length) {
+                teachers.forEach((item) => {
+                    let index = state.teachers.findIndex(t => t.id == item.id)
+                    if (index > -1) {
+                        state.teachers.splice(index, 1, item)
+                    }
+                })
+            }
+        },
+        addTeacher(state, teachers) {
+            if (teachers && teachers.length) {
+                teachers.forEach((item) => {
+                    let index = state.teachers.findIndex(t => t.id == item.id)
+                    if (index == -1) {
+                        state.teachers.unshift(item)
+                    }
+                })
+            }
+        },
     },
     actions: {
         // 获取学校基本信息
@@ -382,21 +329,26 @@ export default {
                 }
             })
         },
-        // 從DB取得所有該校的使用者 && commit to state.schoolUserList
+        // 获取教师列表
         getSchoolTeacher(context) {
             return new Promise(
                 (resolve, reject) => {
-                    if (typeof context.state.schoolCode !== 'undefined' && context.state.schoolCode !== undefined) {
+                    if (!context.state.teachers) {
                         apiTools.schoolUser.getSchoolTeacherAll({
                             school_code: context.state.schoolCode
                         }).then(
                             res => {
-                                //放入storage
-                                if (res.hasOwnProperty('teachers') && res.teachers.length > 0) {
-                                    context.commit('setSchoolUserList', res.teachers)
+                                if (res.teachers) {
+                                    context.commit('setTeachers', res.teachers)
                                     resolve({
                                         code: 1,
-                                        message: 'Get School user successful'
+                                        data: res.teachers
+                                    })
+                                } else {
+                                    reject({
+                                        code: 0,
+                                        data: [],
+                                        message: 'Get School teacher API error!'
                                     })
                                 }
                             },
@@ -404,139 +356,19 @@ export default {
                                 reject({
                                     code: 0,
                                     data: [],
-                                    message: 'Get School user API error!'
+                                    message: 'Get School teacher API error!'
                                 })
                             }
                         )
                     } else {
-                        reject({
-                            code: 0,
-                            data: [],
-                            message: 'No valid school code.'
+                        resolve({
+                            code: 1,
+                            data: context.state.teachers
                         })
                     }
                 }
             )
         },
-
-        // 設定使用者權限
-        setSchoolUserPermission(context, params) {
-            return new Promise(
-                (resolve, reject) => {
-                    let schoolCode = context.state.schoolCode
-                    let ids = params.ids
-                    if (typeof schoolCode !== 'undefined' && schoolCode !== undefined && typeof ids !== 'undefined' && ids !== undefined) {
-                        apiTools.schoolUser.updPermissionByIds({
-                            school_code: schoolCode,
-                            ids: params.ids,
-                            pmAdd: params.pmAdd,
-                            pmRmv: params.pmRmv,
-                            job: params.job,
-                            mode: params.mode
-                        }).then(
-                            res => {
-                                resolve({
-                                    code: 1,
-                                    message: 'Set permission successfully.'
-                                })
-                            },
-                            err => {
-                                reject({
-                                    code: 0,
-                                    data: [],
-                                    message: 'Set authority API error!'
-                                })
-                            }
-                        )
-                    } else {
-                        reject({
-                            code: 0,
-                            data: [],
-                            message: 'No valid school code or TEAMModelIds.'
-                        })
-                    }
-                }
-            )
-        },
-
-        // 更新使用者資訊 輸入項:要更新的使用者資訊(array[object])
-        updSchoolUserByList(context, params) {
-            let schoolUserListNow = context.state.schoolUserList
-            let schoolUserListUpd = params
-            if (schoolUserListUpd.length > 0 && schoolUserListNow.length > 0) {
-                schoolUserListUpd.forEach(function (userUpd) {
-                    schoolUserListNow.forEach(function (userNow, indexNow) {
-                        if (userUpd.id === userNow.id) {
-                            schoolUserListNow[indexNow] = userUpd
-                        }
-                    })
-                })
-            }
-            context.commit('setSchoolUserList', schoolUserListNow)
-        },
-        // 更新單一使用者資訊
-        updSchoolUserInfo(context, params) {
-            let id = params.id;
-            let param = params.param;
-            let schoolUserListNow = context.state.schoolUserList
-            if (schoolUserListNow.length > 0) {
-                schoolUserListNow.forEach(userinfo => {
-                    if (userinfo.id == id) {
-                        for (var prop in param) {
-                            if (typeof userinfo[prop] !== 'undefined') {
-                                userinfo[prop] = param[prop];
-                            }
-                        }
-                    }
-                });
-            }
-            context.commit('setSchoolUserList', schoolUserListNow)
-        },
-
-        // 將使用者從學校使用者列表中移除
-        rmvFromSchoolUserByID(context, params) {
-            return new Promise(
-                (resolve, reject) => {
-                    let school_code = context.state.schoolCode
-                    let schoolUserListNow = context.state.schoolUserList
-                    let rmvId = params.id
-                    apiTools.schoolUser.rmvSchoolUser({
-                        school_code: school_code,
-                        id: rmvId
-                    }).then(
-                        res => {
-                            // 更新 state.schoolUserList
-                            let i = 0
-                            while (i < schoolUserListNow.length) {
-                                if (schoolUserListNow[i].id == rmvId) {
-                                    schoolUserListNow.splice(i, 1)
-                                } else {
-                                    ++i
-                                }
-                            }
-                            context.commit('setSchoolUserList', schoolUserListNow)
-                            resolve({
-                                code: 1,
-                                message: 'Remove user successfully.'
-                            })
-                        },
-                        err => {
-                            reject({
-                                code: 0,
-                                data: [],
-                                message: 'Remove user API error!'
-                            })
-                        }
-                    )
-                }
-            )
-        },
-
-        // 清空 state.schoolUserList
-        resetSchoolUser(context) {
-            context.commit('resetSchoolUserList')
-        },
-
         // 變更使用者加入狀態
         updSchoolUserStatus(context, params) {
             return new Promise(
@@ -571,75 +403,9 @@ export default {
             )
         },
 
-        // 1.取得學校設定權限列表 2.設定老師權限值
-        getSchoolAuthorityList(context) {
-            return new Promise(
-                (resolve, reject) => {
-                    apiTools.schoolUser.getSchoolAuthorityList().then(
-                        res => {
-                            // 暂时去掉四类(课纲、内容、题库、知识点)校本资源的读取权限,老师加入学校默认会添加这四个权限
-                            let auth = ['content-read', 'exercise-read', 'knowledge-read', 'syllabus-read']
-                            for (let i = 0; i < res.authoritylist.length; i++) {
-                                if (auth.includes(res.authoritylist[i].rowKey)) {
-                                    res.authoritylist.splice(i, 1)
-                                    --i
-                                }
-                            }
-
 
-                            //設定權限總列表
-                            context.commit('setSchoolSettingAuthList', res.authoritylist)
-                            //設定老師權限值
-                            let authStatus = {} //單數
-                            let authStatusMulti = { //複數
-                                'on': {},
-                                'off': {}
-                            }
-                            if (res.authoritylist.length > 0) {
-                                res.authoritylist.forEach(function (item) {
-                                    //單數
-                                    authStatus[item.rowKey] = false
-                                    //複數
-                                    authStatusMulti['on'][item.rowKey] = '0'
-                                    authStatusMulti['off'][item.rowKey] = '0'
-                                });
-                            }
-                            context.commit('setAuthStatus', authStatus)
-                            context.commit('setAuthStatusMulti', authStatusMulti)
-                            //回傳值
-                            resolve({
-                                code: 1,
-                                message: 'Get school authority list successfully.'
-                            })
-                        },
-                        err => {
-                            reject({
-                                code: 0,
-                                data: [],
-                                message: 'Get school authority list API error!'
-                            })
-                        }
-                    )
-                }
-            )
-        },
-        // 重設(複數)老師權限值
-        resetAuthStatusMulti(context) {
-            let authStatusMultiNow = context.state.authStatusMulti;
-            let authStatusMulti = {
-                'on': {},
-                'off': {}
-            }
-            for (var key in authStatusMultiNow['on']) {
-                authStatusMulti['on'][key] = '0';
-            }
-            for (var key in authStatusMultiNow['off']) {
-                authStatusMulti['off'][key] = '0';
-            }
-            context.commit('setAuthStatusMulti', authStatusMulti)
-        },
         //追加老師為「邀請」者至資料庫後,追加至state.schoolUserList
-        addSchoolUserToInvite(context, params) {
+        addTeacherToInvite(context, params) {
             return new Promise(
                 (resolve, reject) => {
                     let schoolCode = context.state.schoolCode
@@ -658,7 +424,11 @@ export default {
                                     })
                                 } else {
                                     // 追加新使用者至 state.schoolUserList
-                                    context.dispatch('addSchoolUserToSchoolUserList', { user_list: params, grant_type: 'invite' })
+                                    // context.dispatch('addTeacherToSchoolUserList', { user_list: params, grant_type: 'invite' })
+                                    params.forEach(item=>{
+                                        item.createTime = Math.round((new Date()).getTime() / 1000)
+                                    })
+                                    context.commit('addTeacher', params)
                                     resolve({
                                         code: 1,
                                         message: 'Add user to school successfully.'
@@ -684,20 +454,6 @@ export default {
                 }
             )
         },
-        // 追加使用者資訊至前端學校使用者列表 輸入項:追加的使用者資訊(array[object])
-        addSchoolUserToSchoolUserList(context, params) {
-            let addUserlist = params.user_list
-            let status = params.grant_type
-            let schoolUserListNow = context.state.schoolUserList
-            if (addUserlist.length > 0) {
-                addUserlist.forEach(function (userAdd) {
-                    userAdd.status = status
-                    userAdd.createTime = Math.round((new Date()).getTime() / 1000)
-                    schoolUserListNow.push(userAdd)
-                })
-            }
-            context.commit('setSchoolUserList', schoolUserListNow)
-        },
         setUserProfile(context, data) {
             localStorage.setItem('user_profile', encodeURIComponent(JSON.stringify(data), "utf-8"))
             context.commit('setUserProfile', data)
@@ -751,10 +507,10 @@ export default {
             data.svcStatus = svcStatus
             context.commit('setSchoolProfile', data)
             let index = data.school_base.period.findIndex(item => item.id === context.state.curPeriod?.id)
-            if (index > -1){
+            if (index > -1) {
                 data.school_base.period[index].periodIndex = index
                 context.commit('setCurPeriod', data.school_base.period[index])
-            } 
+            }
             // 设置学校空间
             context.commit('setSchoolSpace', data.school_base.size, { root: true })
         },

+ 0 - 1
TEAMModelOS/ClientApp/src/utils/js-fn.js

@@ -302,7 +302,6 @@ function getYearByGrade(data, curPd, grade) {
  * ]
  */
 function getTeacherSubjects(ids) {
-    console.log(store)
     let schoolPeriod = store.state.user?.schoolProfile?.school_base?.period
     if (ids && ids.length && schoolPeriod) {
         let data = []

+ 5 - 6
TEAMModelOS/ClientApp/src/view/Home.vue

@@ -218,16 +218,16 @@ export default {
         },
         goHelpDoc() {
             if (localStorage.getItem('local') === 'zh-cn') {
-                window.open('http://cdhabook.teammodel.cn:4999/web/#/7/34')
+                window.open(this.$store.state.config.China.docUrl)
             } else if (localStorage.getItem('local') === 'zh-tw') {
-                window.open('http://cdhabook.teammodel.cn:4999/web/#/9/37')
+                window.open(this.$store.state.config.Global.docUrl)
             } else {
                 this.$Message.warning(this.$t('system.noSupport'))
             }
         },
         changePlatform() {
             let goPlatform = this.curPlatform === 'area' ? 'school' : 'area'
-            let homePath = this.$store.state.config.srvAdr == 'China' ? 'home' : 'myCourse'
+            let homePath = 'home'
             this.$router.push({
                 name: goPlatform === 'area' ? 'area' : homePath
             })
@@ -284,7 +284,7 @@ export default {
             })
         },
         toHome() {
-            let homePath = this.$store.state.config.srvAdr == 'China' ? 'home' : 'myCourse'
+            let homePath = 'home'
             this.$router.push({
                 name: homePath
             })
@@ -335,8 +335,7 @@ export default {
             return this.$store.state.user.userProfile.areas.length > 0
         },
         isHomeLight() {
-            return this.routerName == 'homePage' || (this.$store.state.config.srvAdr == 'Global' && this.routerName ==
-                'myCourse')
+            return this.routerName == 'homePage'
         },
         inJinNiu() {
             return window.location.host === 'jinniu.teammodel.cn'

+ 1 - 1
TEAMModelOS/ClientApp/src/view/ability/Ability.vue

@@ -510,7 +510,7 @@ export default {
   },
   computed: {
     ...mapGetters({
-      teachers: 'user/getSchoolUserJoined', // 取得已加入此學校的使用者
+      teachers: 'user/getTeacherJoined', // 取得已加入此學校的使用者
     }),
     hasAuth() {
       return row => {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/ability/GroupReview.vue

@@ -408,7 +408,7 @@ export default {
     },
     computed: {
         ...mapGetters({
-            teachers: 'user/getSchoolUserJoined', // 取得已加入此學校的使用者
+            teachers: 'user/getTeacherJoined', // 取得已加入此學校的使用者
         })
     },
 }

+ 6 - 3
TEAMModelOS/ClientApp/src/view/ability/Review.vue

@@ -20,7 +20,7 @@
         </span>
         <div class="task-item" v-for="(task,taskIndex) in std.task" :key="taskIndex">
           <div v-if="curTaskIndexArr[index] === taskIndex">
-            <p class="unit-item-des">{{ task.stddesc }}</p>
+            <p class="unit-item-des">{{ task.stddesc }}  <span style="color: red;font-weight: bold;">(需上传材料数量:{{ task.limit }})</span> </p>
             <!-- 上传按钮 -->
             <div class="task-upload">
               <Button type="info" icon="md-cloud-upload" class="upload-btn" @click="onUpload(std,index,task)" v-show="stdFileArr[index].length < task.limit && isSelfMode">{{ $t('ability.review.upload') }}</Button>
@@ -125,7 +125,7 @@
       <div class="modal-header" slot="header">
         <span>{{ $t('syllabus.upload') }}</span>
       </div>
-      <AbilityUpload v-if="uploadModal" singleUpload :auth="curSas" :acceptTypes="extLimit" :scope="'school'" mode="modal" :prefix="curPrefix" @uploadFinish="uploadFinish"></AbilityUpload>
+      <AbilityUpload v-if="uploadModal" :auth="curSas" :limit="taskCountLimit" :acceptTypes="extLimit" :scope="'school'" mode="modal" :prefix="curPrefix" @uploadFinish="uploadFinish"></AbilityUpload>
     </Modal>
   </div>
 </template>
@@ -146,6 +146,7 @@ export default {
   },
   data() {
     return {
+		taskCountLimit:1,
       areaSetting: null,
       extLimit: [],
       finalResult: 0,
@@ -273,6 +274,7 @@ export default {
           acceptTypes.push(...this.areaSetting[type])
         })
       }
+	  this.taskCountLimit = (task.limit - this.stdFileArr[index].length) || 1
       this.extLimit = acceptTypes
     },
     /* 上传结束回调 */
@@ -452,7 +454,8 @@ export default {
       this.curTaskIndexArr = abilityDetail.stds.map(i => 0)
       abilityDetail.uploads = this.reviewData.uploads
       if (this.mode !== 'self') {
-        this.stdFileArr = abilityDetail.stds.map(i => abilityDetail.uploads.find(j => j.stdid === i.id).urls)
+        this.stdFileArr = abilityDetail.stds.map(i => abilityDetail.uploads.find(j => j.stdid === i.id) ? abilityDetail.uploads.find(j => j.stdid === i.id).urls : [])
+        // this.stdFileArr = abilityDetail.uploads.filter(i => abilityDetail.stds.map(j => j.id).includes(i.stdid)).map(k => k.urls)
         abilityDetail.targetId = this.reviewData.targetId
         abilityDetail.targetName = this.reviewData.targetName
       }

+ 1 - 1
TEAMModelOS/ClientApp/src/view/areaMgmt/AreaBase.vue

@@ -94,7 +94,7 @@ export default {
         },
 		changePlatform(){
 			let goPlatform = this.curPlatform === 'area' ? 'school' : 'area'
-            let homePath = this.$store.state.config.srvAdr == 'China' ? 'home' : 'myCourse'
+            let homePath = 'home'
 			this.$router.push({
 			    name: goPlatform === 'area' ? 'area' : homePath
 			})

+ 1 - 1
TEAMModelOS/ClientApp/src/view/areatrain/Create.vue

@@ -451,7 +451,7 @@ export default {
     },
     computed: {
         ...mapGetters({
-            teachers: 'user/getSchoolUserJoined', // 取得已加入此學校的使用者
+            teachers: 'user/getTeacherJoined', // 取得已加入此學校的使用者
         })
     },
     methods: {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/forgotPw/Index.vue

@@ -286,7 +286,7 @@ export default {
                                         //設定權限並登入
                                         User.login(result).then(res => {
                                             if (res) {
-                                                let homePath = this.$store.state.config.srvAdr == 'China' ? 'home' : 'myCourse'
+                                                let homePath = 'home'
                                                 this.$router.push({ name: homePath })
                                             }
                                         })

+ 9 - 9
TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue

@@ -56,38 +56,38 @@
                         <!-- 课程班级名单统计 -->
                         <div class="cus-count-wrap" style="margin-top:25px">
                             <div class="cus-count-item cus-count-item-bg1">
-                                <p class="tag-label">学校课程</p>
+                                <p class="tag-label">{{$t('home.count1')}}</p>
                                 <countTo :startVal='0' :endVal='countData.schoolCourseCount  || 0' :duration='1500' class="count-num"></countTo>
                             </div>
                             <div class="cus-count-item cus-count-item-bg1">
-                                <p class="tag-label">任教班级</p>
+                                <p class="tag-label">{{$t('home.count2')}}</p>
                                 <countTo :startVal='0' :endVal='countData.classIdsCount   || 0' :duration='1500' class="count-num"></countTo>
                             </div>
                             <div class="cus-count-item cus-count-item-bg1">
-                                <p class="tag-label">个人课程</p>
+                                <p class="tag-label">{{$t('home.count3')}}</p>
                                 <countTo :startVal='0' :endVal='countData.privateCourseCount   || 0' :duration='1500' class="count-num"></countTo>
                             </div>
                             <div class="cus-count-item cus-count-item-bg1">
-                                <p class="tag-label">个人名单</p>
+                                <p class="tag-label">{{$t('home.count4')}}</p>
                                 <countTo :startVal='0' :endVal='countData.stulistsCount   || 0' :duration='1500' class="count-num"></countTo>
                             </div>
                         </div>
                         <!-- 资源统计 -->
                         <div class="cus-count-wrap" style="margin-top:25px">
                             <div class="cus-count-item cus-count-item-bg2">
-                                <p class="tag-label">课纲数量</p>
+                                <p class="tag-label">{{$t('home.count5')}}</p>
                                 <countTo :startVal='0' :endVal='countData.privateSyllabusCount  || 0' :duration='1500' class="count-num"></countTo>
                             </div>
                             <div class="cus-count-item cus-count-item-bg2">
-                                <p class="tag-label">试卷数量</p>
+                                <p class="tag-label">{{$t('home.count6')}}</p>
                                 <countTo :startVal='0' :endVal='countData.privatePaperCount   || 0' :duration='1500' class="count-num"></countTo>
                             </div>
                             <div class="cus-count-item cus-count-item-bg2">
-                                <p class="tag-label">题目数量</p>
+                                <p class="tag-label">{{$t('home.count7')}}</p>
                                 <countTo :startVal='0' :endVal='countData.privateItemCount  || 0' :duration='1500' class="count-num"></countTo>
                             </div>
                             <div class="cus-count-item cus-count-item-bg2">
-                                <p class="tag-label">资源数量</p>
+                                <p class="tag-label">{{$t('home.count8')}}</p>
                                 <countTo :startVal='0' :endVal='countData.privateBloblogCount  || 0' :duration='1500' class="count-num"></countTo>
                             </div>
                         </div>
@@ -103,7 +103,7 @@
                         </div>
                     </div>
                     <!-- 研修数据 && 活动统计-->
-                    <div style="display: flex;">
+                    <div style="display: flex;" v-show="$store.state.config.srvAdr == 'China'">
                         <!-- 研修数据 -->
                         <!-- <div class="train-chart-box" :style="{width:!checkHost() ? '100%' : 'calc(70% - 15px)',marginRight:!checkHost() ? '0px' : '15px'}" v-show="$store.state.config.srvAdr == 'China'"> -->
                         <div class="train-chart-box" style="width:100%;margin-right:0px" v-show="$store.state.config.srvAdr == 'China'">

+ 6 - 2
TEAMModelOS/ClientApp/src/view/jyzx/application.vue

@@ -166,8 +166,12 @@ export default {
         width: 100
       },
       {
-        title: this.$t('jyzx.application.testByMe'),
         slot: "exerciseScore",
+		renderHeader: (h, params) => {
+			return h('div', [
+				h('strong', this.$t('jyzx.application.testByMe') + '(不计入学时)' ),
+			])
+		}
       },
       {
         title: this.$t('jyzx.common.action'),
@@ -327,7 +331,7 @@ export default {
         this.tableLoading = true
         this.getMyAbilities()
       }
-      // 如果是从互评返回
+      // 如果是从互评返回,则不视为第一次评价
       if(params.isFromOtherAppraise){
         this.isFirstAppraiseOther = false
       }

+ 1 - 1
TEAMModelOS/ClientApp/src/view/jyzx/index.vue

@@ -100,7 +100,7 @@
                                             </p>
                                             <div>
                                                 <video v-if="item.type === 'video'" :id="'video' + index" :src="item.formalUrl" controls="controls" style="border-radius: 5px;max-height: 700px;max-width: 100%;"
-                                                    :currentTime="currentTime" controlslist="noplaybackrate"
+                                                    :currentTime="currentTime" controlslist="noplaybackrate nodownload"
                                                     @pause="sendTime" @abort="pointList[activePointIndex].currency === 1 ? sendTime : ''" @playing="pointList[activePointIndex].currency === 1 ? startTime(item, index) : ''"
                                                     @timeupdate="timeChange" @ended="endStudy"
                                                 />

+ 1 - 1
TEAMModelOS/ClientApp/src/view/jyzx/offline.vue

@@ -1111,7 +1111,7 @@ export default {
 
     computed: {
         ...mapGetters({
-            teachers: 'user/getSchoolUserJoined', // 取得已加入此學校的使用者
+            teachers: 'user/getTeacherJoined', // 取得已加入此學校的使用者
         }),
         noActivity() {
             return this.resource.settings.length === 1 && this.resource.settings.includes("sign")

+ 19 - 14
TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.less

@@ -58,10 +58,6 @@
                     color: var(--assist-color-light);
                 }
             }
-
-            .evaluation-type span {
-                margin-right: 10px;
-            }
         }
     }
 }
@@ -75,19 +71,33 @@
     font-size: 15px;
     color: #2d8cf0 !important;
 }
+.tags-wrap{
+    display: flex;
+    flex-wrap: wrap;
+    margin-top: 6px;
+    border: 1px solid #d2d2d2;
+    width: fit-content;
+    border-radius: 3px;
+    overflow: hidden;
+}
 .ev-info-tag{
     color: #2d8cf0;
-    border: 1px solid #2d8cf0;
+    
 }
 .ev-tag-common{
-    border-radius: 2px;
-    padding: 1px 2px;
+    padding: 1px 6px;
     white-space: nowrap;
     font-size:12px;
-    margin-right: 4px;
+    border-right: 1px solid #d2d2d2;
+    &:last-child{
+        border: none;
+    }
+    &:first-child{
+        background: #b1b1b1;
+        color: white !important;
+    }
 }
 .evaluation-status-tag {
-    border: 1px solid #1CC0F3;
     white-space: nowrap;
 }
 .handle-end-tag{
@@ -153,8 +163,3 @@
     // padding-left: 10px;
     background: #f6f6f6;
 }
-.tags-wrap{
-    display: flex;
-    flex-wrap: wrap;
-    margin-top: 6px;
-}

+ 15 - 19
TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.vue

@@ -53,26 +53,16 @@
                                 <!-- 修改评测名称 -->
                                 <Icon type="md-create" class="edit-end-time" @click="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
                             </p>
-                            <p class="evaluation-type">
-                                <Icon type="md-time" style="margin-right:5px;" size="16" />
-                                <span>{{$t('learnActivity.mgtScEv.createTime')}}{{$jsFn.timeFormat(item.startTime)}}</span>
-                            </p>
-                            <p class="evaluation-type">
-                                <Icon type="md-time" style="margin-right:5px;" size="16" />
-                                <span>{{$t('learnActivity.mgtScEv.endTime')}}{{$jsFn.timeFormat(item.endTime)}}</span>
-                                <!-- 修改评测结束时间 -->
-                                <Icon type="md-create" class="edit-end-time" v-if="item.progress == 'going'" @click="editEvEndtime(index)" :title="$t('learnActivity.mgtScEv.editEndTime')" />
-                            </p>
                             <div class="tags-wrap">
-                                <!-- 评测模式 -->
-                                <span class="ev-info-tag ev-tag-common">{{getModeLabel(item.source)}}</span>
-                                <span class="ev-info-tag ev-tag-common">{{getTypeLabel(item.type)}}</span>
                                 <!-- 活动进度状态 -->
-                                <span class="evaluation-status-tag ev-tag-common" :style="{ borderColor: item.progColor, color: item.progColor}">
+                                <span class="evaluation-status-tag ev-tag-common" :style="{ background:item.progColor, color: item.progColor}">
                                     {{ item.progText }}
                                 </span>
+                                <!-- 评测模式 -->
+                                <span class="ev-info-tag ev-tag-common">{{getModeLabel(item.source)}}</span>
+                                <span class="ev-info-tag ev-tag-common">{{getTypeLabel(item.type)}}</span>
                                 <!-- 活动评分状态 -->
-                                <span class="evaluation-status-tag ev-tag-common" :style="{ borderColor: item.scoreColor, color: item.scoreColor}">
+                                <span class="evaluation-status-tag ev-tag-common" :style="{ color: item.scoreColor}">
                                     {{ item.scoreText }}
                                 </span>
                                 <!-- 立即结束 -->
@@ -80,6 +70,14 @@
                                     {{$t('learnActivity.mgtScEv.stop')}}
                                 </span>
                             </div>
+                            <p class="evaluation-type" style="margin-top:10px">
+                                <Icon type="md-time" style="margin-right:5px;" size="16" />
+                                <span>{{$jsFn.timeFormat(item.startTime)}}</span>
+                                -
+                                <span>{{$jsFn.timeFormat(item.endTime)}}</span>
+                                 <!-- 修改评测结束时间 -->
+                                <Icon type="md-create" class="edit-end-time" v-if="item.progress == 'going'" @click="editEvEndtime(index)" :title="$t('learnActivity.mgtScEv.editEndTime')" />
+                            </p>
                             <!-- 二维码分享 -->
                             <span class="ev-qr-tag" @click="openQrcode(index)" v-show="item.source != '1' && item.progress == 'going'">
                                 <Icon size="25" custom="iconfont icon-qr-code" class="qr-code-icon" />
@@ -208,8 +206,6 @@ export default {
         },
     },
     created() {
-        console.log(this.$router)
-        console.log(this.$route)
         if (this.$route.name === 'schoolExam') {
             this.scope = 'school'
         } else {
@@ -401,10 +397,10 @@ export default {
                 info.progColor = '#2d8cf0'
             } else if (progress == 'going') {
                 info.progText = this.$t('learnActivity.mgtScEv.going')
-                info.progColor = '#19be6b'
+                info.progColor = '#2d8cf0'
             } else if (progress == 'finish') {
                 info.progText = this.$t('learnActivity.mgtScEv.finish')
-                info.progColor = '#515a6e'
+                info.progColor = '#75787d'
             }
             if (isScore === 0) {
                 info.scoreText = this.$t('learnActivity.mgtScEv.scoreStatus')

+ 10 - 60
TEAMModelOS/ClientApp/src/view/learnactivity/echarts/CognitineLevel.vue

@@ -12,55 +12,8 @@ export default {
             type: Object,
             default: () => {
                 return {
-
-                    "fs": [
-
-                        1,
-
-                        2,
-
-                        3,
-
-                        4,
-
-                        5,
-
-                        6
-
-                    ],
-
-                    "fps": [
-
-                        0.82,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        0
-
-                    ],
-
-                    "cfps": [
-
-                        0.4117647058823529,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0
-
-                    ]
-
+                    "fs": [],
+                    "afps": []
                 }
             }
         }
@@ -94,8 +47,7 @@ export default {
                     max: 1
                 }
             ],
-            cfps: [], //班级
-            fps: [], //个人
+            afps: [], //所有
         }
     },
     created() {
@@ -130,12 +82,12 @@ export default {
                 },
                 series: [
                     {
-                        name: 'Budget vs spending',
+                        name:'',
                         type: 'radar',
                         data: [
                             {
-                                value: this.cfps,
-                                name: this.$t("studentWeb.exam.chart.participantClass")
+                                value: this.afps,
+                                name: ''
                             }
                         ]
                     }
@@ -144,16 +96,13 @@ export default {
             myChart.setOption(option)
         },
         getFiled() {
-            let fps = []
-            let cfps = []
+            let afps = []
             if (this.filed.fs) {
                 this.filed.fs.map((item, index) => {
-                    fps.push(this.filed.fps[index] ? this.filed.fps[index].toFixed(2) : 0)
-                    cfps.push(this.filed.cfps[index] ? this.filed.cfps[index].toFixed(2) : 0)
+                    afps.push(this.filed.afps[index] ? this.filed.afps[index].toFixed(2) : 0)
                 })
             }
-            this.fps = fps
-            this.cfps = cfps
+            this.afps = afps
         },
     },
     mounted() {
@@ -163,6 +112,7 @@ export default {
     watch: {
         filed: {
             handler(n, o) {
+                console.log('认知层次数据:', n)
                 if (n.fs) {
                     this.$nextTick(() => {
                         this.getFiled()

+ 7 - 164
TEAMModelOS/ClientApp/src/view/learnactivity/echarts/KngPoint.vue

@@ -12,157 +12,8 @@ export default {
             type: Object,
             default: () => {
                 return {
-
-                    "kn": [
-
-                        "汉字读音",
-
-                        "汉字书写",
-
-                        "成语运用",
-
-                        "病句",
-
-                        "名著阅读",
-
-                        "文言实词用法",
-
-                        "文言虚词用法",
-
-                        "课内文言文内容理解及写法分析",
-
-                        "划分朗读停顿",
-
-                        "课外文言文内容分析",
-
-                        "诗歌内容主旨的理解",
-
-                        "课外文言文句意感知",
-
-                        "诗歌景物描写的赏析",
-
-                        "重点诗文名句的准确记忆",
-
-                        "说明文信息筛选",
-
-                        "说明文内容分析",
-
-                        "说明方法的分析",
-
-                        "说明文语言赏析",
-
-                        "散文情节的梳理",
-
-                        "人物形象评价",
-
-                        "散文语言赏析",
-
-                        "散文主旨的理解",
-
-                        "表达能力的评价考察"
-
-                    ],
-
-                    "kps": [
-
-                        0,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1,
-
-                        1
-
-                    ],
-
-                    "ckps": [
-
-                        0,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5,
-
-                        0.5
-
-                    ]
-
+                    "kn": [],
+                    "akps": []
                 }
             }
         }
@@ -171,8 +22,7 @@ export default {
         return {
             id: '',
             categories: [],
-            ckps: [], //班级
-            kps: [], //个人
+            akps: [], //个人
         }
     },
     created() {
@@ -212,11 +62,7 @@ export default {
                         type: 'radar',
                         data: [
                             {
-                                value: this.kps,
-                                name: this.$t("studentWeb.exam.chart.me")
-                            },
-                            {
-                                value: this.ckps,
+                                value: this.akps,
                                 name: this.$t("studentWeb.exam.chart.participantClass")
                             }
                         ]
@@ -226,16 +72,13 @@ export default {
             myChart.setOption(option)
         },
         getFiled() {
-            let kps = []
-            let ckps = []
+            let akps = []
             if (this.knowledge.kn) {
                 this.knowledge.kn.map((item, index) => {
-                    kps.push(this.knowledge.kps[index] ? this.knowledge.kps[index].toFixed(2) : 0)
-                    ckps.push(this.knowledge.ckps[index] ? this.knowledge.ckps[index].toFixed(2) : 0)
+                    akps.push(this.knowledge.akps[index] ? this.knowledge.akps[index].toFixed(2) : 0)
                 })
             }
-            this.kps = kps
-            this.ckps = ckps
+            this.akps = akps
         },
     },
     mounted() {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkSetting.vue

@@ -938,7 +938,7 @@ export default {
     },
     computed: {
         ...mapGetters({
-            teacherList: 'user/getSchoolUserJoined', // 取得已加入此學校的使用者
+            teacherList: 'user/getTeacherJoined', // 取得已加入此學校的使用者
         }),
         //当前科目按题分配数据
         quBlockData() {

+ 35 - 5
TEAMModelOS/ClientApp/src/view/learnactivity/tabs/DataView.vue

@@ -59,7 +59,7 @@
                     </p>
                 </div>
             </div>
-            
+
             <!-- 单科或多科都会呈现 -->
             <div class="chart-wrap">
                 <p class="subject-name" v-show="examInfo.subjects && examInfo.subjects.length > 1">总览</p>
@@ -81,11 +81,11 @@
                 </div>
                 <!-- 认知层次分布图 -->
                 <div class="score-dist-box" v-show="examInfo.subjects && examInfo.subjects.length == 1">
-                    <CognitineLevel></CognitineLevel>
+                    <CognitineLevel :filed="levelData[0]"></CognitineLevel>
                 </div>
                 <!-- 知识点统计图 -->
                 <div class="score-dist-box" v-show="examInfo.subjects && examInfo.subjects.length == 1">
-                    <KngPoint></KngPoint>
+                    <KngPoint :knowledge="knData[0]"></KngPoint>
                 </div>
                 <!-- 占位符 -->
                 <!-- <div class="score-dist-box" v-show="examInfo.subjects && examInfo.subjects.length == 1" style="opacity: 0;">
@@ -103,11 +103,11 @@
                         </div>
                         <!-- 认知层次分布图 -->
                         <div class="score-dist-box">
-                            <CognitineLevel></CognitineLevel>
+                            <CognitineLevel :filed="levelData[index]"></CognitineLevel>
                         </div>
                         <!-- 知识点统计图 -->
                         <div class="score-dist-box">
-                            <KngPoint></KngPoint>
+                            <KngPoint :knowledge="knData[index]"></KngPoint>
                         </div>
                     </div>
                 </div>
@@ -234,6 +234,36 @@ export default {
             } else {
                 return []
             }
+        },
+        //认知层次统计数据
+        levelData() {
+            if (this.simpleData && this.simpleData.averageTotal) {
+                let data = this.simpleData.averageTotal.map((subItem, i) => {
+                    return {
+                        subjectId: subItem.subjectId,
+                        fs: subItem.fs,
+                        afps: subItem.afp
+                    }
+                })
+                return data
+            } else {
+                return []
+            }
+        },
+        //知识点数据
+        knData() {
+            if (this.simpleData && this.simpleData.averageTotal) {
+                let data = this.simpleData.averageTotal.map((subItem, i) => {
+                    return {
+                        subjectId: subItem.subjectId,
+                        kn: subItem.kn,
+                        akps: subItem.akp
+                    }
+                })
+                return data
+            } else {
+                return []
+            }
         }
     },
     methods: {

+ 3 - 3
TEAMModelOS/ClientApp/src/view/login/Index.vue

@@ -490,7 +490,7 @@ export default {
 					} else {
 						// 前往校级平台 判断是否有记录的目标地址 如果没有则按照站点来进行对应跳转固定页面
 						let targetPath = localStorage.getItem('target_path')
-						let defaultPath = this.$store.state.config.srvAdr == 'China' ? '/home' : '/home/myCourse'
+						let defaultPath = '/home'
 					    let homePath = targetPath ? (targetPath.includes('home/') ? targetPath : defaultPath) : defaultPath
 					    localStorage.setItem('platform', 'school')
 						localStorage.setItem('target_path','')
@@ -512,7 +512,7 @@ export default {
         },
         goWhere: function (identity) {
             sessionStorage.setItem('identity', identity)
-            let homePath = this.$store.state.config.srvAdr == 'China' ? 'home' : 'myCourse'
+            let homePath = 'home'
             let path = identity == 'student' ? 'studentWeb' : homePath
             this.$router.push({ name: path })
         },
@@ -534,7 +534,7 @@ export default {
 					} else {
 						// 前往校级平台 判断是否有记录的目标地址 如果没有则按照站点来进行对应跳转固定页面
 						let targetPath = localStorage.getItem('target_path')
-						let defaultPath = this.$store.state.config.srvAdr == 'China' ? '/home' : '/home/myCourse'
+						let defaultPath = '/home'
 					    let homePath = targetPath ? (targetPath.includes('home/') ? targetPath : defaultPath) : defaultPath
 					    localStorage.setItem('platform', 'school')
 						localStorage.setItem('target_path','')

+ 3 - 27
TEAMModelOS/ClientApp/src/view/login/page/Teacher.vue

@@ -334,7 +334,7 @@ export default {
 							} else {
 								// 前往校级平台 判断是否有记录的目标地址 如果没有则按照站点来进行对应跳转固定页面
 								let targetPath = localStorage.getItem('target_path')
-								let defaultPath = this.$store.state.config.srvAdr == 'China' ? '/home' : '/home/myCourse'
+								let defaultPath = '/home'
 							    let homePath = targetPath ? (targetPath.includes('home/') ? targetPath : defaultPath) : defaultPath
 							    localStorage.setItem('platform', 'school')
 								localStorage.setItem('target_path','')
@@ -345,37 +345,13 @@ export default {
                 }
             })
         },
-        // bandingID(idToken, result) {
-        //     this.$api.train.thirdSSO(this.routerData.bindurl, {
-        //         type: this.routerData.type,
-        //         param: this.routerData.param,
-        //         id_token: idToken
-        //     }).then(
-        //         res => {
-        //             //绑定成功
-        //             if (res && res.status == 200) {
-        //                 this.$Message.success("绑定成功")
-        //                 this.loginProcess(result, this.defaultSchool.code)
-        //             } else {
-        //                 this.$Message.error("绑定失败")
-        //             }
-        //         },
-        //         err => {
-
-        //         }
-        //     )
-        // },
         oauthLogin: function (provider) { // 第三方登入
             let isDev = this.$store.state.config.srvAdrType != 'product'
             if (provider === 'dingding' && !isDev) {
                 this.$Message.warning(this.$t('login.dingCloseTip'))
                 return
             }
-			// let targetPath = localStorage.getItem('target_path')
-			// let defaultPath = '/login'
-			// let homePath = targetPath ? (targetPath === '/login' ? defaultPath : targetPath) : defaultPath
             let redirect_uri = window.location.origin + '/login';
-            // console.log(redirect_uri);
             this.$api.BuildOauthUrl(provider, redirect_uri).then(res => {
                 console.log('三方登录', res)
                 window.location.href = res
@@ -461,7 +437,7 @@ export default {
                         this.$router.push({ path: '/area' })
                     } else {
 						let targetPath = localStorage.getItem('target_path')
-						let defaultPath = this.$store.state.config.srvAdr == 'China' ? '/home' : '/home/myCourse'
+						let defaultPath = '/home'
                         let homePath = targetPath ? (targetPath.includes('home/') ? targetPath : defaultPath) : defaultPath
                         localStorage.setItem('platform', 'school')
 						localStorage.setItem('target_path','')
@@ -495,7 +471,7 @@ export default {
 						} else {
 							// 前往校级平台 判断是否有记录的目标地址 如果没有则按照站点来进行对应跳转固定页面
 							let targetPath = localStorage.getItem('target_path')
-							let defaultPath = this.$store.state.config.srvAdr == 'China' ? '/home' : '/home/myCourse'
+							let defaultPath = '/home'
 						    let homePath = targetPath ? (targetPath.includes('home/') ? targetPath : defaultPath) : defaultPath
 						    localStorage.setItem('platform', 'school')
 							localStorage.setItem('target_path','')

+ 1 - 1
TEAMModelOS/ClientApp/src/view/newcourse/NewCusMgt.vue

@@ -1263,7 +1263,7 @@ export default {
     },
     computed: {
         ...mapGetters({
-            teacherList: 'user/getSchoolUserJoined', // 取得已加入此學校的使用者
+            teacherList: 'user/getTeacherJoined', // 取得已加入此學校的使用者
         }),
         subjectData() {
             let nodes = []

+ 1 - 0
TEAMModelOS/ClientApp/src/view/newsheet/index.vue

@@ -517,6 +517,7 @@
 					// let configParams = this.$store.state.answerSheet.config
 					let cropCount = this.$store.state.answerSheet.pages
 					delete configParams.contents
+					configParams.newContents = configParams.newContents.filter(i => i.points.length > 0)
 					configParams.mode = this.curMode
 					configParams.pageHeight = Number(configParams.pageHeight.toFixed())
 					// A3模式下的pageWidth、pageCount和A4模式下不同

+ 1 - 1
TEAMModelOS/ClientApp/src/view/regist/Index.vue

@@ -340,7 +340,7 @@ export default {
                                 //設定權限並登入
                                 User.login(result).then(res => {
                                     if (res) {
-                                        let homePath = this.$store.state.config.srvAdr == 'China' ? 'home' : 'myCourse'
+                                        let homePath = 'home'
                                         this.$router.push({ name: homePath })
                                     }
                                 })

+ 514 - 0
TEAMModelOS/ClientApp/src/view/research-center/ResearchCenterMock.vue

@@ -0,0 +1,514 @@
+<template>
+	<div class="research-center-container" ref="outerBox" @scroll="handleScroll($event)">
+		<div class="swiper-wrap">
+			<div class="left">
+				<p class="title">
+					<Icon type="ios-people" />基础数据统计
+				</p>
+				<div class="count-box">
+					<div class="count-box-item" v-for="(item,index) in titleItem">
+						<countTo :startVal='0' :endVal='item.number' :duration='2000' class="count-num"></countTo>
+						<span>{{ item.title }}</span>
+					</div>
+				</div>
+			</div>
+			<div class="mid">
+				<img :src="introVideos.length ? introVideos[curSwiperIndex].poster : emptyPoster" width="100%">
+				<div class="overlay">
+					{{ introVideos.length ? overlayContent : '暂无数据' }}
+				</div>
+			</div>
+			<div class="right">
+				<div class="swiper-list">
+					<div class="swiper-list-title">
+						<Icon type="md-flame" color="red" />
+						<span>名师课堂公开课</span>
+					</div>
+					<span :class="['swiper-item', 'text-cut', curSwiperIndex === index ? 'swiper-item-active' : '']"
+						v-for="(item,index) in introVideos" :key="index" @mouseenter="onSwiperItemHover(index)">
+						{{ item.teacher }} - {{ item.name }}
+					</span>
+				</div>
+			</div>
+		</div>
+		<!-- 专家好课 -->
+		<div class="cate-wrap">
+			<div class="title-wrap">
+				<span class="title">专家好课</span>
+				<span class="more" v-if="introVideos.length">
+					更多 >
+				</span>
+			</div>
+			<div>
+				<EmptyData v-if="!introVideos.length"></EmptyData>
+				<div class="video-box" v-else>
+					<BaseVideo v-for="(item,index) in introVideos" :key="index" :item="item"></BaseVideo>
+				</div>
+			</div>
+			
+		</div>
+		<!-- 精选推荐 -->
+		<div class="cate-wrap">
+			<div class="title-wrap">
+				<span class="title">精选推荐</span>
+				<span class="more" v-if="introVideos.length">
+					更多 >
+				</span>
+			</div>
+			<div>
+				<EmptyData v-if="!introVideos.length"></EmptyData>
+				<div class="video-box" v-else>
+					<BaseVideo v-for="(item,index) in introVideos" :key="index" :item="item"></BaseVideo>
+				</div>
+			</div>
+		</div>
+		<!-- 今日课堂 -->
+		<div class="cate-wrap">
+			<div class="title-wrap">
+				<span class="title">今日课堂</span>
+				<span class="more" v-if="introVideos.length">
+					更多 >
+				</span>
+			</div>
+			<div>
+				<EmptyData v-if="!introVideos.length"></EmptyData>
+				<div class="video-box" v-else>
+					<BaseVideo v-for="(item,index) in introVideos" :key="index" :item="item"></BaseVideo>
+				</div>
+			</div>
+			
+		</div>
+		<!-- 教师课例 -->
+		<div class="cate-wrap">
+			<div class="title-wrap">
+				<span class="title">教师课例 </span>
+			</div>
+			<div class="filter-box">
+				<div class="filter-section">
+					<span class="filter-title">科目</span>
+					<span :class="['filter-item',!subjectIndexArr.length ? 'filter-item-active' : '']" @click="onFilterChange('subject',-1)">不限</span>
+					<span :class="['filter-item',subjectIndexArr.includes(index) ? 'filter-item-active' : '']"
+						v-for="(item,index) in curPeriod.subjects" :key="index"
+						@click="onFilterChange('subject',index)">{{ item.name }}</span>
+				</div>
+				<div class="filter-section">
+					<span class="filter-title">年级</span>
+					<span :class="['filter-item',!gradeIndexArr.length ? 'filter-item-active' : '']" @click="onFilterChange('grade',-1)">不限</span>
+					<span :class="['filter-item',gradeIndexArr.includes(index) ? 'filter-item-active' : '']"
+						v-for="(item,index) in curPeriod.grades" :key="index"
+						@click="onFilterChange('grade',index)">{{ item }}</span>
+				</div>
+				<div class="filter-section">
+					<span class="filter-title">类别</span>
+					<span :class="['filter-item',!tagIndexArr.length ? 'filter-item-active' : '']" @click="onFilterChange('tag',-1)">不限</span>
+					<span :class="['filter-item',tagIndexArr.includes(index) ? 'filter-item-active' : '']"
+						v-for="(item,index) in tagList" :key="index"
+						@click="onFilterChange('tag',index)">{{ item }}</span>
+				</div>
+				<div class="filter-section">
+					<span class="filter-title">其它</span>
+					<span :class="['filter-item',!otherIndexArr.length ? 'filter-item-active' : '']" @click="onFilterChange('other',-1)">不限</span>
+					<span :class="['filter-item',otherIndexArr.includes(index) ? 'filter-item-active' : '']"
+						v-for="(item,index) in otherList" :key="index"
+						@click="onFilterChange('other',index)">{{ item }}</span>
+				</div>
+				<div class="filter-section" style="margin-top: 20px;">
+					<span :class="['sort-item',curSortType === 'time' ? 'sort-item-active' : '']"
+						@click="onSortChange('time')">
+						<span>上传时间</span>
+						<Icon type="md-arrow-up" />
+					</span>
+					<span :class="['sort-item',curSortType === 'like' ? 'sort-item-active' : '']"
+						@click="onSortChange('like')">
+						<span>收藏数</span>
+						<Icon type="md-arrow-up" />
+					</span>
+					<span>符合条件课例数 <span class="search-count">{{ totalNum.count }}</span> 个</span>
+				</div>
+			</div>
+			<div class="video-box">
+				<div v-if="!listVideos.length" style="margin: 20px auto 50px auto;">
+					<EmptyData></EmptyData>
+				</div>
+				<BaseVideo v-for="(item,index) in listVideos" :key="index" :item="item">
+				</BaseVideo>
+			</div>
+			<div class="loading-box" v-if="!isReachBottom">
+				<Spin v-if="!isLoadFinish"></Spin>
+				<span>{{ isLoadFinish ? '我也是有底线的~' :  '加载中'}}</span>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+	import countTo from 'vue-count-to'
+	import BaseVideo from './BaseVideo.vue'
+	export default {
+		components: {
+			BaseVideo,
+			countTo
+		},
+		data() {
+			return {
+				totalNum:0,
+				pageSize:10,
+				continuationToken:null,
+				curSwiperIndex: 0,
+				isLoadFinish: false,
+				isReachBottom: true,
+				filterParams:null,
+				listVideos: [],
+				tagList: ['语文教研', '数学教研', '英语教研', '特色课程', '混合学习'],
+				otherList: ['双绿灯课例', '优课课例'],
+				swiperList: [],
+				gradeIndexArr: [],
+				subjectIndexArr: [],
+				tagIndexArr: [],
+				otherIndexArr: [],
+				curSortType: 'time',
+				invId: null,
+				titleItem: [
+					{
+						title: '课例总数',
+						key:'total',
+						number: 0
+					},
+					{
+						title: '今日课例',
+						key:'today',
+						number: 0
+					},
+					{
+						title: '本周课例',
+						key:'week',
+						number: 0,
+					},
+					{
+						title: '本学期课例',
+						key:'semester',
+						number: 0
+					},
+					{
+						title: '典藏课例',
+						number: 0
+					},
+					{
+						title: '专家课例',
+						number: 0
+					}
+				],
+				introVideos: [{
+						poster: 'https://sokrates.teammodel.cn/storage/tba/10997/thum.jpg?0.02871025161938201',
+						name: '小学差异教学的实践研究 ',
+						teacher: '楼兆辉',
+						duration: 621,
+						tScore: 78,
+						pScore: 85,
+						isPro: true,
+						subject: '语文',
+						grade: '三年级'
+					},
+					{
+						poster: 'https://sokrates.teammodel.cn/storage/tba/10998/thum.jpg?0.8956634819391203',
+						name: '小学“远程植入式教学”引领教育精准扶智',
+						teacher: '李蓓',
+						duration: 621,
+						tScore: 78,
+						pScore: 85,
+						isPro: true,
+						subject: '语文',
+						grade: '三年级'
+					},
+					{
+						poster: 'https://sokrates.teammodel.cn/storage/tba/20835/thum.png?0.7129748401071314',
+						name: '中华优秀传统文化·博悟课程开发与实施 ',
+						teacher: '陈致寒',
+						duration: 621,
+						tScore: 78,
+						pScore: 85,
+						isPro: true,
+						subject: '语文',
+						grade: '三年级'
+					},
+					{
+						poster: 'https://sokrates.teammodel.cn/storage/tba/20764/thum.jpg?0.8641756343721363',
+						name: '小学差异教学的实践研究 ',
+						teacher: '楼兆辉',
+						duration: 621,
+						tScore: 78,
+						pScore: 85,
+						isPro: true,
+						subject: '语文',
+						grade: '三年级'
+					},
+					{
+						poster: 'https://sokrates.teammodel.cn/storage/tba/20934/thum.png?0.04874312058678698',
+						name: '小学差异教学的实践研究 ',
+						teacher: '宋代打',
+						duration: 621,
+						tScore: 78,
+						pScore: 85,
+						isPro: true,
+						subject: '语文',
+						grade: '三年级'
+					},
+					{
+						poster: 'https://sokrates.teammodel.cn/storage/tba/20835/thum.png?0.7129748401071314',
+						name: '小学差异教学的实践研究 ',
+						teacher: '楼兆辉',
+						duration: 621,
+						tScore: 78,
+						pScore: 85,
+						isPro: true,
+						subject: '语文',
+						grade: '三年级'
+					}],
+				doubleGreenVideos:[],
+				todayVideos:[],
+				schoolSas:null
+			}
+		},
+		created() {
+			this.runInv()
+			this.initFilter()
+			this.getDashboardData()
+			this.getIntroLessons()
+		},
+		methods: {
+			/* 获取最新课例统计数据 */
+			async getDashboardData(){
+				let semesterRange = this.$tools.getSemesterTimeRange()
+				this.schoolSas = await this.$tools.getSchoolSas()
+				this.$api.lessonRecord.getDashboardData({
+					"stime": semesterRange.st,
+					"etime": semesterRange.et,
+					"code": this.$store.state.user.schoolCode,
+					"periodId":this.$store.state.user.curPeriod.id
+				}).then(res => {
+					console.error(res)
+					let totalJson = res.total
+					if(totalJson){
+						totalJson.forEach(i => {
+							this.titleItem.find(j => j.key === i.name).number = i.value
+						})
+					}
+				})
+			},
+			/* 获取推荐课例数据 */
+			getIntroLessons(){
+				let semesterRange = this.$tools.getSemesterTimeRange()
+				this.$api.lessonRecord.getIntroLessons({
+					"stime": semesterRange.st,
+					"etime": semesterRange.et,
+					"tmdid": this.$store.state.user.TEAMModelId,
+					"scope": "school",
+					"school": this.$store.state.user.schoolCode,
+					"periodId":this.$store.state.user.curPeriod.id
+				}).then(res => {
+					// this.introVideos = this.getFullInfo(res.excellentRcd)
+					// this.doubleGreenVideos = this.getFullInfo(res.doubleGreenRcd)
+					// this.todayVideos = this.getFullInfo(res.todayRcd)
+					
+					// this.introVideos = []
+					// this.doubleGreenVideos = []
+					// this.todayVideos = []
+					// console.error(this.introVideos)
+				})
+			},
+			/* 初始化请求参数 */
+			initFilter(){
+				this.subjectIndexArr = []
+				this.gradeIndexArr = []
+				this.tagIndexArr = []
+				this.otherIndexArr = []
+				this.filterParams = {
+					"tmdid": this.$store.state.userInfo.TEAMModelId,
+					"scope": "school",
+					"school": this.$store.state.userInfo.schoolCode,
+					"category": [],
+					"subjectId": [],
+					"grade": [],
+					"doubleGreen": false,
+					"periodId": this.curPeriod.id,
+					"quality": false,
+					"DESC": "startTime",
+					"pageCount": this.pageSize,
+					"continuationToken": this.continuationToken
+				}
+				this.doFilter()
+			},
+			/* 轮播鼠标滑动事件 */
+			onSwiperItemHover(index) {
+				this.curSwiperIndex = index
+			},
+			/* 开启轮播轮询 */
+			runInv() {
+				this.invId = setInterval(() => {
+					this.curSwiperIndex = this.curSwiperIndex === this.introVideos.length - 1 ? 0 : this.curSwiperIndex + 1
+				}, 3000)
+			},
+			/* 关闭轮询 */
+			clearInv() {
+				clearInterval(this.invId)
+			},
+			/* 筛选操作 */
+			onFilterChange(type, index) {
+				if (type === 'grade') {
+					if(index === -1){
+						this.gradeIndexArr = []
+					}else if(this.gradeIndexArr.includes(index)){
+						this.gradeIndexArr.splice(this.gradeIndexArr.indexOf(index),1)
+					}else{
+						this.gradeIndexArr.push(index)
+					}
+					this.filterParams.grade = this.gradeIndexArr.map(i => i + 1 + '')
+				} else if (type === 'subject') {
+					if(index === -1){
+						this.subjectIndexArr = []
+					}else if(this.subjectIndexArr.includes(index)){
+						this.subjectIndexArr.splice(this.subjectIndexArr.indexOf(index),1)
+					}else{
+						this.subjectIndexArr.push(index)
+					}
+					this.filterParams.subjectId = index === -1 ? [] : this.subjectIndexArr.map(j => this.curPeriod.subjects[j].id)
+				} else if (type === 'tag') {
+					if(index === -1){
+						this.tagIndexArr = []
+					}else if(this.tagIndexArr.includes(index)){
+						this.tagIndexArr.splice(this.tagIndexArr.indexOf(index),1)
+					}else{
+						this.tagIndexArr.push(index)
+					}
+					this.filterParams.category = this.tagIndexArr.map(i => this.tagList[i])
+				} else {
+					if(index === -1){
+						this.otherIndexArr = []
+					}else if(this.otherIndexArr.includes(index)){
+						this.otherIndexArr.splice(this.otherIndexArr.indexOf(index),1)
+					}else{
+						this.otherIndexArr.push(index)
+					}
+					this.filterParams.doubleGreen = this.otherIndexArr.includes(0)
+					this.filterParams.quality = this.otherIndexArr.includes(1)
+				}
+				this.doFilter()
+			},
+			/* 替换课例数据的科目学段等信息 */
+			getFullInfo(list){
+				list.forEach(item => {
+					let container = item.scope === 'school' ? item.school : item.tmdid
+					let blobHost = this.$evTools.getBlobHost()
+					item.videoPath = blobHost + '/' + container + '/records/' + item.id + '/Record/CourseRecord.mp4'  + this.schoolSas.sas
+					item.poster = blobHost + '/' + container + '/records/' + item.id + '/Record/CoverImage.jpg' + this.schoolSas.sas
+					item.subject = this.curPeriod.subjects.find(i => i.id === item.subjectId).name
+					item.grade = item.grade.map(i => this.curPeriod.grades[+i]).join(',')
+				})
+				return list
+			},
+			/* 发送筛选请求 初始化请求 第一次 */
+			async doFilter(){
+				this.isReachBottom = false
+				this.filterParams.continuationToken = null
+				this.totalNum = await this.$api.lessonRecord.getLessonCount(this.filterParams)
+				this.$api.lessonRecord.getLessonList(this.filterParams).then(res => {
+					if(!res.error && res.lessonRecords){
+						this.listVideos = this.getFullInfo(res.lessonRecords)
+						this.isReachBottom = true
+						this.continuationToken = res.continuationToken
+					}
+				})
+				this.filterParams.continuationToken = this.continuationToken
+			},
+			/* 排序操作 */
+			onSortChange(type) {
+				this.curSortType = type
+			},
+			/* 触底加载更多操作 */
+			handleScroll(e) {
+				let scrollHeight = e.srcElement.scrollTop
+				let clientHeight = e.target.clientHeight
+				let totalHeight = e.target.scrollHeight
+				if (scrollHeight + clientHeight >= totalHeight && this.isReachBottom && this.continuationToken) {
+					this.isReachBottom = false
+					this.isLoadFinish = false
+					setTimeout(() => {
+						this.getMore()
+					},500)
+				}
+			},
+			/* 获取当前条件课例数据 */
+			getMore() {
+				this.filterParams.continuationToken = this.continuationToken
+				this.$api.lessonRecord.getLessonList(this.filterParams).then(res => {
+					if(!res.error && res.lessonRecords){
+						if(res.continuationToken === null){
+							this.isLoadFinish = true
+							this.isReachBottom = false
+						}else{
+							this.isReachBottom = true
+						}
+						console.log(this.listVideos);
+						this.listVideos = this.listVideos.concat(this.getFullInfo(res.lessonRecords))
+						this.continuationToken = res.continuationToken
+					}
+				})
+			},
+		},
+		mounted() {
+			
+		},
+		beforeDestroy() {
+			this.clearInv()
+		},
+		computed: {
+			curPeriod() {
+				return this.$store.state.user.curPeriod
+			},
+			overlayContent() {
+				let curItem = this.introVideos[this.curSwiperIndex]
+				// return curItem.teacher + '-' + curItem.name + '【' + curItem.subject + '】'+ '【' + curItem.grade + '】'
+				return `${curItem.teacher}-${curItem.grade}-${curItem.subject} 【${curItem.name}】`
+			},
+			emptyPoster(){
+				return require('@/assets/image/no_data.png')
+			}
+		},
+		watch:{
+			'$store.state.user.curPeriod': {
+				deep: true,
+				handler(n, o) {
+					if (n) {
+						this.initFilter()
+					}
+				}
+			}
+		}
+	}
+</script>
+<style type="text/css">
+	.slide-left-enter {
+		transform: translateX(-100%);
+	}
+
+	.slide-left-enter-active {
+		transition: transform .2s;
+	}
+
+	.slide-left-enter-to {
+		transform: translateX(0);
+	}
+
+	.slide-left-leave {
+		transform: translateX(0);
+	}
+
+	.slide-left-leave-active {
+		transition: transform .5s
+	}
+
+	.slide-left-leave-to {
+		transform: translateX(-100%);
+	}
+</style>
+<style lang="less" src="./ResearchCenter.less" scoped></style>

+ 22 - 92
TEAMModelOS/ClientApp/src/view/schoolmgmt/SystemSetting/SystemSetting.vue

@@ -43,7 +43,7 @@
                     <Option v-for="(item,index) in timeZoneList" :value="item.label" :key="index" @click.native="setTimeZone(item)">{{ item.label }}</Option>
                 </Select>
             </div>
-            <div class="base-info-item custom-radio">
+            <div class="base-info-item custom-radio-box">
                 <span class="setting-label">{{$t('schoolBaseInfo.scType')}}</span>
                 <RadioGroup v-model="schoolSetting.type">
                     <!-- 普教 -->
@@ -226,6 +226,26 @@
                                 </div>
                                 </Col>
                             </Row>
+                            <!-- 班级专业设置 -->
+                            <!-- <div v-if="schoolSetting && schoolSetting.type == 2" class="setting-content profession-content disabled-iview-inputnumber"> -->
+                            <div class="setting-content profession-content disabled-iview-inputnumber">
+                                <p class="block-title bf-color5">
+                                    {{$t('schoolBaseInfo.professionLabel1')}}
+                                    <span class="block-action-box">
+                                        <Icon type="md-add" class="action-btn-icon" @click.stop="addMajor" v-if="$access.ability('admin','schoolSetting-upd').validateAll" />
+                                    </span>
+                                </p>
+                                <div style="height:150px">
+                                    <vuescroll>
+                                        <div class="profs-item input-line-height tag-item item-active" @click.stop v-for="(item,index) in schoolSetting.period[curPriodIndex].majors" :key="index">
+                                            <Input v-model="item.name" :disabled="etMajorIndex !== index" :placeholder="$t('schoolBaseInfo.profsHolder')" :style="{width: getWidth(index,item.name)+'px'}" />
+                                            <Icon class="profs-action-icon" type="md-close" style="margin-left:0px" @click="delMajor(index)" />
+                                            <Icon class="profs-action-icon" type="md-create" @click="etMajorIndex = index" />
+                                        </div>
+                                        <EmptyData v-show="!schoolSetting.period[curPriodIndex].majors.length"></EmptyData>
+                                    </vuescroll>
+                                </div>
+                            </div>
                             <!-- 学情设置 -->
                             <div class="setting-content analysis-content subject-content">
                                 <p class="block-title bf-color4">
@@ -278,25 +298,7 @@
                                     </div>
                                 </div>
                             </div>
-                            <!-- 专业设置 -->
-                            <div v-if="schoolSetting && schoolSetting.type == 2" class="setting-content profession-content disabled-iview-inputnumber">
-                                <p class="block-title bf-color5">
-                                    {{$t('schoolBaseInfo.proSetting')}}
-                                    <span class="block-action-box">
-                                        <Icon type="md-add" class="action-btn-icon" @click.stop="addMajor" v-if="$access.ability('admin','schoolSetting-upd').validateAll" />
-                                    </span>
-                                </p>
-                                <div style="height:150px">
-                                    <vuescroll>
-                                        <div class="profs-item input-line-height tag-item item-active" @click.stop v-for="(item,index) in schoolSetting.period[curPriodIndex].majors" :key="index">
-                                            <Input v-model="item.name" :disabled="etMajorIndex !== index" :placeholder="$t('schoolBaseInfo.profsHolder')" :style="{width: getWidth(index,item.name)+'px'}" />
-                                            <Icon class="profs-action-icon" type="md-close" style="margin-left:0px" @click="delMajor(index)" />
-                                            <Icon class="profs-action-icon" type="md-create" @click="etMajorIndex = index" />
-                                        </div>
-                                        <EmptyData v-show="!schoolSetting.period[curPriodIndex].majors.length"></EmptyData>
-                                    </vuescroll>
-                                </div>
-                            </div>
+                            
                         </vuescroll>
                         <!--时段设置-->
                         <div slot="right" class="time-setting-wrap">
@@ -1679,78 +1681,6 @@ export default {
     cursor: text;
     color: var(--primary-text-color);
 }
-.custom-radio {
-    .ivu-select-selection {
-        background: transparent;
-        border-color: #363738;
-        color: #a6a6a6;
-    }
-
-    .ivu-radio-wrapper {
-        margin-right: 20px;
-        color: #303030;
-    }
-
-    .ivu-radio-inner {
-        width: 18px;
-        height: 18px;
-        border-radius: 4px;
-        // background-color: #0f0f0f;
-        border-color: #c3c3c3;
-        border-width: 1px;
-        margin-right: 5px;
-        &::after {
-            content: "";
-            display: block;
-            width: 10px;
-            height: 16px;
-            border-right: #ffffff solid 3px;
-            border-bottom: #ffffff solid 3px;
-            transform: rotate(35deg);
-            position: absolute;
-            top: -4px;
-            left: 4px;
-            border-radius: 0;
-            background-color: transparent;
-            border-color: #0094ff;
-        }
-    }
-    .ivu-checkbox-inner {
-        width: 18px;
-        height: 18px;
-        border-radius: 4px;
-        // background-color: #0f0f0f;
-        border-color: var(--border-color);
-        border-width: 1px;
-        margin-right: 5px;
-    }
-
-    .ivu-checkbox-checked .ivu-checkbox-inner {
-        width: 18px;
-        height: 18px;
-        border-radius: 4px;
-        background-color: #fff;
-        border-color: #4d4d4d;
-        border-width: 1px;
-        margin-right: 5px;
-        &::after {
-            content: "";
-            display: block;
-            width: 10px;
-            height: 16px;
-            border-right: #ffffff solid 3px;
-            border-bottom: #ffffff solid 3px;
-            transform: rotate(35deg);
-            transition: all 0.1s;
-            position: absolute;
-            top: -4px;
-            left: 4px;
-            border-radius: 0;
-            background-color: transparent;
-            border-color: #0094ff;
-        }
-    }
-}
 .grade-name .ivu-input {
     text-align: center;
     color: var(--primary-text-color);

+ 1 - 1
TEAMModelOS/ClientApp/src/view/sso/Index.vue

@@ -104,7 +104,7 @@ export default {
 				} else {
 					// 前往校级平台 判断是否有记录的目标地址 如果没有则按照站点来进行对应跳转固定页面
 					let targetPath = localStorage.getItem('target_path')
-					let defaultPath = this.$store.state.config.srvAdr == 'China' ? '/home' : '/home/myCourse'
+					let defaultPath = '/home'
 				    let homePath = targetPath ? (targetPath.includes('home/') ? targetPath : defaultPath) : defaultPath
 				    localStorage.setItem('platform', 'school')
 					localStorage.setItem('target_path','')

+ 9 - 10
TEAMModelOS/ClientApp/src/view/student-account/class/ClassMgt.vue

@@ -179,10 +179,6 @@
         </Modal>
         <Modal v-model="addClassStatus" :title="$t('schoolBaseInfo.newClass')" @on-ok="addClass" :loading="mLoading">
             <Form ref="classInfo" :model="classInfo" :rules="classValidate" style="padding-top:20px">
-                <FormItem prop="name" @click.native.stop class="requird-color">
-                    <span slot="label" class="class-attr-wrap-label">{{$t('schoolBaseInfo.className')}}</span>
-                    <Input v-special-char @on-change="watchUpdate" :disabled="editStatus" v-model="classInfo.name" clearable :placeholder="$t('schoolBaseInfo.classroomNameHolder')" />
-                </FormItem>
                 <FormItem prop="year" @click.native.stop class="requird-color">
                     <span slot="label" class="class-attr-wrap-label">{{$t('schoolBaseInfo.yearGrade')}}</span>
                     <Select @on-change="watchUpdate" :disabled="editStatus" v-model="classInfo.year" clearable>
@@ -191,6 +187,11 @@
                         </Option>
                     </Select>
                 </FormItem>
+                <FormItem prop="name" @click.native.stop class="requird-color">
+                    <span slot="label" class="class-attr-wrap-label">{{$t('schoolBaseInfo.className')}}</span>
+                    <Input v-special-char @on-change="watchUpdate" :disabled="editStatus" v-model="classInfo.name" clearable :placeholder="$t('schoolBaseInfo.classNameHolder')" />
+                </FormItem>
+                
                 <FormItem prop="no" @click.native.stop class="requird-color">
                     <span slot="label" class="class-attr-wrap-label">{{$t('schoolBaseInfo.classLabel')}}</span>
                     <Input v-special-char @on-change="watchUpdate" :disabled="editStatus" v-model="classInfo.no" clearable :placeholder="$t('schoolBaseInfo.classroomCodeHolder')" />
@@ -205,8 +206,8 @@
                     </Select>
                 </FormItem>
                 <!-- 设置专业 这里建议学校类型为高教显示 -->
-                <FormItem v-if="schoolBase && schoolBase.type == 2" prop="marjorId" @click.native.stop class="requird-color">
-                    <span slot="label" class="class-attr-wrap-label">{{$t('schoolBaseInfo.profession')}}</span>
+                <FormItem prop="marjorId" @click.native.stop class="requird-color">
+                    <span slot="label" class="class-attr-wrap-label">{{$t('schoolBaseInfo.professionLabel')}}</span>
                     <Select @on-change="watchUpdate" :disabled="editStatus" v-model="classInfo.marjorId" clearable :not-found-text="$t('schoolBaseInfo.noProfession')">
                         <Option v-for="(item,index) in majorList" :value="item.id" :key="index">
                             {{ item.name }}
@@ -436,7 +437,7 @@ export default {
             classList: 'user/getClasses',
             roomList: 'user/getRooms',
             allStudents: 'student/getStudent', // 學生List
-            teacherList: 'user/getSchoolUserJoined', // 取得已加入此學校的使用者
+            teacherList: 'user/getTeacherJoined', // 取得已加入此學校的使用者
         }),
         filterYearName() {
             if (this.filterYear == 'all') {
@@ -1060,7 +1061,6 @@ export default {
                 }
             },
             err => {
-                this.$Message.error('user/setSchoolTeacher API error!')
             }
         )
     },
@@ -1101,8 +1101,7 @@ export default {
                     })
                 }
             },
-            deep: true,
-            immediate: true
+            deep: true
         }
     }
 }

+ 1 - 1
TEAMModelOS/ClientApp/src/view/student-web/App.vue

@@ -246,7 +246,7 @@
             },
             onQuit() {
                 this.$store.commit('user/resetSchoolProfile')
-                this.$store.commit("ChangeItemName",{})
+                this.$store.commit("ChangeItemName", null)
                 localStorage.removeItem('Item')
                 localStorage.removeItem('subjectNow')
                 localStorage.removeItem('examInfo')

+ 12 - 5
TEAMModelOS/ClientApp/src/view/teachermgmt/Index.less

@@ -6,7 +6,6 @@
         height: 45px;
         box-shadow: 0 2px 5px #e9e9e9;
         margin-bottom: 5px;
-        // border-bottom: 1px solid var(--border-color);
         padding: 0px 15px;
         background-color: var(--body-bg);
         .tab-box {
@@ -33,9 +32,17 @@
         width: 100%;     
     }
 }
-.opacity-enter-active, .opacity-leave-active {
-    transition: all 0.3s;
+
+.teachemgt-action-btn{
+    float: right;
+    margin-top: 10px;
+    margin-right: 10px;
+    cursor: pointer;
+    user-select: none;
 }
-.opacity-enter, .opacity-leave-to /* .list-leave-active below version 2.1.8 */ {
-    opacity: 0;
+.import-icon{
+    margin-right: 5px;
+    vertical-align: baseline;
+    font-size: 12px;
+
 }

+ 81 - 93
TEAMModelOS/ClientApp/src/view/teachermgmt/Index.vue

@@ -1,118 +1,106 @@
 <style lang="less" scoped>
-@import './Index.less';
+@import "./Index.less";
 </style>
 
 <style lang="less">
 .badgesty {
-  margin-left: 6px;
-  box-shadow: none;
+    margin-left: 6px;
+    box-shadow: none;
 }
 </style>
 
 <template>
-  <div id="teachermgmt">
-    <div class="mgmt-top">
-      <div class="tab-box">
-        <span class="pane" @click="paneBtn('userList')" :class="{ active: compts === 'userList' }">{{ $t('teachermgmt.page.text1') }}</span>
-        <span v-if="$store.state.config.srvAdr === 'China'" class="pane" @click="paneBtn('Group')" :class="{ active: compts === 'Group' }">{{ $t('teachermgmt.page.text3')}}</span>
-        <span v-if="$access.can('admin.*|teacher-upd')" class="pane" @click="paneBtn('personnel')" :class="{ active: compts === 'personnel' }">{{ $t('teachermgmt.page.text2') }} <Badge :count="requestedUserCount" class-name="badgesty"></Badge></span>
-      </div>
+    <div id="teachermgmt">
+        <Loading v-if="isLoading"></Loading>
+        <div class="mgmt-top">
+            <div class="tab-box">
+                <span class="pane" @click="paneBtn('mgt')" :class="{ active: compts === 'mgt' }">{{ $t('teachermgmt.page.text1') }}</span>
+                <span v-if="$store.state.config.srvAdr === 'China'" class="pane" @click="paneBtn('group')" :class="{ active: compts === 'group' }">{{ $t('teachermgmt.page.text3')}}</span>
+                <span v-if="$access.can('admin.*|teacher-upd')" class="pane" @click="paneBtn('add')" :class="{ active: compts === 'add' }">{{ $t('teachermgmt.page.text2') }} <Badge :count="requestedTeacher.length" class-name="badgesty"></Badge></span>
+            </div>
+            <!-- <span class="teachemgt-action-btn" @click="paneBtn('import')">
+                <icon class="import-icon" icon="upload" />
+                {{ $t('teachermgmt.addTeacher.btn.upload') }}
+            </span> -->
+        </div>
+        <div class="mgmt-main">
+            <!-- <personnel v-if="compts == 'personnel'"></personnel>
+            <Group v-else-if="compts == 'Group'"></Group>
+            <teacherMgt v-else-if="compts == 'teacherMgt'"></teacherMgt> -->
+            <!-- <transition name="opacity" mode="out-in">
+                <div :is="compts"></div>
+            </transition> -->
+            <keep-alive>
+                <router-view></router-view>
+            </keep-alive>
+        </div>
     </div>
-    <div class="mgmt-main">
-      <transition name="opacity" mode="out-in">
-        <div :is="compts"></div>
-      </transition>
-    </div>
-  </div>
 </template>
 
 <script>
-import userList from './components/userList/Index.vue'
+import teacherMgt from './components/mgt/TeacherMgt.vue'
 import personnel from './components/personnel/Index.vue'
 import Group from './components/group/Group.vue'
-import { mapGetters, mapMutations } from 'vuex'
+import { mapGetters } from 'vuex'
 
 export default {
-  data() {
-    return {
-      compts: 'userList'
-    }
-  },
-  components: {
-    userList,
-    personnel,
-    Group
-  },
-  computed: {
-    ...mapGetters({
-      requestedUserCount: 'user/getSchoolUserRequestedCount', //申請加入此學校的使用者數
-      authList: 'user/getschoolSettingAuthList', //權限總列表
-      isKeyInSpace: 'spaceAuth/getIsKeyInSpace'
-    }),
-    user() {
-      return this.$access.getExtendInfo('userInfo')
-    }
-  },
-  methods: {
-    paneBtn(pane) {
-      this.compts = pane
-    },
-    //由DB取得該校所有使用者並放入state.schoolUserList
-    getSchoolTeacher() {
-      this.$store.dispatch('user/getSchoolTeacher').then(
-        res => {
-          if (res.code == 0) {
-            // this.$Message.error('API error')
-          }
-        },
-        err => {
-          // this.$Message.error('user/setSchoolTeacher API error!')
+    data() {
+        return {
+            compts: 'mgt',
+            isLoading: false
         }
-      )
     },
-    //由DB取得權限總列表並放入state.schoolSettingAuthList
-    getSchoolAuthorityList() {
-      this.$store.dispatch('user/getSchoolAuthorityList').then(
-        res => {
-          if (res.code == 0) {
-            // alert('API error')
-          }
-        },
-        err => {
-          // alert('user/getSchoolAuthorityList API error: ' + err)
+    components: {
+        personnel,
+        Group,
+        teacherMgt
+    },
+    computed: {
+        ...mapGetters({
+            requestedTeacher: 'user/getTeacherRequested', //申請加入此學校的使用者數
+            isKeyInSpace: 'spaceAuth/getIsKeyInSpace'
+        }),
+        user() {
+            return this.$access.getExtendInfo('userInfo')
         }
-      )
-    }
-    // 取得所有學校資料
-    // getAllSchoolBaesInfoTest() {
-    //    this.$api.GetAllSchoolBaesInfo({}).then(
-    //          res => {
-    //            console.log(res);
-    //      })
-    // }
-  },
-  beforeRouteLeave(to, from, next) {
-    if (this.isKeyInSpace == true) {
-      let config = {
-        title: this.$t('teachermgmt.saveWarning'),
-        content: this.$t('teachermgmt.warningCnt'),
-        okText: this.$t('teachermgmt.leaveText'),
-        onOk: () => {
-          next()
+    },
+    methods: {
+        paneBtn(pane) {
+            this.compts = pane
+            this.$router.push({
+                name: pane
+            })
         },
-        onCancel: () => {
-          next(false)
+        getSchoolTeachers() {
+            this.isLoading = true
+            this.$store.dispatch('user/getSchoolTeacher').then().finally(() => {
+                this.isLoading = false
+            })
         }
-      }
-      this.$Modal.confirm(config)
-    } else {
-      next()
+    },
+    created() {
+        this.getSchoolTeachers()
+    },
+    // beforeRouteLeave(to, from, next) {
+    //     if (this.isKeyInSpace == true) {
+    //         let config = {
+    //             title: this.$t('teachermgmt.saveWarning'),
+    //             content: this.$t('teachermgmt.warningCnt'),
+    //             okText: this.$t('teachermgmt.leaveText'),
+    //             onOk: () => {
+    //                 next()
+    //             },
+    //             onCancel: () => {
+    //                 next(false)
+    //             }
+    //         }
+    //         this.$Modal.confirm(config)
+    //     } else {
+    //         next()
+    //     }
+    // },
+    mounted() {
+        this.compts = this.$route.name
     }
-  },
-  mounted() {
-    this.getSchoolTeacher()
-    this.getSchoolAuthorityList()
-    // this.getAllSchoolBaesInfoTest()
-  }
 }
 </script>

+ 7 - 2
TEAMModelOS/ClientApp/src/view/teachermgmt/components/group/Group.vue

@@ -1,5 +1,6 @@
 <template>
     <div class="teacher-group-container">
+        <Loading v-if="isLoading"></Loading>
         <vuescroll>
             <div class="group-data-box">
                 <div class="group-wrap-item" v-for="(item,index) in groupList" :key="index">
@@ -83,6 +84,7 @@ export default {
     },
     data() {
         return {
+            isLoading: false,
             subjectSlt: [],
             teacherListShow: [],
             keyword: '',
@@ -144,7 +146,7 @@ export default {
     },
     computed: {
         ...mapGetters({
-            teacherList: 'user/getSchoolUserJoined', // 取得已加入此學校的使用者
+            teacherList: 'user/getTeacherJoined', // 取得已加入此學校的使用者
         }),
         subjectData() {
             let nodes = []
@@ -273,6 +275,7 @@ export default {
         },
         // 查询教研组
         getResearchGroup() {
+            this.isLoading = true
             let params = {
                 schoolId: this.$store.state.userInfo.schoolCode,
                 scope: 'school',
@@ -296,7 +299,9 @@ export default {
                 err => {
                     this.$Message.error(this.$t('teachermgmt.groupInfoErr'))
                 }
-            )
+            ).finally(() => {
+                this.isLoading = false
+            })
         },
         //删除组别
         delGroup(id) {

+ 88 - 0
TEAMModelOS/ClientApp/src/view/teachermgmt/components/import/Import.vue

@@ -0,0 +1,88 @@
+<template>
+    <div class="teacher-import-container">
+        <div class="import-tips-box">
+            <p class="import-title">导入教师名单栏位说明:</p>
+            <p class="import-info" style="margin-top:20px">1. ID: 教师醍摩豆ID,可以不填;</p>
+            <p class="import-info">2. name: 教师姓名,必填;</p>
+            <p class="import-info">3. note: 备注信息</p>
+            <p class="download-text" @click="downloadExample">
+                {{ $t('teachermgmt.addTeacher.btn.download') }}
+            </p>
+        </div>
+        <div class="import-file-box">
+            <Upload multiple type="drag" action="" :before-upload="customUpload">
+                <div class="file-area">
+                    <Icon type="ios-cloud-upload" size="52" style="color: #3399ff"></Icon>
+                    <p>点击或者拖拽文件导入</p>
+                </div>
+            </Upload>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+
+        }
+    },
+    methods: {
+        downloadExample() {
+            let lang = localStorage.getItem('local')
+            switch (lang) {
+                case 'zh-tw':
+                    window.location.href = 'https://teammodeltest.blob.core.chinacloudapi.cn/download/%E5%AF%BC%E5%85%A5%E6%95%99%E5%B8%88%E6%A8%A1%E6%9D%BF/%E6%95%99%E5%B8%AB%E5%8C%AF%E5%85%A5%E7%AF%84%E4%BE%8B.xlsx'
+                    break
+                case 'en-us':
+                    window.location.href = 'https://teammodeltest.blob.core.chinacloudapi.cn/download/%E5%AF%BC%E5%85%A5%E6%95%99%E5%B8%88%E6%A8%A1%E6%9D%BF/Teacher%20Import%20Template.xlsx'
+                    break
+                default:
+                    window.location.href = 'https://teammodeltest.blob.core.chinacloudapi.cn/download/%E5%AF%BC%E5%85%A5%E6%95%99%E5%B8%88%E6%A8%A1%E6%9D%BF/%E6%95%99%E5%B8%88%E6%B1%87%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx'
+                    break
+            }
+        },
+        customUpload(file){
+            
+        }
+    }
+}
+</script>
+<style scoped lang="less">
+.teacher-import-container {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+.import-tips-box {
+    // background: #f0f0f0;
+    width: 400px;
+    height: fit-content;
+}
+.import-file-box {
+    width: 400px;
+    height: fit-content;
+}
+.import-title {
+    font-size: 16px;
+    font-weight: 600;
+}
+.download-text {
+    color: #2d8cf0;
+    font-weight: 800;
+    font-size: 16px;
+    margin-top: 10px;
+    cursor: pointer;
+    user-select: none;
+    text-decoration: underline;
+}
+.import-info {
+    font-size: 16px;
+    margin-top: 5px;
+}
+.file-area{
+    padding: 50px;
+    background: #f3f3f3;
+}
+</style>

+ 199 - 0
TEAMModelOS/ClientApp/src/view/teachermgmt/components/mgt/SpaceStatusChart.vue

@@ -0,0 +1,199 @@
+<template>
+    <div id="spaceStatus-chart"></div>
+</template>
+
+<script>
+export default {
+    props: {
+        pieNumData: {
+            type: Array,
+            default: () => {
+                return []
+            }
+        }
+    },
+    name: 'SpaceStatusChart',
+    data() {
+        return {
+            currentColor: '#fff',
+            e: event,
+            index: 0,
+            myChart: undefined
+        }
+    },
+
+    mounted() {
+        this.drawLine(this.pieNumData);
+    },
+    watch: {
+        pieNumData: {
+            handler(val) {
+                if (val) {
+                    this.drawLine(val);
+                }
+            },
+            deep: true,
+            immediate: true
+        }
+    },
+
+    methods: {
+        drawLine() {
+            //基于准备好的dom,初始化echarts实例
+            let _this = this
+            this.$nextTick(() => {
+                if (!this.myChart) {
+                    this.myChart = this.$echarts.init(document.getElementById('spaceStatus-chart')) //绘制图表
+                }
+                this.myChart.setOption({
+                    tooltip: {
+                        position: [130, 90],
+                        trigger: 'item',
+                        backgroundColor: 'rgba(50,50,50,0.9)',
+                        borderColor: '#8D8D8D',
+                        borderWidth: 1,
+                        formatter: function (v) {
+                            if (v.color != '#48474c') _this._data.currentColor = v.color
+                            else _this._data.currentColor = 'white'
+                            return `
+                            <div class='chart-toolTip'> 
+                            <p id='color-title'>
+                            ${v.data.name}</p>
+                            <p class='value'>${v.data.value}&nbsp;GB (${v.percent}%)</p>
+                            </div> 
+                            `
+                        }
+                    },
+                    color: ['#eb974e', '#fb62bb', '#00f492'],
+                    series: [
+                        {
+                            type: 'pie',
+                            radius: ['50%', '90%'],
+                            avoidLabelOverlap: true,
+                            hoverOffset: 0, //調整餅圖凸顯時的高度
+                            label: {
+                                show: false,
+                                position: 'center',
+                                formatter: '{title1|{b}空間數}\n{num|{c}}{chracter|GB}\n\n{title2|空間占比}\n {percent|{d}}{chracter|%}',
+                                align: 'left',
+                                rich: {
+                                    title1: { fontWeight: 'bold', padding: [2, 15, 2, 0] },
+                                    title2: { fontWeight: 'bold', padding: [2, 63, 2, 0] },
+                                    chracter: {
+                                        fontSize: 10,
+                                        color: 'white',
+                                        padding: [0, 0, 10, 3]
+                                    },
+                                    picon: {
+                                        color: 'white'
+                                    },
+                                    percent: {
+                                        color: 'white',
+                                        fontSize: 30,
+                                        fontWeight: 'bold'
+                                    },
+                                    num: {
+                                        color: 'white',
+                                        fontSize: 30,
+                                        fontWeight: 'bold',
+                                        padding: [2, 0, 2, -20]
+                                    }
+                                }
+                            },
+                            startAngle: 90,
+                            emphasis: {
+                                label: {
+                                    show: false, //把餅圖中間預設顯示各類圖例的效果關掉
+                                    fontSize: '18',
+                                    fontWeight: 'bold'
+                                }
+                            },
+                            labelLine: {
+                                show: false
+                            },
+                            data: this.pieNumData
+                        }
+                    ]
+                })
+                this.myChart.dispatchAction({
+                    type: 'highlight',
+                    seriesIndex: 0,
+                    dataIndex: 7
+                })
+                //   this.myChart.on('mousemove', function (e) {
+                //       //在滑動時修改提示框樣式時的方法!!!
+                //       document.getElementById('color-title').style.color = _this._data.currentColor
+                //   })
+
+                //  this.myChart.on('mouseover', function (e) {
+                //       //Highlight the hovering piece
+                //       document.getElementById('color-title').style.color = _this._data.currentColor
+                //       myChart.dispatchAction({
+                //           type: 'downplay',
+                //           seriesIndex: 0,
+                //           dataIndex: 0
+                //       })
+
+                //       if (e.dataIndex == 0) {
+                //           myChart.dispatchAction({
+                //               type: 'highlight',
+                //               seriesIndex: 0,
+                //               dataIndex: e.dataIndex
+                //           })
+                //       }
+                //       if (e.dataIndex != this.index) {
+                //           myChart.dispatchAction({
+                //               type: 'downplay',
+                //               seriesIndex: 0,
+                //               dataIndex: this.index
+                //           })
+                //       }
+                //   })
+                //   myChart.on('mouseout', function (e) {
+                //       this.index = e.dataIndex
+                //       document.getElementById('color-title').style.color = _this._data.currentColor
+                //       myChart.dispatchAction({
+                //           type: 'highlight',
+                //           seriesIndex: 0,
+                //           dataIndex: this.index
+                //       })
+                //   })
+                //   //自適應
+                //   setTimeout(function () {
+                //       window.onresize = function () {
+                //           myChart.resize()
+                //       }
+                //   }, 200)
+            })
+        }
+    }
+}
+</script>
+
+<style lang="less">
+#spaceStatus-chart {
+    position: relative;
+    height: 150px;
+    margin-top: 20px;
+    width: 240px;
+    margin-bottom: 40px;
+    z-index: 22;
+    .chart-toolTip {
+        position: relative;
+        z-index: 99;
+        padding: 10px;
+        #color-title {
+            font-weight: bolder;
+        }
+        .title {
+            font-size: 10px;
+            color: gray;
+            font-weight: bolder;
+        }
+        .value {
+            font-weight: bolder;
+            color: white;
+        }
+    }
+}
+</style>

+ 0 - 0
TEAMModelOS/ClientApp/src/view/teachermgmt/components/mgt/TeacherMgt.less


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