Преглед изворни кода

Merge branch 'develop5.0' into TPE/develop5.0

jeff пре 3 година
родитељ
комит
432751678f
100 измењених фајлова са 2619 додато и 794 уклоњено
  1. 6 6
      TEAMModelFunction/ActivityHttpTrigger.cs
  2. 9 0
      TEAMModelFunction/MonitorCosmosDB.cs
  3. 146 137
      TEAMModelFunction/TriggerExam.cs
  4. 85 0
      TEAMModelFunction/TriggerExamLite.cs
  5. 85 0
      TEAMModelFunction/TriggerStudy.cs
  6. 5 4
      TEAMModelFunction/TriggerSurvey.cs
  7. 8 4
      TEAMModelFunction/TriggerVote.cs
  8. 85 0
      TEAMModelFunction/TriggerWork.cs
  9. 1 1
      TEAMModelOS.SDK/Extension/Utils.cs
  10. 89 0
      TEAMModelOS.SDK/Models/Cosmos/Common/ExamLite.cs
  11. 2 3
      TEAMModelOS.SDK/Models/Cosmos/Common/StuList.cs
  12. 16 20
      TEAMModelOS.SDK/Models/Cosmos/Common/Study.cs
  13. 2 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Survey.cs
  14. 5 1
      TEAMModelOS.SDK/Models/Cosmos/Common/TchList.cs
  15. 2 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Vote.cs
  16. 28 1
      TEAMModelOS.SDK/Models/Cosmos/School/Area.cs
  17. 1 1
      TEAMModelOS.SDK/Models/Cosmos/School/ClassAnalysis.cs
  18. 1 1
      TEAMModelOS.SDK/Models/Cosmos/School/GradeAnalysis.cs
  19. 1 1
      TEAMModelOS.SDK/Models/Cosmos/School/SchoolTeacher.cs
  20. 9 2
      TEAMModelOS.SDK/Models/Cosmos/Teacher/Teacher.cs
  21. 110 0
      TEAMModelOS.SDK/Models/Cosmos/Teacher/TeacherWork.cs
  22. 30 0
      TEAMModelOS.SDK/Models/Service/ExamService.cs
  23. 1 1
      TEAMModelOS.SDK/Models/Service/StuListService.cs
  24. 40 0
      TEAMModelOS.SDK/Models/Service/SurveyService.cs
  25. 40 0
      TEAMModelOS.SDK/Models/Service/TeacherWorkService.cs
  26. 130 40
      TEAMModelOS.SDK/Models/Service/TriggerStuActivity.cs
  27. 1 1
      TEAMModelOS.SDK/TEAMModelOS.SDK.csproj
  28. 2 1
      TEAMModelOS/ClientApp/public/theme/dark-theme.css
  29. 25 5
      TEAMModelOS/ClientApp/src/api/ability.js
  30. 6 4
      TEAMModelOS/ClientApp/src/api/http.js
  31. 34 4
      TEAMModelOS/ClientApp/src/api/jyzx.js
  32. 9 3
      TEAMModelOS/ClientApp/src/api/login.js
  33. 16 5
      TEAMModelOS/ClientApp/src/api/schoolSetting.js
  34. 1 1
      TEAMModelOS/ClientApp/src/api/train.js
  35. 9 5
      TEAMModelOS/ClientApp/src/assets/student-web/component_styles/paper-test.css
  36. 142 0
      TEAMModelOS/ClientApp/src/common/BaseAreaList.vue
  37. 20 15
      TEAMModelOS/ClientApp/src/common/BaseCanvas.vue
  38. 2 2
      TEAMModelOS/ClientApp/src/common/BaseClassSelect.vue
  39. 1 1
      TEAMModelOS/ClientApp/src/common/BaseClassSelectPri.vue
  40. 2 2
      TEAMModelOS/ClientApp/src/common/BaseLayout.less
  41. 45 29
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  42. 5 4
      TEAMModelOS/ClientApp/src/common/BaseNotification.vue
  43. 207 0
      TEAMModelOS/ClientApp/src/common/BaseSelectArea.vue
  44. 89 20
      TEAMModelOS/ClientApp/src/common/BaseSelectSchool.vue
  45. 1 1
      TEAMModelOS/ClientApp/src/common/BaseUpload.vue
  46. 50 29
      TEAMModelOS/ClientApp/src/common/BaseUserPoptip.vue
  47. 23 6
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseJudge.vue
  48. 58 8
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseMultiple.vue
  49. 3 3
      TEAMModelOS/ClientApp/src/components/questionnaire/BasePie.vue
  50. 10 9
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseQnForm.less
  51. 202 95
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseQnForm.vue
  52. 47 21
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseQuestionnaire.vue
  53. 26 6
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseSingle.vue
  54. 6 6
      TEAMModelOS/ClientApp/src/components/selflearn/ExerciseList.vue
  55. 1 1
      TEAMModelOS/ClientApp/src/components/selflearn/NewChooseContent.vue
  56. 5 5
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseBar.vue
  57. 8 4
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseEntryBar.vue
  58. 43 37
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseMyTable.vue
  59. 2 2
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseRadar.vue
  60. 3 3
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseScoreRateBar.vue
  61. 5 4
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue
  62. 5 3
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperTest.vue
  63. 3 2
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/composePaper.vue
  64. 9 0
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/HomeView.vue
  65. 6 1
      TEAMModelOS/ClientApp/src/components/syllabus/DragTree.less
  66. 8 5
      TEAMModelOS/ClientApp/src/components/syllabus/DragTree.vue
  67. 11 10
      TEAMModelOS/ClientApp/src/components/vote/BaseVoteForm.less
  68. 260 176
      TEAMModelOS/ClientApp/src/components/vote/BaseVoteForm.vue
  69. 1 0
      TEAMModelOS/ClientApp/src/components/vote/BaseVotePie.vue
  70. 1 1
      TEAMModelOS/ClientApp/src/css/common-style.less
  71. 1 1
      TEAMModelOS/ClientApp/src/css/custom-animate.less
  72. 123 0
      TEAMModelOS/ClientApp/src/css/light-iview-form.less
  73. 5 2
      TEAMModelOS/ClientApp/src/css/site.css
  74. 3 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js
  75. 8 8
      TEAMModelOS/ClientApp/src/locale/lang/en-US/global.js
  76. 2 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/http.js
  77. 19 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/jyzx.js
  78. 2 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/login.js
  79. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/notify.js
  80. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolBaseInfo.js
  81. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/system.js
  82. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/teachContent.js
  83. 26 2
      TEAMModelOS/ClientApp/src/locale/lang/en-US/teachermgmt.js
  84. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/totalAnalysis.js
  85. 2 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/user.js
  86. 6 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/utils.js
  87. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/vote.js
  88. 3 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/cusMgt.js
  89. 2 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/http.js
  90. 19 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/jyzx.js
  91. 3 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/login.js
  92. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/notify.js
  93. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/schoolBaseInfo.js
  94. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/stuAccount.js
  95. 3 3
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/studentWeb.js
  96. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/system.js
  97. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachContent.js
  98. 27 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachermgmt.js
  99. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/user.js
  100. 0 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/utils.js

+ 6 - 6
TEAMModelFunction/ActivityHttpTrigger.cs

@@ -164,7 +164,7 @@ namespace TEAMModelFunction
                                 pk = "Activity",
                                 id = info.id,
                                 code = $"Activity-{x.id}",
-                                type = "exam",
+                                type = "Exam",
                                 name = info.name,
                                 startTime = info.startTime,
                                 endTime = info.endTime,
@@ -190,7 +190,7 @@ namespace TEAMModelFunction
                                 pk = "Activity",
                                 id = info.id,
                                 code = $"Activity-{info.school}-{x.id}",
-                                type = "exam",
+                                type = "Exam",
                                 name = info.name,
                                 startTime = info.startTime,
                                 endTime = info.endTime,
@@ -265,7 +265,7 @@ namespace TEAMModelFunction
                                 pk = "Activity",
                                 id = info.id,
                                 code = $"Activity-{x.id}",
-                                type = "vote",
+                                type = "Vote",
                                 name = info.name,
                                 startTime = info.startTime,
                                 endTime = info.endTime,
@@ -291,7 +291,7 @@ namespace TEAMModelFunction
                                 pk = "Activity",
                                 id = info.id,
                                 code = $"Activity-{info.school}-{x.id}",
-                                type = "vote",
+                                type = "Vote",
                                 name = info.name,
                                 startTime = info.startTime,
                                 endTime = info.endTime,
@@ -365,7 +365,7 @@ namespace TEAMModelFunction
                                 pk = "Activity",
                                 id = info.id,
                                 code = $"Activity-{x.id}",
-                                type = "survey",
+                                type = "Survey",
                                 name = info.name,
                                 startTime = info.startTime,
                                 endTime = info.endTime,
@@ -391,7 +391,7 @@ namespace TEAMModelFunction
                                 pk = "Activity",
                                 id = info.id,
                                 code = $"Activity-{info.school}-{x.id}",
-                                type = "survey",
+                                type = "Survey",
                                 name = info.name,
                                 startTime = info.startTime,
                                 endTime = info.endTime,

+ 9 - 0
TEAMModelFunction/MonitorCosmosDB.cs

@@ -103,6 +103,15 @@ namespace TEAMModelFunction
                                 case "Correct":
                                     TriggerCorrect.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis);
                                     break;
+                                case "ExamLite":
+                                    TriggerExamLite.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis);
+                                    break;
+                                case "Study":
+                                    TriggerStudy.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis);
+                                    break;
+                                case "TeacherWork":
+                                    TriggerWork.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis);
+                                    break;
 
                             }
 

+ 146 - 137
TEAMModelFunction/TriggerExam.cs

@@ -178,181 +178,190 @@ namespace TEAMModelFunction
                             #endregion
                             if (examClassResults.Count == 0)
                             {
-                                foreach (string cla in classes)
+                                try
                                 {
-                                    int m = 0;
-                                    foreach (ExamSubject subject in info.subjects)
+                                    foreach (string cla in classes)
                                     {
-                                        string classCode = "";
-                                        if (string.IsNullOrEmpty(info.school) || !info.scope.Equals("school", StringComparison.OrdinalIgnoreCase))
+                                        int m = 0;
+                                        foreach (ExamSubject subject in info.subjects)
                                         {
-                                            classCode = "ExamClassResult-" + info.creatorId;
-                                        }
-                                        else
-                                        {
-                                            classCode = "ExamClassResult-" + info.school;
-                                        }
-                                        ExamClassResult result = new ExamClassResult
-                                        {
-                                            code = classCode,
-                                            examId = info.id,
-                                            id = Guid.NewGuid().ToString(),
-                                            subjectId = subject.id,
-                                            year = info.year,
-                                            scope = info.scope
-                                        };
-                                        result.info.id = cla;
-                                        List<string> ans = new List<string>();
-                                        List<List<string>> anses = new List<List<string>>();
-                                        List<List<Details>> marks = new List<List<Details>>();
-                                        List<double> ansPoint = new List<double>();
-                                        List<string> ids = new List<string>();
-                                        foreach (double p in info.papers[m].point)
-                                        {
-                                            //Details details = new Details();
-                                            //ans.Add(new List<string>());
-                                            anses.Add(new List<string>());
-                                            marks.Add(new List<Details>());
-                                            ansPoint.Add(-1);
-                                        }
-                                        var sresponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"Class-{info.school}"));
-                                        if (sresponse.Status == 200)
-                                        {
-
-                                            using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
-                                            Class classroom = json.ToObject<Class>();
-                                            School sc = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(info.school, new Azure.Cosmos.PartitionKey("Base"));
-                                            foreach (Period period in sc.period)
+                                            string classCode = "";
+                                            if (string.IsNullOrEmpty(info.school) || !info.scope.Equals("school", StringComparison.OrdinalIgnoreCase))
+                                            {
+                                                classCode = "ExamClassResult-" + info.creatorId;
+                                            }
+                                            else
+                                            {
+                                                classCode = "ExamClassResult-" + info.school;
+                                            }
+                                            ExamClassResult result = new ExamClassResult
                                             {
-                                                if (period.id.Equals(classroom.periodId))
+                                                code = classCode,
+                                                examId = info.id,
+                                                id = Guid.NewGuid().ToString(),
+                                                subjectId = subject.id,
+                                                year = info.year,
+                                                scope = info.scope
+                                            };
+                                            result.info.id = cla;
+                                            List<string> ans = new List<string>();
+                                            List<List<string>> anses = new List<List<string>>();
+                                            List<List<Details>> marks = new List<List<Details>>();
+                                            List<double> ansPoint = new List<double>();
+                                            List<string> ids = new List<string>();
+                                            foreach (double p in info.papers[m].point)
+                                            {
+                                                //Details details = new Details();
+                                                //ans.Add(new List<string>());
+                                                anses.Add(new List<string>());
+                                                marks.Add(new List<Details>());
+                                                ansPoint.Add(-1);
+                                            }
+                                            var sresponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"Class-{info.school}"));
+                                            if (sresponse.Status == 200)
+                                            {
+
+                                                using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
+                                                Class classroom = json.ToObject<Class>();
+                                                School sc = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(info.school, new Azure.Cosmos.PartitionKey("Base"));
+                                                foreach (Period period in sc.period)
                                                 {
-                                                    foreach (Semester semester in period.semesters)
+                                                    if (period.id.Equals(classroom.periodId))
                                                     {
-                                                        if (semester.start == 1)
+                                                        foreach (Semester semester in period.semesters)
                                                         {
-                                                            int year = DateTimeOffset.UtcNow.Year;
-                                                            int month = DateTimeOffset.UtcNow.Month;
-                                                            int day = DateTimeOffset.UtcNow.Day;
-                                                            int time = 0;
-                                                            if (month == semester.month)
+                                                            if (semester.start == 1)
                                                             {
-                                                                time = day >= semester.day ? 0 : 1;
+                                                                int year = DateTimeOffset.UtcNow.Year;
+                                                                int month = DateTimeOffset.UtcNow.Month;
+                                                                int day = DateTimeOffset.UtcNow.Day;
+                                                                int time = 0;
+                                                                if (month == semester.month)
+                                                                {
+                                                                    time = day >= semester.day ? 0 : 1;
+                                                                }
+                                                                else
+                                                                {
+                                                                    time = month > semester.month ? 0 : 1;
+                                                                }
+                                                                int eyear = year - time;
+                                                                result.gradeId = (eyear - classroom.year).ToString();
                                                             }
-                                                            else
-                                                            {
-                                                                time = month > semester.month ? 0 : 1;
-                                                            }
-                                                            int eyear = year - time;
-                                                            result.gradeId = (eyear - classroom.year).ToString();
                                                         }
                                                     }
                                                 }
-                                            }
-                                            //result.info.id = classroom.id;
-                                            result.info.name = classroom.name;
-                                            //result.gradeId = classroom.year.ToString();
-                                            //处理班级人数
-                                            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: $"select c.id from c where c.classId = '{classroom.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Base-{info.school}") }))
-                                            {
-                                                using var json_stu = await JsonDocument.ParseAsync(item.ContentStream);
-                                                if (json_stu.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                                                //result.info.id = classroom.id;
+                                                result.info.name = classroom.name;
+                                                //result.gradeId = classroom.year.ToString();
+                                                //处理班级人数
+                                                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: $"select c.id from c where c.classId = '{classroom.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Base-{info.school}") }))
                                                 {
-                                                    var accounts = json_stu.RootElement.GetProperty("Documents").EnumerateArray();
-                                                    while (accounts.MoveNext())
+                                                    using var json_stu = await JsonDocument.ParseAsync(item.ContentStream);
+                                                    if (json_stu.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                                                     {
-                                                        JsonElement account = accounts.Current;
-                                                        ids.Add(account.GetProperty("id").GetString());
+                                                        var accounts = json_stu.RootElement.GetProperty("Documents").EnumerateArray();
+                                                        while (accounts.MoveNext())
+                                                        {
+                                                            JsonElement account = accounts.Current;
+                                                            ids.Add(account.GetProperty("id").GetString());
+                                                        }
                                                     }
                                                 }
                                             }
-                                        }
-                                        if (info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
-                                        {
-                                            var stuResponse = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"StuList"));
-                                            if (stuResponse.Status == 200)
+                                            if (info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
                                             {
-                                                using var json = await JsonDocument.ParseAsync(stuResponse.ContentStream);
-                                                StuList stuList = json.ToObject<StuList>();
-                                                //result.info.id = stuList.id;
-                                                result.info.name = stuList.name;
-                                                //处理发布对象为自选名单(个人)
-
-                                                foreach (Students stus in stuList.students)
+                                                var stuResponse = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"StuList"));
+                                                if (stuResponse.Status == 200)
                                                 {
+                                                    using var json = await JsonDocument.ParseAsync(stuResponse.ContentStream);
+                                                    StuList stuList = json.ToObject<StuList>();
+                                                    //result.info.id = stuList.id;
+                                                    result.info.name = stuList.name;
+                                                    //处理发布对象为自选名单(个人)
 
-                                                    if (!ids.Contains(stus.id))
+                                                    foreach (Students stus in stuList.students)
                                                     {
-                                                        ids.Add(stus.id);
+
+                                                        if (!ids.Contains(stus.id))
+                                                        {
+                                                            ids.Add(stus.id);
+                                                        }
                                                     }
-                                                }
-                                                if (stuList.tmids.Count > 0)
-                                                {
-                                                    foreach (string tid in stuList.tmids)
+                                                    if (stuList.tmids.Count > 0)
                                                     {
-                                                        ids.Add(tid);
+                                                        foreach (string tid in stuList.tmids)
+                                                        {
+                                                            ids.Add(tid);
+                                                        }
                                                     }
                                                 }
                                             }
-                                        }
-                                        else
-                                        {
-                                            var stuResponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"StuList-{info.school}"));
-                                            if (stuResponse.Status == 200)
+                                            else
                                             {
-                                                using var json = await JsonDocument.ParseAsync(stuResponse.ContentStream);
-                                                StuList stuList = json.ToObject<StuList>();
-                                                //result.info.id = stuList.id;
-                                                result.info.name = stuList.name;
-                                                //处理发布对象为自选名单(校本)
-                                                foreach (Students stus in stuList.students)
+                                                var stuResponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"StuList-{info.school}"));
+                                                if (stuResponse.Status == 200)
                                                 {
-                                                    if (!ids.Contains(stus.id))
+                                                    using var json = await JsonDocument.ParseAsync(stuResponse.ContentStream);
+                                                    StuList stuList = json.ToObject<StuList>();
+                                                    //result.info.id = stuList.id;
+                                                    result.info.name = stuList.name;
+                                                    //处理发布对象为自选名单(校本)
+                                                    foreach (Students stus in stuList.students)
                                                     {
-                                                        ids.Add(stus.id);
+                                                        if (!ids.Contains(stus.id))
+                                                        {
+                                                            ids.Add(stus.id);
+                                                        }
                                                     }
                                                 }
                                             }
-                                        }
-                                        foreach (string stu in ids)
-                                        {
-                                            result.mark.Add(marks);
-                                            result.studentIds.Add(stu);
-                                            result.studentAnswers.Add(ans);
-                                            result.studentScores.Add(ansPoint);
-                                            result.ans.Add(anses);
-                                            result.sum.Add(0);
-                                        }
+                                            foreach (string stu in ids)
+                                            {
+                                                result.mark.Add(marks);
+                                                result.studentIds.Add(stu);
+                                                result.studentAnswers.Add(ans);
+                                                result.studentScores.Add(ansPoint);
+                                                result.ans.Add(anses);
+                                                result.sum.Add(0);
+                                            }
 
-                                        //result.progress = info.progress;
-                                        result.school = info.school;
-                                        m++;
-                                        await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(result, new Azure.Cosmos.PartitionKey($"{result.code}"));
+                                            //result.progress = info.progress;
+                                            result.school = info.school;
+                                            m++;
+                                            await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(result, new Azure.Cosmos.PartitionKey($"{result.code}"));
+                                        }
                                     }
                                 }
-                                // 发送信息通知
-                                var messageEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
-                                messageEnd.ApplicationProperties.Add("name", "Exam");
-                                if (records.Count > 0)
+                                catch (Exception ex)
                                 {
-                                    long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
-                                    records[0].sequenceNumber = end;
-                                    await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
-                                    //await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
+                                    await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测going初始化异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
                                 }
-                                else
-                                {
-                                    long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                                    ChangeRecord changeRecord = new ChangeRecord
+                                finally {
+                                    // 发送信息通知
+                                    var messageEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
+                                    messageEnd.ApplicationProperties.Add("name", "Exam");
+                                    if (records.Count > 0)
                                     {
-                                        RowKey = input.Id,
-                                        PartitionKey = "going",
-                                        sequenceNumber = end,
-                                        msgId = messageEnd.MessageId
-                                    };
-                                    await _azureStorage.Save<ChangeRecord>(changeRecord);
-                                    //await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
-                                }
+                                        long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
+                                        await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
+                                        records[0].sequenceNumber = end;
+                                        await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
+                                        //await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
+                                    }
+                                    else
+                                    {
+                                        long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
+                                        ChangeRecord changeRecord = new ChangeRecord
+                                        {
+                                            RowKey = input.Id,
+                                            PartitionKey = "going",
+                                            sequenceNumber = end,
+                                            msgId = messageEnd.MessageId
+                                        };
+                                        await _azureStorage.Save<ChangeRecord>(changeRecord);
+                                        //await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
+                                    }
+                                }                               
                             }
                             else
                             {

+ 85 - 0
TEAMModelFunction/TriggerExamLite.cs

@@ -0,0 +1,85 @@
+using Azure.Cosmos;
+using HTEXLib.COMM.Helpers;
+using Microsoft.Azure.Documents;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+
+namespace TEAMModelFunction
+{
+    public static class TriggerExamLite
+    {
+        public static async void Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
+                    CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis)
+        {
+            try
+            {
+                if ((tdata.status != null && tdata.status.Value == 404) || tdata.ttl > 0)
+                {
+                    return;
+                }
+                var adid = tdata.id;
+                var adcode = "";
+                string blobcntr = null;
+                if (tdata.scope.Equals("school"))
+                {
+                    adcode = $"Activity-{tdata.school}";
+                    blobcntr = tdata.school;
+                }
+                else
+                {
+                    adcode = $"Activity-{tdata.creatorId}";
+                    blobcntr = tdata.creatorId;
+                }
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修评测活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
+                ExamLite lite = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamLite>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
+                //List<ChangeRecord> voteRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", vote.progress } });
+                if (lite != null)
+                {
+                    (List<TmdInfo> tchList, _) = await TriggerStuActivity.GetTchList(client, _dingDing, lite.tchLists, lite.school);
+                    List<StuActivity> tchActivities = new List<StuActivity>();
+
+                    if (tchList.IsNotEmpty())
+                    {
+                        tchList.ForEach(x =>
+                        {
+                            tchActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = lite.id,
+                                code = $"Activity-{x.id}",
+                                type = "ExamLite",
+                                name = lite.name,
+                                startTime = lite.startTime,
+                                endTime = lite.endTime,
+                                scode = lite.code,
+                                scope = lite.scope,
+                                school = lite.school,
+                                creatorId = lite.creatorId,
+                                subjects = new List<string> { "" },
+                                blob = null,
+                                owner = lite.owner,
+                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
+                                taskStatus = -1,
+                                classIds = lite.tchLists
+                            });
+                        });
+                    }
+                    await TriggerStuActivity.SaveStuActivity(client, _dingDing, null, null, tchActivities);
+
+
+                }
+
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修评测异常{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+            }
+
+        }
+    }
+}

+ 85 - 0
TEAMModelFunction/TriggerStudy.cs

@@ -0,0 +1,85 @@
+using Azure.Cosmos;
+using HTEXLib.COMM.Helpers;
+using Microsoft.Azure.Documents;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+
+namespace TEAMModelFunction
+{
+    public static class TriggerStudy
+    {
+        public static async void Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
+                    CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis)
+        {
+            try
+            {
+                if ((tdata.status != null && tdata.status.Value == 404) || tdata.ttl > 0)
+                {
+                    return;
+                }
+                var adid = tdata.id;
+                var adcode = "";
+                string blobcntr = null;
+                if (tdata.scope.Equals("school"))
+                {
+                    adcode = $"Activity-{tdata.school}";
+                    blobcntr = tdata.school;
+                }
+                else
+                {
+                    adcode = $"Activity-{tdata.creatorId}";
+                    blobcntr = tdata.creatorId;
+                }
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
+                Study study = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Study>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
+                //List<ChangeRecord> voteRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", vote.progress } });
+                if (study != null)
+                {
+                    (List<TmdInfo> tchList,_ ) = await TriggerStuActivity.GetTchList(client, _dingDing, study.tchLists, study.school);
+                    List<StuActivity> tchActivities = new List<StuActivity>();
+
+                    if (tchList.IsNotEmpty())
+                    {
+                        tchList.ForEach(x =>
+                        {
+                            tchActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = study.id,
+                                code = $"Activity-{x.id}",
+                                type = "Study",
+                                name = study.name,
+                                startTime = study.startTime,
+                                endTime = study.endTime,
+                                scode = study.code,
+                                scope = study.scope,
+                                school = study.school,
+                                creatorId = study.creatorId,
+                                subjects = new List<string> { "" },
+                                blob = null,
+                                owner = study.owner,
+                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
+                                taskStatus = -1,
+                                classIds = study.tchLists
+                            });
+                        });
+                    }
+                    await TriggerStuActivity.SaveStuActivity(client, _dingDing, null, null, tchActivities);
+
+
+                }
+
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修活动异常{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+            }
+
+        }
+    }
+}

+ 5 - 4
TEAMModelFunction/TriggerSurvey.cs

@@ -134,14 +134,15 @@ namespace TEAMModelFunction
                                 });
                             }
 
-                            if (survey.tchLists.IsNotEmpty())
+                            (List<TmdInfo> tchList, _) = await TriggerStuActivity.GetTchList(client, _dingDing, survey.tchLists, survey.school);
+                            if (tchList.IsNotEmpty())
                             {
-                                survey.tchLists.ForEach(x => {
+                               tchList.ForEach(x => {
                                     tchActivities.Add(new StuActivity
                                     {
                                         pk = "Activity",
                                         id = survey.id,
-                                        code = $"Activity-{x}",
+                                        code = $"Activity-{x.id}",
                                         type = "Survey",
                                         name = survey.name,
                                         startTime = survey.startTime,
@@ -155,7 +156,7 @@ namespace TEAMModelFunction
                                         owner = survey.owner,
                                         createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                                         taskStatus = -1,
-                                        classIds = classes
+                                        classIds = survey.tchLists
                                     });
                                 });
                             }

+ 8 - 4
TEAMModelFunction/TriggerVote.cs

@@ -139,15 +139,16 @@ namespace TEAMModelFunction
                                     });
                                 });
                             }
-
-                            if (vote.tchLists.IsNotEmpty())
+                           
+                            (List<TmdInfo> tchList, _) = await TriggerStuActivity.GetTchList(client, _dingDing, vote.tchLists, vote.school);
+                            if (tchList.IsNotEmpty())
                             {
-                                vote.tchLists.ForEach(x => {
+                                tchList.ForEach(x => {
                                     tchActivities.Add(new StuActivity
                                     {
                                         pk = "Activity",
                                         id = vote.id,
-                                        code = $"Activity-{x}",
+                                        code = $"Activity-{x.id}",
                                         type = "Vote",
                                         name = vote.name,
                                         startTime = vote.startTime,
@@ -165,6 +166,9 @@ namespace TEAMModelFunction
                                     });
                                 });
                             }
+                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}投票活动,:教研组活动:" +
+                             
+                               $"{tchActivities.ToJsonString()}\n", GroupNames.成都开发測試群組);
                             await TriggerStuActivity.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities, tchActivities);
                             //向学生或醍摩豆账号发起通知
                             #region

+ 85 - 0
TEAMModelFunction/TriggerWork.cs

@@ -0,0 +1,85 @@
+using Azure.Cosmos;
+using HTEXLib.COMM.Helpers;
+using Microsoft.Azure.Documents;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+
+namespace TEAMModelFunction
+{
+    public static class TriggerWork
+    {
+        public static async void Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
+                    CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis)
+        {
+            try
+            {
+                if ((tdata.status != null && tdata.status.Value == 404) || tdata.ttl > 0)
+                {
+                    return;
+                }
+                var adid = tdata.id;
+                var adcode = "";
+                string blobcntr = null;
+                if (tdata.scope.Equals("school"))
+                {
+                    adcode = $"Activity-{tdata.school}";
+                    blobcntr = tdata.school;
+                }
+                else
+                {
+                    adcode = $"Activity-{tdata.creatorId}";
+                    blobcntr = tdata.creatorId;
+                }
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修作业活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
+                TeacherWork work = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<TeacherWork>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
+                //List<ChangeRecord> voteRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", vote.progress } });
+                if (work != null)
+                {
+                    (List<TmdInfo> tchList, _) = await TriggerStuActivity.GetTchList(client, _dingDing, work.tchLists, work.school);
+                    List<StuActivity> tchActivities = new List<StuActivity>();
+
+                    if (tchList.IsNotEmpty())
+                    {
+                        tchList.ForEach(x =>
+                        {
+                            tchActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = work.id,
+                                code = $"Activity-{x.id}",
+                                type = "TeacherWork",
+                                name = work.name,
+                                startTime = work.startTime,
+                                endTime = work.endTime,
+                                scode = work.code,
+                                scope = work.scope,
+                                school = work.school,
+                                creatorId = work.creatorId,
+                                subjects = new List<string> { "" },
+                                blob = null,
+                                owner = work.owner,
+                                createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
+                                taskStatus = -1,
+                                classIds = work.tchLists
+                            });
+                        });
+                    }
+                    await TriggerStuActivity.SaveStuActivity(client, _dingDing, null, null, tchActivities);
+
+
+                }
+
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修作业活动异常{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+            }
+
+        }
+    }
+}

+ 1 - 1
TEAMModelOS.SDK/Extension/Utils.cs

@@ -103,7 +103,7 @@ namespace TEAMModelOS.SDK.Extension
         /// <returns></returns>
         public static (bool, string, int) ImageValidateByStream(Stream stream)
         {
-            int length = 10240;
+            int length = 100000; //100 KB
             byte[] bytes = new byte[length];
             BinaryReader br = new BinaryReader(stream);
             StringBuilder stringBuilder = new StringBuilder();

+ 89 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/ExamLite.cs

@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+
+namespace TEAMModelOS.SDK.Models
+{
+    public class ExamLite : CosmosEntity
+    {
+        public ExamLite()
+        {
+            pk = "ExamLite";
+
+        }
+        /// <summary>
+        ///发布层级 类型 school  area
+        /// </summary>
+        public string owner { get; set; }
+        public string areaId { get; set; }
+        public string name { get; set; }
+        public string school { get; set; }
+        public string creatorId { get; set; }
+        public long createTime { get; set; }
+        public long updateTime { get; set; }
+        //public string examCode { get; set; }
+
+        /// <summary>
+        /// 施测起始时间
+        /// </summary>
+        public long startTime { get; set; }
+        /// <summary>
+        /// 施测结束时间
+        /// </summary>
+        public long endTime { get; set; }
+        /// <summary>
+        /// 评测类型
+        /// </summary>
+        public string source { get; set; }
+        /// <summary>
+        ///  评测描述
+        /// </summary>
+        public string description { get; set; }
+        /// <summary>
+        ///  行政班  
+        /// </summary>
+        public List<string> classes { get; set; } = new List<string>();
+        /// <summary>
+        /// 学生名单(包含自定义个人学生名单,学校教学班)
+        /// </summary>
+        public List<string> stuLists { get; set; } = new List<string>();
+        /// <summary>
+        /// 教研组名单
+        /// </summary>
+        public List<string> tchLists { get; set; } = new List<string>();
+        /// <summary>
+        /// student 学生名单类型    research 教研组名单
+        /// </summary>
+        public string targetType { get; set; }
+        public List<JsonElement> targets { get; set; } = new List<JsonElement>();
+        public List<Record> teachers { get; set; } = new List<Record>();
+        /// <summary>
+        /// TTL删除改变状态使用
+        /// </summary>
+        public int? status { get; set; } = 0;
+        //记录该评测内容下blob大小
+        public long? size { get; set; } = 0;
+        //标记是否研修活动中发起的评测
+        public string sType { get; set; } = "normal";
+        /// <summary>
+        ///  练习的试卷 blob地址
+        /// </summary>
+        public string blob { get; set; }
+        public string pId { get; set; }
+        public string scope { get; set; }
+        //容器名称 container name
+        //public string cn { get; set; }
+    }
+    public class Record
+    {
+        public string id { get; set; }
+        public string name { get; set; }
+        public string groupName { get; set; }
+        public List<List<string>> answer { get; set; } = new List<List<string>>();
+        public List<int> rw { get; set; } = new List<int>();
+        public long time { get; set; }
+    }
+
+}

+ 2 - 3
TEAMModelOS.SDK/Models/Cosmos/Common/StuList.cs

@@ -2,7 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 
-namespace TEAMModelOS.SDK.Models.Cosmos.Common
+namespace TEAMModelOS.SDK.Models
 {
     public class StuList : CosmosEntity
     {
@@ -12,7 +12,6 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         }
         public List<Students> students { get; set; } = new List<Students>();
         public List<string> tmids { get; set; }
-        public List<string> teachers { get; set; }
         public string name { get; set; }
         //标记该名单唯一code
         public string no { get; set; }
@@ -21,7 +20,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         public string school { get; set; }
         public string creatorId { get; set; }
         /// <summary>
-        /// student 学生名单类型  teacher 教师分组名单 , research 教研组名单
+        /// student 学生名单类型
         /// </summary>
         public string type { get; set; } = "student";
     }

+ 16 - 20
TEAMModelOS.SDK/Models/Cosmos/Common/Study.cs

@@ -3,7 +3,7 @@ using System.Collections.Generic;
 using System.Text;
 using System.Text.Json;
 
-namespace TEAMModelOS.SDK.Models.Cosmos.School
+namespace TEAMModelOS.SDK.Models
 {
     public class Study : CosmosEntity
     {
@@ -15,8 +15,6 @@ namespace TEAMModelOS.SDK.Models.Cosmos.School
 
         public string name { get; set; }
         public string school { get; set; }
-        //详细信息
-        public Detail detail { get; set; } = new Detail();
         //高级设置
         public List<string> settings { get; set; } = new List<string>();
         public string creatorId { get; set; }
@@ -57,31 +55,29 @@ namespace TEAMModelOS.SDK.Models.Cosmos.School
         public string owner { get; set; }
         public string areaId { get; set; }
         public string pId { get; set; }
-    }
-    public class Setting {
-        public string id { get; set; }
-        public string name { get; set; }
-        public string groupName { get; set; }
-        public string sign { get; set; }
-        public long signTime { get; set; }
-        public string hw { get; set; }
-        public long hwTime { get; set; }
-        //0未审核 1 通过 2 未通过
-        public int status { get; set; }
-        public long aTime { get; set; }
-    }
-    public class Detail { 
         public string presenter { get; set; }
         public string topic { get; set; }
         public long startTime { get; set; }
         public long endTime { get; set; }
         public string address { get; set; }
+        //培训内容
         public string desc { get; set; }
         public string img { get; set; }
-        public string hwName { get; set; }
-        public string hwDesc { get; set; }
-        public long hwTime { get; set; }
+        public string workId { get; set; }
         public string surveyId { get; set; }
         public string examId { get; set; }
     }
+    public class Setting
+    {
+        public string id { get; set; }
+        public string name { get; set; }
+        public string groupName { get; set; }
+        public string sign { get; set; }
+        public long signTime { get; set; }
+/*        public string hw { get; set; }
+        public long hwTime { get; set; }*/
+        //0未审核 1 通过 2 未通过
+        public int status { get; set; }
+        public long aTime { get; set; }
+    }
 }

+ 2 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Survey.cs

@@ -110,6 +110,8 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public int? status { get; set; } = 0;
         public long? size { get; set; } = 0;
+        public string areaId { get; set; }
+        public string pId { get; set; }
     }
 
     /// <summary>

+ 5 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/TchList.cs

@@ -2,10 +2,14 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 
-namespace TEAMModelOS.SDK.Models.Cosmos.Common
+namespace TEAMModelOS.SDK.Models
 {
    public class TchList : CosmosEntity
     {
+        public TchList()
+        {
+            pk = "TchList";
+        }
         public List<string> teachers { get; set; }
         public string name { get; set; }
         //标记该名单唯一code

+ 2 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Vote.cs

@@ -123,6 +123,8 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public int? status { get; set; } = 0;
         public long? size { get; set; } = 0;
+        public string areaId { get; set; }
+        public string pId { get; set; }
     }
     /// <summary>
     /// 投票选项

+ 28 - 1
TEAMModelOS.SDK/Models/Cosmos/School/Area.cs

@@ -10,12 +10,39 @@ namespace TEAMModelOS.SDK.Models
         {
             pk = "Area";
         }
+        /// <summary>
+        /// 区域级名称
+        /// </summary>
         public string name { get; set; }
-
+        /// <summary>
+        /// 省编码
+        /// </summary>
         public string provCode { get; set; }
+        /// <summary>
+        /// 省名称
+        /// </summary>
         public string provName { get; set; }
+        /// <summary>
+        /// 城市编码
+        /// </summary>
         public string cityCode { get; set; }
+        /// <summary>
+        /// 城市名称
+        /// </summary>
         public string cityName { get; set; }
+        /// <summary>
+        /// 能力点版本
+        /// </summary>
         public string standard { get; set; }
+        /// <summary>
+        /// 能力点名称
+        /// </summary>
+        public string standardName { get; set; }
+        /// <summary>
+        /// 单位
+        /// </summary>
+        public string institution { get; set; }
+
+
     }
 }

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/School/ClassAnalysis.cs

@@ -2,7 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 
-namespace TEAMModelOS.SDK.Models.Cosmos
+namespace TEAMModelOS.SDK.Models
 {
     public class ClassAnalysis
     {

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/School/GradeAnalysis.cs

@@ -2,7 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 
-namespace TEAMModelOS.SDK.Models.Cosmos
+namespace TEAMModelOS.SDK.Models
 {
     public class GradeAnalysis
     {

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/School/SchoolTeacher.cs

@@ -11,7 +11,7 @@ namespace TEAMModelOS.SDK.Models
         public string picture { get; set; }
         public int size { get; set; }
         public string job { get; set; }
-        public List<string> roles { get; set; }
+        public List<string> roles { get; set; } = new List<string>();
         public List<string> permissions { get; set; }
         public string status { get; set; }
         public long createTime { get; set; }

+ 9 - 2
TEAMModelOS.SDK/Models/Cosmos/Teacher/Teacher.cs

@@ -11,13 +11,20 @@ namespace TEAMModelOS.SDK.Models
         public string picture { get; set; }
         public int size { get; set; }
         public string defaultSchool { get; set; }
-        public List<School> schools { get; set; }
-        public class School
+        public List<TeacherSchool> schools { get; set; }= new List<TeacherSchool>();
+        public List<TeacherArea> areas { get; set; } = new List<TeacherArea>();
+        public class TeacherSchool
         {
             public string schoolId { get; set; }
             public string name { get; set; }
             public string status { get; set; }
             public long time { get; set; }
         }
+        public class TeacherArea
+        {
+            public string areaId { get; set; }
+            public string name { get; set; }
+            public string status { get; set; }
+        }
     }
 }

+ 110 - 0
TEAMModelOS.SDK/Models/Cosmos/Teacher/TeacherWork.cs

@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Text;
+using System.Text.Json;
+using TEAMModelOS.SDK.Context.Attributes.Azure;
+
+
+namespace TEAMModelOS.SDK.Models
+{
+    /// <summary>
+    /// 教师作业活动
+    /// </summary>    
+    public class TeacherWork : CosmosEntity
+    {
+        public TeacherWork() {
+            pk = "TeacherWork";
+            classes = new List<string>();
+            stuLists = new List<string>();
+            tchLists = new List<string>();
+        }
+        /// <summary> 
+        ///发布层级 类型 school  teacher
+        /// </summary>
+
+        /// <summary>
+        /// 学校编码或教室tmdid
+        /// </summary>
+        [Required(ErrorMessage = "owner 必须设置")]
+        public string owner { get; set; }
+      
+        public string school { get; set; }
+        /// <summary>
+        /// 作业名称
+        /// </summary>
+        [Required(ErrorMessage = "name 必须设置")]
+        public string name { get; set; }
+        /// <summary>
+        ///  作业内容
+        /// </summary>
+        public string description { get; set; }
+        /// <summary>
+        /// 创建者的id 
+        /// </summary>
+        [Required(ErrorMessage = "creatorId 必须设置")]
+        public string creatorId { get; set; }
+        // public int year { get; set; }
+        /// <summary>
+        /// pending 待发布|going 已发布|finish 已结束
+        /// </summary>
+        //[Required(ErrorMessage = "progress 必须设置")]
+        public string progress { get; set; }
+        public string scope { get; set; }
+
+        //public List<string> tmdids { get; set; } = new List<string>();
+        /// <summary>
+        ///  行政班  
+        /// </summary>
+        public List<string> classes { get; set; } = new List<string>();
+        /// <summary>
+        /// 学生名单(包含自定义个人学生名单,学校教学班)
+        /// </summary>
+        public List<string> stuLists { get; set; } = new List<string>();
+        /// <summary>
+        /// 教研组名单
+        /// </summary>
+        public List<string> tchLists { get; set; } = new List<string>();
+        /// <summary>
+        /// student 学生名单类型    research 教研组名单
+        /// </summary>
+        public string targetType { get; set; }
+        /// <summary>
+        /// 发布对象全部信息。由前端操作,用于前端回显发布对象的格式。
+        /// </summary>
+        public List<JsonElement> targets { get; set; } = new List<JsonElement>();
+        /// <summary>
+        ///class行政班/teach教学班
+        /// </summary>
+        //public string classType { get; set; }
+        /// <summary>
+        /// 开始时间
+        /// </summary>
+        public long startTime { get; set; }
+
+        /// <summary>
+        /// 结束时间
+        /// </summary>
+        public long endTime { get; set; }
+        public long createTime { get; set; } // 作业发布时间
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        public long updateTime { get; set; }
+        public string  blob { get; set; }
+        /// <summary>
+        /// TTL删除改变状态使用
+        /// </summary>
+        public int? status { get; set; } = 0;
+        public long? size { get; set; } = 0;
+        public string areaId { get; set; }
+        public List<Submits> teachers { get; set; } = new List<Submits>();
+    }
+    public class Submits {
+        public string id { get; set; }
+        //public string name { get; set; }
+        //记录作业上传内容
+        public string hw { get; set; }
+        public long hwTime { get; set; }
+    }
+}

+ 30 - 0
TEAMModelOS.SDK/Models/Service/ExamService.cs

@@ -1,6 +1,9 @@
+using Azure.Cosmos;
 using System;
 using System.Collections.Generic;
 using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
 
 namespace TEAMModelOS.SDK.Models.Service
 {
@@ -32,5 +35,32 @@ namespace TEAMModelOS.SDK.Models.Service
                 return classes;
             }
         }
+        public static async Task<string> saveMoreAsync(CosmosClient client, DingDing _dingDing, ExamLite trExam)
+        {
+            try
+            {
+                trExam.ttl = -1;
+                trExam.code = "ExamLite-" + trExam.school;
+                long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                trExam.createTime = now;
+
+                if (string.IsNullOrEmpty(trExam.id))
+                {
+                    trExam.id = Guid.NewGuid().ToString();
+                    await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(trExam, new PartitionKey($"{trExam.code}"));
+                }
+                else
+                {
+                    await client.GetContainer("TEAMModelOS", "Common").UpsertItemAsync(trExam, new PartitionKey($"{trExam.code}"));
+                }
+                return trExam.id;
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ExamService-saveMore\n{e.Message}{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
+                return "";
+
+            }
+        }
     }
 }

+ 1 - 1
TEAMModelOS.SDK/Models/Service/StuListService.cs

@@ -129,7 +129,7 @@ namespace TEAMModelFunction
                             id = activity.id,
                             scode = activity.code,
                             name = activity.name,
-                            code = $"Activity-{ activity.school}-{tch}",
+                            code = $"Activity-{tch}",
                             scope = activity.scope,
                             school = activity.school,
                             creatorId = activity.creatorId,

+ 40 - 0
TEAMModelOS.SDK/Models/Service/SurveyService.cs

@@ -0,0 +1,40 @@
+using Azure.Cosmos;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+
+namespace TEAMModelOS.SDK.Models.Service
+{
+    public static class SurveyService
+    {
+        public static async Task<string> saveMoreAsync(CosmosClient client, DingDing _dingDing, Survey survey)
+        {
+            try
+            {
+                survey.ttl = -1;
+                survey.code = "Survey-" + survey.school;
+                long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                survey.createTime = now;
+
+                if (string.IsNullOrEmpty(survey.id))
+                {
+                    survey.id = Guid.NewGuid().ToString();
+                    await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(survey, new PartitionKey($"{survey.code}"));
+                }
+                else
+                {
+                    await client.GetContainer("TEAMModelOS", "Common").UpsertItemAsync(survey, new PartitionKey($"{survey.code}"));
+                }
+                return survey.id;
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-SurveyService-saveMore\n{e.Message}{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
+                return "";
+
+            }
+        }
+    }
+}

+ 40 - 0
TEAMModelOS.SDK/Models/Service/TeacherWorkService.cs

@@ -0,0 +1,40 @@
+using Azure.Cosmos;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+
+namespace TEAMModelOS.SDK.Models.Service
+{
+	public static class TeacherWorkService
+	{
+        public static async Task<string> saveMoreAsync(CosmosClient client, DingDing _dingDing, TeacherWork work)
+        {
+            try
+            {
+                work.ttl = -1;
+                work.code = "TeacherWork-" + work.school;
+                long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                work.createTime = now;
+
+                if (string.IsNullOrEmpty(work.id))
+                {
+                    work.id = Guid.NewGuid().ToString();
+                    await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(work, new PartitionKey($"{work.code}"));
+                }
+                else
+                {
+                    await client.GetContainer("TEAMModelOS", "Common").UpsertItemAsync(work, new PartitionKey($"{work.code}"));
+                }
+                return work.id;
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-TeacherWorkService-saveMore\n{e.Message}{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
+                return "";
+
+            }
+        }
+    }
+}

+ 130 - 40
TEAMModelOS.SDK/Models/Service/TriggerStuActivity.cs

@@ -28,8 +28,9 @@ namespace TEAMModelOS.SDK
                 using var da = await JsonDocument.ParseAsync(aactivity.ContentStream);
                 activity = da.ToObject<MQActivity>();
             }
-            catch (CosmosException ex)
+            catch (CosmosException )
             {
+                activity=null;
             }
             if (activity != null)
             {
@@ -110,7 +111,7 @@ namespace TEAMModelOS.SDK
                 }
                 if (tchActivities.IsNotEmpty())
                 {
-                    foreach (var x in tmdActivities)
+                    foreach (var x in tchActivities)
                     {
                         await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(x, new PartitionKey(x.code));
                     }
@@ -150,6 +151,12 @@ namespace TEAMModelOS.SDK
                             //item.from = "SchStuList";
                             classInfos.Add(item);
                         }
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ClassInfo>(queryText: $"select c.id,c.name from c where c.id in ({sql})",
+                        requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"TchList-{school}") }))
+                        {
+                            //item.from = "SchStuList";
+                            classInfos.Add(item);
+                        }
                     }
                     List<StuList> tchLists = new List<StuList>();
                     await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<ClassInfo>(queryText: $"select c.id,c.name from c where c.id in ({sql})",
@@ -215,10 +222,7 @@ namespace TEAMModelOS.SDK
                     {
                         tmdids.AddRange(x.tmids);
                     }
-                    if (x.teachers.IsNotEmpty())
-                    {
-                        tmdids.AddRange(x.teachers);
-                    }
+                   
                     classes.Remove(x.id);
                 }
                 foreach (var x in tchLists)
@@ -272,7 +276,6 @@ namespace TEAMModelOS.SDK
                             stuInfos.Add(item);
                         }
                     }
-                    
                 }
                 students.ForEach(x =>
                 {
@@ -304,16 +307,6 @@ namespace TEAMModelOS.SDK
                             }
                         });
                     }
-                    if (x.teachers.IsNotEmpty())
-                    {
-                        x.teachers.ForEach(y => {
-                            var tmdinfo = tmdinfos.Where(z => z.id.Equals(y)).FirstOrDefault();
-                            if (tmdinfo != null)
-                            {
-                                classListInfo.tmdInfos.Add(tmdinfo);
-                            }
-                        });
-                    }
                     classInfo.Add(classListInfo);
                 });
                 tchLists.ForEach(x => {
@@ -360,9 +353,97 @@ namespace TEAMModelOS.SDK
             }
             return (null, null, null);
         }
-        public static async Task<(List<TmdInfo> tmdinfos, List<StuInfo> students,List<ClassListInfo>classInfo)> GetStuList(CosmosClient client, DingDing _dingDing, List<string> claes, string school)
+        public static async Task<(List<TmdInfo> tmdinfos, List<ClassListInfo> classInfo)> GetTchList(CosmosClient client, DingDing _dingDing, List<string> claes, string school)
         {
-            try {
+            try
+            {
+                List<TmdInfo> tmdinfos = new List<TmdInfo>();
+                List<ClassListInfo> classInfo = new List<ClassListInfo>();
+                if (claes.Count == 1 && claes.First().Equals("default"))
+                {
+                    List<TmdInfo> infos = new List<TmdInfo>();
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<TmdInfo>(queryText: $"SELECT  value(c) FROM c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school}") }))
+                    {
+                        infos.Add(item);
+                    }
+                    tmdinfos.AddRange(infos);
+                    classInfo.Add(new ClassListInfo { id = "default",name= "default", tmdInfos = infos });
+                }
+                else {
+                    List<string> classes = new List<string>();
+                    foreach (string ss in claes)
+                    {
+                        classes.Add(ss);
+                    }
+
+                    List<string> tmdids = new List<string>();
+                    List<StuInfo> stuInfos = new List<StuInfo>();
+                    if (!classes.IsNotEmpty()) { return (tmdinfos, null); }
+                    List<string> sqlList = new List<string>();
+                    classes.ForEach(x => { sqlList.Add($" '{x}' "); });
+                    string sql = string.Join(" , ", sqlList);
+                    List<TchList> tchLists = new List<TchList>();
+
+                    if (!string.IsNullOrEmpty(school))
+                    {
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<TchList>(queryText: $"select value(c) from c where c.id in ({sql})",
+                        requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"TchList-{school}") }))
+                        {
+                            tchLists.Add(item);
+                        }
+
+                    }
+                    foreach (var x in tchLists)
+                    {
+
+                        if (x.teachers.IsNotEmpty())
+                        {
+                            tmdids.AddRange(x.teachers);
+                        }
+                        classes.Remove(x.id);
+                    }
+
+                    if (tmdids.IsNotEmpty())
+                    {
+                        List<TmdInfo> infos = new List<TmdInfo>();
+                        List<string> inids = new List<string>();
+                        tmdids.ForEach(x => { inids.Add($"'{x}'"); });
+                        var insql = string.Join(",", inids);
+                        var queryslt = $"SELECT  value(c) FROM c where c.id in ({insql})";
+                        //合并代码/
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<TmdInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
+                        {
+                            infos.Add(item);
+                        }
+                        tmdinfos.AddRange(infos);
+                    }
+                    tchLists.ForEach(x => {
+                        ClassListInfo classListInfo = new ClassListInfo { id = x.id, name = x.name };
+                        if (x.teachers.IsNotEmpty())
+                        {
+                            x.teachers.ForEach(y => {
+                                var tmdinfo = tmdinfos.Where(z => z.id.Equals(y)).FirstOrDefault();
+                                if (tmdinfo != null)
+                                {
+                                    classListInfo.tmdInfos.Add(tmdinfo);
+                                }
+                            });
+                        }
+                        classInfo.Add(classListInfo);
+                    });
+                }
+                return (tmdinfos,  classInfo);
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-OS,TriggerStuActivity-GetStuList\n{ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
+            }
+            return (null,  null);
+        }
+        public static async Task<(List<TmdInfo> tmdinfos, List<StuInfo> students, List<ClassListInfo> classInfo)> GetStuList(CosmosClient client, DingDing _dingDing, List<string> claes, string school)
+        {
+            try
+            {
                 List<string> classes = new List<string>();
                 foreach (string ss in claes)
                 {
@@ -372,13 +453,14 @@ namespace TEAMModelOS.SDK
                 List<Students> studentss = new List<Students>();
                 List<string> tmdids = new List<string>();
                 List<StuInfo> stuInfos = new List<StuInfo>();
-                if (!classes.IsNotEmpty()) { return (tmdinfos, new List<StuInfo>(),null); }
+                if (!classes.IsNotEmpty()) { return (tmdinfos, new List<StuInfo>(), null); }
                 List<string> sqlList = new List<string>();
                 classes.ForEach(x => { sqlList.Add($" '{x}' "); });
                 string sql = string.Join(" , ", sqlList);
                 List<StuList> schList = new List<StuList>();
                 List<Student> students = new List<Student>();
-                if (!string.IsNullOrEmpty(school)) {
+                if (!string.IsNullOrEmpty(school))
+                {
                     await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<StuList>(queryText: $"select value(c) from c where c.id in ({sql})",
                     requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"StuList-{school}") }))
                     {
@@ -396,8 +478,9 @@ namespace TEAMModelOS.SDK
                 {
                     tchLists.Add(item);
                 }
-                
-                foreach (var x  in schList) {
+
+                foreach (var x in schList)
+                {
                     if (x.students.IsNotEmpty())
                     {
                         studentss.AddRange(x.students);
@@ -408,9 +491,10 @@ namespace TEAMModelOS.SDK
                     }
                     classes.Remove(x.id);
                 }
-                foreach (var x in tchLists) 
+                foreach (var x in tchLists)
                 {
-                    if (x.students.IsNotEmpty()) {
+                    if (x.students.IsNotEmpty())
+                    {
                         studentss.AddRange(x.students);
                     }
                     if (x.tmids.IsNotEmpty())
@@ -420,7 +504,8 @@ namespace TEAMModelOS.SDK
                     classes.Remove(x.id);
                 }
 
-                if (tmdids.IsNotEmpty()) {
+                if (tmdids.IsNotEmpty())
+                {
                     List<TmdInfo> infos = new List<TmdInfo>();
                     List<string> inids = new List<string>();
                     tmdids.ForEach(x => { inids.Add($"'{x}'"); });
@@ -433,9 +518,11 @@ namespace TEAMModelOS.SDK
                     }
                     tmdinfos.AddRange(infos);
                 }
-                if (studentss.IsNotEmpty()) {
+                if (studentss.IsNotEmpty())
+                {
                     List<string> inidstus = new List<string>();
-                    foreach (Students stu in studentss) {
+                    foreach (Students stu in studentss)
+                    {
                         var querystu = $"SELECT  c.id,c.code,c.name,c.picture,c.classId,c.year,c.schoolId FROM c where c.id = '{stu.id}'";
                         await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryIterator<StuInfo>(queryText: querystu, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{stu.code}") }))
                         {
@@ -452,17 +539,20 @@ namespace TEAMModelOS.SDK
                 }
                 students.ForEach(x =>
                 {
-                    if (!stuInfos.Select(y => y.classId).ToList().Contains(x.id)) {
-                        stuInfos.Add(new StuInfo { id = x.id, code = x.code, schoolId = x.schoolId, classId = x.classId, name = x.name, picture = x.picture, year = x.year,groupId=x.groupId,groupName=x.groupName,no=x.no });
+                    if (!stuInfos.Select(y => y.classId).ToList().Contains(x.id))
+                    {
+                        stuInfos.Add(new StuInfo { id = x.id, code = x.code, schoolId = x.schoolId, classId = x.classId, name = x.name, picture = x.picture, year = x.year, groupId = x.groupId, groupName = x.groupName, no = x.no });
                     }
                 });
                 List<ClassListInfo> classInfo = new List<ClassListInfo>();
                 schList.ForEach(x => {
-                    ClassListInfo classListInfo = new ClassListInfo {id=x.id,name=x.name };
-                    if (x.students.IsNotEmpty()) {
+                    ClassListInfo classListInfo = new ClassListInfo { id = x.id, name = x.name };
+                    if (x.students.IsNotEmpty())
+                    {
                         x.students.ForEach(y => {
-                            var stuinfo= stuInfos.Where(z => z.id.Equals(y.id)).FirstOrDefault();
-                            if (stuinfo != null) {
+                            var stuinfo = stuInfos.Where(z => z.id.Equals(y.id)).FirstOrDefault();
+                            if (stuinfo != null)
+                            {
                                 classListInfo.stuInfos.Add(stuinfo);
                             }
                         });
@@ -506,22 +596,22 @@ namespace TEAMModelOS.SDK
 
 
                 //var classeids= students.GroupBy(x => x.classId).Select(x => x.Key).ToList();
-                List<ClassInfo> classInfos= await  GetClassInfo(client, _dingDing, classes, school);
+                List<ClassInfo> classInfos = await GetClassInfo(client, _dingDing, classes, school);
                 classInfos.ForEach(x =>
                 {
                     ClassListInfo classListInfo = new ClassListInfo { id = x.id, name = x.name };
-                    var list= students.Where(y => y.classId .Equals(x.id)).ToList();
-                    list.ForEach(z => { classListInfo.stuInfos.Add(new StuInfo { id = z.id, code = z.code, schoolId = z.schoolId, classId = z.classId, name = z.name, picture = z.picture, year = z.year ,groupId=z.groupId,groupName=z.groupName,no=z.no}); });
+                    var list = students.Where(y => y.classId.Equals(x.id)).ToList();
+                    list.ForEach(z => { classListInfo.stuInfos.Add(new StuInfo { id = z.id, code = z.code, schoolId = z.schoolId, classId = z.classId, name = z.name, picture = z.picture, year = z.year, groupId = z.groupId, groupName = z.groupName, no = z.no }); });
                     classInfo.Add(classListInfo);
                 });
-                
-                return (tmdinfos, stuInfos, classInfo) ;
+
+                return (tmdinfos, stuInfos, classInfo);
             }
             catch (Exception ex)
             {
                 await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-OS,TriggerStuActivity-GetStuList\n{ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
             }
-                return (null, null,null);
+            return (null, null, null);
         }
     }
     public class ClassListInfo

+ 1 - 1
TEAMModelOS.SDK/TEAMModelOS.SDK.csproj

@@ -11,7 +11,7 @@
 
 
   <ItemGroup>
-    <PackageReference Include="HTEXLib" Version="5.2108.27" />
+    <PackageReference Include="HTEXLib" Version="5.2109.6" />
     <PackageReference Include="AspectCore.Extensions.Reflection" Version="2.2.0" />
     <PackageReference Include="Azure.Cosmos" Version="4.0.0-preview3" />
     <PackageReference Include="Azure.Identity" Version="1.4.0" />

+ 2 - 1
TEAMModelOS/ClientApp/public/theme/dark-theme.css

@@ -17,7 +17,7 @@
     --primary-text-color: #303030; /* 文本主颜色 */
     --second-text-color: #757575; /* 文本副颜色 */
 
-    --border-color: #f1f1f1; /*边框颜色*/
+    --border-color: #d5d5d5; /*边框颜色*/
     
     --label-text-color: #a5a5a5; /*标签颜色*/
 
@@ -27,6 +27,7 @@
     --normal-icon-color: #40A8F0; /* Icon基本颜色 */
 
     --tabs-bottom-color: #006ee6; /* tab切换,底部颜色,左边时,padding-left = 10px */
+    --tabs-text-color: #303030; /* tab切换,底部颜色,左边时,padding-left = 10px */
 
     --card-shadow: #ececec; /* 卡片阴影 */
 

+ 25 - 5
TEAMModelOS/ClientApp/src/api/ability.js

@@ -69,18 +69,30 @@ export default {
 	},
 	/* 评测相关 */
 	getExamList:function (data) {
-		return post('/common/TrExam/find', data)
+		return post('/common/ExamLite/find', data)
 	},
 	getExamSummary:function (data) {
-		return post('/common/TrExam/find-summary', data)
+		return post('/common/ExamLite/find-summary', data)
 	},
 	saveExam:function (data) {
-		return post('/common/TrExam/save', data)
+		return post('/common/ExamLite/save', data)
 	},
 	deleteExam:function (data) {
-		return post('/common/TrExam/delete', data)
+		return post('/common/ExamLite/delete', data)
+	},
+	//作业相关
+	saveWork:function (data) {
+		return post('/common/work/save', data)
+	},
+	deleteWork:function (data) {
+		return post('/common/work/delete', data)
+	},
+	getWorkList:function (data) {
+		return post('/common/work/find', data)
+	},
+	getWorkSummary:function (data) {
+		return post('/common/work/find-summary', data)
 	},
-    
 	//数据统计API
 	FindTotalData: function (data) {
 		return post('/research/ability/get-subs-statistics', data)
@@ -103,6 +115,14 @@ export default {
 		return post('/school/area/save-vote', data)
 	},
 	
+	getAreaVoteById(data){
+		return post('/school/area/find-vote-id', data)
+	},
+	
+	getAreaSurveyById(data){
+		return post('/school/area/find-survey-id', data)
+	},
+	
 	getAreaVotes(data){
 		return post('/school/area/find-all-vote', data)
 	},

+ 6 - 4
TEAMModelOS/ClientApp/src/api/http.js

@@ -8,7 +8,8 @@ const NO_ACCESS_API = [
     '/oauth2/login',
     '/oauth2/token',
     '/teacher/init/get-school-list',
-    '/student/login'
+    '/student/login',
+    '/area/lang'
 ]
 const NO_AUTH_API = [
     '/teacher/init/get-teacher-info',
@@ -112,8 +113,9 @@ axios.interceptors.response.use(
         return response
     },
     error => {
-        console.log(error)
-        if (error.response && error.response.status === 401) {
+		if(!error.response){
+			Message.error(app.$t('http.error'))
+		}else if (error.response && error.response.status === 401) {
             localStorage.clear()
             window.location.href = window.location.origin + '/login'
             Message.error(app.$t('http.error401'))
@@ -122,7 +124,7 @@ axios.interceptors.response.use(
         } else if (error.response.status === 404) {
             Message.error(app.$t('http.error404'))
         } else {
-            Message.error(app.$t('http.error'))
+            Message.error(app.$t('http.error400'))
         }
         return Promise.reject(error)
     }

+ 34 - 4
TEAMModelOS/ClientApp/src/api/jyzx.js

@@ -71,13 +71,13 @@ export default {
     getcurrents: function (data) {
         return post('/common/TrSurvey/find-summary-by-teacher', data)
     },
-    //提交问卷
+    /* //提交问卷
     submitquestionnaire: function (data) {
-        return post('/common/TrSurvey/record-in', data)
-    },
+        return post('/common/survey/answer', data)
+    }, */
     //提交评测
     submitExam: function (data) {
-        return post('/common/TrExam/record-in',data)
+        return post('/common/ExamLite/record-in',data)
     },
     // 投票列表
     getVoteList: function (data) {
@@ -95,4 +95,34 @@ export default {
     getTeamclass: function (data) {
         return post('/research/class-video/get-group',data)
     },
+
+    // 获取所有活动
+    getAllActivity: function (data) {
+        return post("/teacher/tec-activity", data)
+    },
+
+    // 删除不存在的投票和问卷
+    delActivity: function (data) {
+        return post("/teacher/delete-activity", data)
+    },
+
+    // 查询投票信息
+    getVoteInfo: function (data) {
+        return post('/common/vote/find-id', data)
+    },
+
+    //提交投票结果数据
+    sendVoteResult: function (data) {
+        return post('/common/vote/decide', data)
+    },
+
+    //查詢學生端问卷活动
+    getSurveyInfo: function (data) {
+        return post('/common/survey/find-id', data)
+    },
+
+    //查詢學生端问卷活动
+    answerSurvey: function (data) {
+        return post('/common/survey/answer', data)
+    },
 }

+ 9 - 3
TEAMModelOS/ClientApp/src/api/login.js

@@ -59,6 +59,8 @@ export default {
 			localStorage.setItem("expires_in", item.expires_in)
 			// 輸出暫存
 			let result;
+			let areas = []
+			let toArea = false
 
 			// 取得登入者基本資訊
 			let id_token = item.id_token
@@ -73,11 +75,14 @@ export default {
 				localStorage.setItem("auth_token", res.auth_token)
 				localStorage.setItem("location", res.location)
 				store.dispatch('user/setUserProfile', res)
+				areas = res.areas
 				result = res
+				console.log(res)
 			}).catch(err => {
 				console.log(err)
 			})
-			let hasJoinSchool = result.schools && result.schools.length && result.schools.filter(i => i.status === 'join').length
+			console.log(areas)
+			let hasJoinSchool = result.schools && result.schools.length && result.schools.find(i => i.status === 'join')
 			let joinSchools = hasJoinSchool ? result.schools.filter(i => i.status === 'join') : []
 			let defaultschool = schoolcode != '' ? schoolcode : result.defaultschool ? result.defaultschool : (joinSchools.length ? joinSchools[0].schoolId : null)
 			let authByUser = jwtDecode(result.auth_token)
@@ -88,6 +93,8 @@ export default {
 				permissions: authByUser.permissions == null ? [] : authByUser.permissions,
 				picture: t_Data.picture ? t_Data.picture : ''
 			}
+			
+			info.toArea = areas.length && !joinSchools.length
 
 			if (defaultschool != null) {
 				// 取得使用者的在該學校的設定檔
@@ -104,7 +111,6 @@ export default {
 						store.dispatch('user/setSchoolProfile', res)
 						result = res
 					}
-
 				}).catch(err => {
 					console.log(err)
 				})
@@ -114,7 +120,7 @@ export default {
 				info.defaultschool = defaultschool
 				info.permissions = authBySchool.permissions == null ? [] : authBySchool.permissions
 			}
-
+			console.log(info)
 			resolve(info)
 		})
 	},

+ 16 - 5
TEAMModelOS/ClientApp/src/api/schoolSetting.js

@@ -35,11 +35,6 @@ export default {
         return post('/teacher/init/get-teacher-info', data)
     },
 
-    // 取得老師所在學校相關數據
-    getTeacherSchoolInfo: function (data) {
-        return post('/teacher/init/get-school-info', data)
-    },
-
     // 取得數據中心當前所有學校名單
     getSchoolList: function (data) {
         data = (data == null) ? {} : data
@@ -89,4 +84,20 @@ export default {
 	setDefaultSch:function (data) {
         return post('/teacher/init/set-teacher-info', data)
     },
+    //转让管理员身份
+    TransferAdminRole:function (data) {
+        return post('/teacher/init/set-teacher-info', data)
+    },
+    // 查询教研组
+    FindTchGroup:function (data) {
+        return post('/tchlist/get-research-list', data)
+    },
+    // 创建或修改教研组
+    UpsertTchGroup:function (data) {
+        return post('/tchlist/upsert-list', data)
+    },
+    // 删除教研组
+    DelTchGroup:function (data) {
+        return post('/tchlist/delete-list', data)
+    },
 }

+ 1 - 1
TEAMModelOS/ClientApp/src/api/train.js

@@ -26,7 +26,7 @@ export default {
     },
     // 上传作业
     uploadHw: function (data) {
-        return post("/common/study/upload", data)
+        return post("/common/work/record-in", data)
     },
     // 签到
     signIn: function (data) {

+ 9 - 5
TEAMModelOS/ClientApp/src/assets/student-web/component_styles/paper-test.css

@@ -118,13 +118,13 @@
 .lesson-test-pop .myProgressBar {
   position: fixed;
   right: 14%;
-  top: -40px;
+  top: -5px;
   width: 10%;
 }
 .lesson-test-pop .myTestProgresstitle {
-    left: -30%;
+    /* right: -69%; */
     z-index: 3;
-    top: 40px;
+    top: -25px;
     position: relative;
     font-weight: 900;
     font-size: 10pt;
@@ -132,7 +132,8 @@
 }
 .lesson-test-pop .submitBtn {
   outline: none;
-  width: 100px;
+  min-width: 100px;
+  padding: 0 10px;
   position: absolute;
   height: 24px;
   right: 36px;
@@ -143,6 +144,7 @@
   border-radius: 15px;
   background: transparent;
   color: #6d7278;
+  z-index: 4;
 }
 .lesson-test-pop .messageCardIcon {
   font-size: 40px;
@@ -189,9 +191,11 @@
   color: #6d7278;
   border-radius: 5px;
   text-align: center;
-  max-width: 100px;
+  min-width: 100px;
   margin-bottom: 5px;
   /*margin-top: 20px;*/
+  display: inline-block;
+  padding: 0 10px;
 }
 .lesson-test-pop .questioDes {
     margin-top: 20px;

+ 142 - 0
TEAMModelOS/ClientApp/src/common/BaseAreaList.vue

@@ -0,0 +1,142 @@
+<template>
+	<div class="base-area-select">
+		<div v-if="!areaList.length"></div>
+		<Dropdown @on-click="onAreaSelect" v-else>
+			<!-- <img class="school-logo" src="https://teammodelstorage.blob.core.chinacloudapi.cn/0-public/image/%E5%B0%91%E5%9F%8E%E6%A0%A1%E5%BE%BD.jpg" /> -->
+			<a href="javascript:void(0)"
+				:class="['base-user-post']">
+				{{ areaList[curAreaIndex].name }}
+				<Icon type="ios-arrow-down"></Icon>
+			</a>
+			<DropdownMenu slot="list">
+				<div v-for="(item,index) in areaList" :key="index">
+					<DropdownItem :name="index">
+						<div class="school-item">
+							<span>{{ item.name }}</span>
+						</div>
+					</DropdownItem>
+				</div>
+			</DropdownMenu>
+		</Dropdown>
+	</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				curSchool: {
+					logo: ''
+				},
+				defaultLogo: '',
+				user: {
+					schools: []
+				},
+				joinSchools: [],
+				areaList:[],
+				curAreaIndex:0
+			}
+		},
+		created() {
+			this.defaultLogo = require('@/assets/icon/default_school.png')
+			// 获取本地存储中的 用户信息
+			let user = JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8"));
+			let schoolProfile = localStorage.school_profile ? JSON.parse(decodeURIComponent(localStorage.school_profile,
+				"utf-8")) : undefined;
+			this.user.schools = user.schools
+			let joinSchools = user.schools && user.schools.length ? user.schools.filter(i => i.status === 'join') : null
+			this.joinSchools = joinSchools
+			this.areaList = user.areas
+			this.onAreaSelect(0)
+
+		},
+		methods: {
+			onAreaSelect(val){
+				this.curAreaIndex = val
+				sessionStorage.setItem('areaId',this.areaList[this.curAreaIndex].areaId)
+				sessionStorage.setItem('areaName',this.areaList[this.curAreaIndex].name)
+				this.$EventBus.$emit('onGlobalLoading', true)
+				this.$EventBus.$emit('onSwitchArea')
+				setTimeout(() => {
+					this.$EventBus.$emit('onGlobalLoading', false)
+				}, 500)
+				this.$router.push({
+					name: 'area'
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="less">
+	.base-area-select {
+		margin-left: 20px;
+		font-size: 20px;
+		font-weight: bold;
+		color: #fff;
+		// font-family: 'NotoSerif', '微软正黑体', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Sans-serif;
+		.ivu-dropdown {
+			.ivu-select-dropdown {
+				width: max-content;
+				width: -webkit-max-content;
+				left: -35%;
+			}
+
+			.ivu-dropdown-item:hover {
+				background: #83d7ff;
+			}
+
+			a {
+				color: var(--primary-textColor) !important;
+
+				&:hover {
+					color: var(--primary-textColor) !important;
+				}
+
+				.ivu-icon {
+					display: none;
+				}
+
+				&::after {
+					content: '';
+					display: inline-block;
+					width: 0;
+					height: 0;
+					border-right: solid 8px transparent;
+					border-left: solid 8px transparent;
+					border-top: solid 8px #d0d0d0;
+					margin-left: 8px;
+					margin-bottom: 3px;
+				}
+
+			}
+		}
+
+		.single-school {
+			&::after {
+				display: none !important;
+			}
+
+		}
+
+		.school-logo {
+			width: 30px;
+			border-radius: 50%;
+			margin-right: 10px;
+			margin-bottom: 5px;
+			vertical-align: middle;
+		}
+
+		.school-item {
+			display: flex;
+			align-items: center;
+
+			img {
+				width: 30px;
+				margin-right: 15px;
+			}
+
+		}
+	}
+</style>

+ 20 - 15
TEAMModelOS/ClientApp/src/common/BaseCanvas.vue

@@ -3,37 +3,37 @@
 		<div class="panel-body">
 			<div class="demo">
 				<div class="draw-btn-group">
-					<div :class="{active:drawType==''}" title="自由选择" @click="drawTypeChange('')">
+					<div :class="{active:drawType==''}" :title="vm.$t('utils.choose')" @click="drawTypeChange('')">
 						<i class="iconfont icon-move1"></i>
 					</div>
-					<div :class="{active:drawType=='pen'}" title="笔画" @click="drawTypeChange('pen')">
+					<div :class="{active:drawType=='pen'}" :title="vm.$t('utils.draw')" @click="drawTypeChange('pen')">
 						<i class="iconfont icon-brush"></i>
 					</div>
-					<div :class="{active:drawType=='arrow'}" title="画箭头" @click="drawTypeChange('arrow')">
+					<div :class="{active:drawType=='arrow'}" :title="vm.$t('utils.arrow')" @click="drawTypeChange('arrow')">
 						<i class="iconfont icon-arrow-mark"></i>
 					</div>
-					<div :class="{active:drawType=='text'}" title="文本输入框" @click="drawTypeChange('text')">
+					<div :class="{active:drawType=='text'}" :title="vm.$t('utils.text')" @click="drawTypeChange('text')">
 						<i class="iconfont icon-text"></i>
 					</div>
-					<div :class="{active:drawType=='ellipse'}" title="画圆" @click="drawTypeChange('ellipse')">
+					<div :class="{active:drawType=='ellipse'}" :title="vm.$t('utils.circle')" @click="drawTypeChange('ellipse')">
 						<i class="iconfont icon-oval"></i>
 					</div>
-					<div :class="{active:drawType=='rectangle'}" title="画矩形" @click="drawTypeChange('rectangle')">
+					<div :class="{active:drawType=='rectangle'}" :title="vm.$t('utils.rect')" @click="drawTypeChange('rectangle')">
 						<i class="iconfont icon-rect"></i>
 					</div>
-					<div :class="{active:drawType=='pentagram'}" title="五角星" @click="drawTypeChange('pentagram')">
+					<div :class="{active:drawType=='pentagram'}" :title="vm.$t('utils.star')" @click="drawTypeChange('pentagram')">
 						<i class="iconfont icon-k-point"></i>
 					</div>
-					<div @click="uploadImg" title="从文件选择图片上传">
+					<div @click="uploadImg" :title="vm.$t('utils.upload')">
 						<i class="iconfont icon-cus-video"></i>
 					</div>
-					<div @click="undo" title="撤销">
+					<div @click="undo" :title="vm.$t('utils.undo')">
 						<i class="iconfont icon-undo"></i>
 					</div>
-					<div @click="clear" title="清空">
+					<div @click="clear" :title="vm.$t('utils.clear')">
 						<i class="iconfont icon-reset"></i>
 					</div>
-					<div @click="save" title="保存">
+					<div @click="save" :title="vm.$t('utils.save')">
 						<i class="iconfont icon-baocun1"></i>
 					</div>
 					<ColorPicker v-model="color" />
@@ -41,8 +41,8 @@
 				<canvas id="canvas" :width="width" :height="height"></canvas>
 			</div>
 			<div class="footer">
-				<Button @click="cancel">取消</Button>
-				<Button type="success" @click="save">确认</Button>
+				<Button @click="cancel">{{ vm.$t('utils.cancel') }}</Button>
+				<Button type="success" @click="save">{{ vm.$t('utils.save') }}</Button>
 			</div>
 		</div>
 		<input type="file" @change="uploadImgChange" id="imgInput" accept="image/*" />
@@ -57,6 +57,10 @@
 				type: String,
 				default: ''
 			},
+			vm:{
+				type:Object,
+				default:() => {}
+			},
 		},
 		data() {
 			return {
@@ -93,6 +97,9 @@
 				penWidth: 5
 			};
 		},
+		created() {
+			console.log(this)
+		},
 		watch: {
 			drawType() {
 				this.canvas.selection = !this.drawType;
@@ -105,8 +112,6 @@
 			},
 			bgImg: {
 				handler(n,o){
-					console.log(n);
-					console.log(this.bgImg);
 					if (this.bgImg && this.canvas) {
 						var imgElement = document.createElement("img"); //声明我们的图片
 						imgElement.crossOrigin = 'Anonymous'

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

@@ -1,5 +1,5 @@
 <template>
-	<div class="base-class-select dark-el-cascader">
+	<div class="base-class-select">
 		<RadioGroup v-model="targetType" @on-change="onTargetTypeChange" style="margin-bottom: 10px;">
 		    <Radio label="research">{{ $t('teachermgmt.page.text3') }}</Radio>
 		    <Radio label="student">{{ $t('courseManage.classroom.studentList')}}</Radio>
@@ -59,7 +59,7 @@
 					code:this.$store.state.userInfo.schoolCode,
 					scope:'school'
 				}).then(res => {
-					this.groupList = res.stuList
+					this.groupList = res.tchLists
 				})
 			},
 			/* 选择教研组发生变化 */

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

@@ -1,5 +1,5 @@
 <template>
-    <div class="base-class-select dark-el-cascader">
+    <div class="base-class-select">
         <RadioGroup v-model="evaluationInfo.scope" @on-change="onClassTypeChange" style="margin-bottom: 10px;">
             <Radio label="private">{{ $t('survey.form.privateClass') }}</Radio>
             <Radio label="school" v-if="hasSchool">{{ $t('survey.form.schoolClass') }}</Radio>

+ 2 - 2
TEAMModelOS/ClientApp/src/common/BaseLayout.less

@@ -27,7 +27,7 @@
         position: absolute;
         top: 70px;
         left: 0px;
-        z-index: 999;
+        z-index: 9;
         overflow: hidden;
         background: var(--header-bg);
     }
@@ -66,7 +66,7 @@
     height: 70px;
     float: left;
     align-items: center;
-	margin-left: 20px;
+	// margin-left: 20px;
 
     .unit-logo {
         height: 40px;

+ 45 - 29
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -3,7 +3,8 @@
         <!-- 头部菜单栏 -->
         <Header class="header">
             <div class="logo-wrap">
-                <img src="../assets/login/ies5_logo_2.svg" :class="isCollapsed ? 'collapsed-logo-width unit-logo':'collapsed-logo-width  unit-logo'" v-show="isShowLogo" />
+                <img style="margin-left: 20px;" src="../assets/login/ies5_logo_2.svg" :class="isCollapsed ? 'collapsed-logo-width unit-logo':'collapsed-logo-width  unit-logo'" v-show="isShowLogo && !isShowAreaSelect" />
+                <BaseSelectArea @noArea="isShowAreaSelect = false" v-show="isShowAreaSelect"></BaseSelectArea>
             </div>
             <div class="school-wrap">
                 <BaseSelectSchool></BaseSelectSchool>
@@ -126,6 +127,7 @@ import jwtDecode from 'jwt-decode'
 export default {
     data() {
         return {
+			isShowAreaSelect:true,
             openNames: [],
             activeName: '',
             tipsOpt: {
@@ -342,8 +344,20 @@ export default {
                     role: 'admin',
                     permission: '',
                     subName: 'scTrain',
-                    isShow: process.env.NODE_ENV == 'development',
+                    isShow: true,
+                    // isShow: this.srvAdr == 'China',
                     child: [
+                        {
+                            icon: 'iconfont icon-policy',
+                            name: '政策文件',
+                            router: '/home/policy',
+                            tag: '',
+                            role: 'admin|teacher|expert',
+                            permission: '',
+                            menuName: 'policy',
+                            child: [],
+                            isShow: this.$store.state.config.srvAdr == 'China'
+                        },
                         {
                             icon: 'iconfont icon-test',
                             name: this.$t('system.menu.trainData'),
@@ -367,11 +381,11 @@ export default {
                         {
                             icon: 'iconfont icon-test',
                             name: this.$t('system.menu.scTrain'),
-                            router: '',
+                            router: '/home/TrainMgt',
                             tag: '',
                             role: 'admin',
                             permission: '',
-                            menuName: '',
+                            menuName: 'TrainMgt',
                             isShow: true
                         },
                         {
@@ -402,7 +416,7 @@ export default {
                             role: 'admin|teacher',
                             permission: '',
                             menuName: 'resource',
-                            isShow: true
+                            isShow: this.$store.state.config.srvAdr == 'China'
                         }
                     ]
                 },
@@ -570,7 +584,9 @@ export default {
                     role: 'teacher|admin',
                     permission: '',
                     subName: 'privTrain',
-                    isShow: process.env.NODE_ENV == 'development',
+                    // isShow: process.env.NODE_ENV == 'development',
+                    // isShow: this.$store.state.config.srvAdr == 'China',
+                    isShow: true,
                     child: [
                         {
                             icon: 'iconfont icon-test',
@@ -619,7 +635,7 @@ export default {
                             tag: '',
                             role: 'teacher|admin',
                             permission: '',
-                            menuName: 'classMemoir',
+                            menuName: 'classmemoir',
                             isShow: true
                         },
                         {
@@ -632,28 +648,28 @@ export default {
                             menuName: 'discuss',
                             isShow: true
                         },
-						{
-							icon: 'iconfont icon-vote',
+                        {
+                            icon: 'iconfont icon-vote',
                             name: this.$t('system.menu.scVote'),
-							router: '/home/privateVote',
-							tag: '',
-							role: 'admin|teacher',
-							permission: '',
-							child: [],
-							menuName: 'privateVote',
-							isShow: true
-						},
-						{
-							icon: 'iconfont icon-questionnaire',
+                            router: '/home/privateVote',
+                            tag: '',
+                            role: 'admin|teacher',
+                            permission: '',
+                            child: [],
+                            menuName: 'privateVote',
+                            isShow: true
+                        },
+                        {
+                            icon: 'iconfont icon-questionnaire',
                             name: this.$t('system.menu.scQu'),
-							router: '/home/privateQuestionnaire',
-							tag: '',
-							role: 'admin|teacher',
-							permission: '',
-							child: [],
-							menuName: 'privateQuestionnaire',
-							isShow: true
-						},
+                            router: '/home/privateQuestionnaire',
+                            tag: '',
+                            role: 'admin|teacher',
+                            permission: '',
+                            child: [],
+                            menuName: 'privateQuestionnaire',
+                            isShow: true
+                        },
                     ]
                 },
 
@@ -765,9 +781,8 @@ export default {
             }
             this.isShowLogo = cloudSetting.logoStatus === 'open'
         }
-        this.srvAdr = this.$store.state.config.srvAdr
         //只有大陆站才验证手机号
-        if (this.srvAdr == 'China') {
+        if (this.$store.state.config.srvAdr == 'China') {
             // 暂不提示
             // this.getIdInfo()
         } else {
@@ -808,6 +823,7 @@ export default {
         this.$EventBus.$on('onLogoStatusChange', val => {
             this.isShowLogo = val === 'open'
         })
+        console.log('站点:', this.$store.state.config.srvAdr)
     },
     watch: {
         $route: {

+ 5 - 4
TEAMModelOS/ClientApp/src/common/BaseNotification.vue

@@ -1,6 +1,6 @@
 <template>
 	<div class="base-notification">
-		<Poptip :title="$t('utils.newNotice')" class="dark-iview-poptip" placement="bottom">
+		<Poptip :title="$t('utils.newNotice')" placement="bottom">
 			<Badge :count="msgArr.length">
 				<Icon type="md-notifications" />
 			</Badge>
@@ -141,7 +141,7 @@
 
 <style lang="less">
 	.base-notification {
-		font-family: 'NotoSerif', '微软正黑体', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Sans-serif;
+		// font-family: 'NotoSerif', '微软正黑体', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Sans-serif;
 
 		.ivu-icon {
 			font-size: 22px;
@@ -149,10 +149,11 @@
 			cursor: pointer;
 		}
 
-		.dark-iview-poptip .ivu-poptip-popper {
+		.ivu-poptip-popper {
 			padding: 0;
-			top: 40px !important;
+			top: 65px !important;
 			z-index: 9999;
+			width: 450px !important;
 			
 			.ivu-poptip-body{
 				max-height: 320px;

+ 207 - 0
TEAMModelOS/ClientApp/src/common/BaseSelectArea.vue

@@ -0,0 +1,207 @@
+<template>
+	<div class="base-area-select">
+		<div v-if="!areaList.length"></div>
+		<Dropdown @on-click="onAreaSelect" v-else>
+			<!-- <img class="school-logo" src="https://teammodelstorage.blob.core.chinacloudapi.cn/0-public/image/%E5%B0%91%E5%9F%8E%E6%A0%A1%E5%BE%BD.jpg" /> -->
+			<a href="javascript:void(0)"
+				:class="['base-user-post', joinSchools && joinSchools.length === 1 ? 'single-school' : '']">
+				{{ areaList[curAreaIndex] }}
+				<Icon type="ios-arrow-down"></Icon>
+			</a>
+			<DropdownMenu slot="list">
+				<div v-for="(item,index) in areaList" :key="index">
+					<DropdownItem :name="index">
+						<div class="school-item">
+							<span>{{ item }}</span>
+						</div>
+					</DropdownItem>
+				</div>
+
+			</DropdownMenu>
+		</Dropdown>
+	</div>
+	</div>
+</template>
+
+<script>
+	import User from '@/service/User.js'
+	export default {
+		data() {
+			return {
+				curSchool: {
+					logo: ''
+				},
+				user: {
+					schools: []
+				},
+				joinSchools: [],
+				areaList:[],
+				curAreaIndex:0,
+				otherSch:'其它学校'
+			}
+		},
+		created() {
+			// 获取本地存储中的 用户信息
+			let user = JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8"));
+			let schoolProfile = localStorage.school_profile ? JSON.parse(decodeURIComponent(localStorage.school_profile,
+				"utf-8")) : undefined;
+			this.user.schools = user.schools
+			let joinSchools = user.schools && user.schools.length ? user.schools.filter(i => i.status === 'join') : null
+			// 优先读取本地存储(F5刷新影响) 如果是登录进入 则是读取默认学校
+			let defaultSchoolCode = localStorage.getItem('login_schoolCode') || user.defaultschool
+			console.log(joinSchools);
+			/* 如果没有加入的学校或者加入的学校都没有归属区 */
+			if(!joinSchools || joinSchools.every(i => !i.area)){
+				this.$emit('noArea')
+			}else{
+				joinSchools.forEach(i => {
+					if(!i.area){
+						i.area = {
+							name:this.otherSch
+						}
+					}
+				})
+			}
+			this.joinSchools = joinSchools
+			// 如果本地存储已经有保存学校信息 则刷新后会直接读取之前的学校信息
+			if (schoolProfile && joinSchools.length) {
+				this.curSchool = joinSchools.filter(i => i.schoolId === schoolProfile.school_base.id)[0]
+				this.$store.commit('setSchoolCode', this.curSchool.schoolId)
+				this.areaList = [...new Set(this.joinSchools.map(i => i.area).map(j => j.name))]
+				if(this.areaList.includes(this.otherSch)){
+					this.areaList = this.areaList.filter(i => i !== this.otherSch)
+					this.areaList.push(this.otherSch)
+				}
+				let defaultAreaIndex = defaultSchoolCode ? this.areaList.indexOf(joinSchools.find(i => i.schoolId === defaultSchoolCode).area.name) : 0
+				this.onAreaSelect(defaultAreaIndex,defaultSchoolCode)
+			} else if (joinSchools && joinSchools.length) {
+				// 拿到用户管理的schools 必须是已加入的学校
+				this.curSchool = user.defaultschool ? joinSchools.filter(i => i.schoolId === user.defaultschool)[0] :
+					joinSchools[0]
+				this.$store.commit('setSchoolCode', this.curSchool.schoolId)
+				this.areaList = [...new Set(this.joinSchools.map(i => i.area).map(j => j.name))]
+				if(this.areaList.includes(this.otherSch)){
+					this.areaList = this.areaList.filter(i => i !== this.otherSch)
+					this.areaList.push(this.otherSch)
+				}
+				let defaultAreaIndex = defaultSchoolCode ? this.areaList.indexOf(joinSchools.find(i => i.schoolId === defaultSchoolCode).area.name) : 0
+				this.onAreaSelect(defaultAreaIndex,defaultSchoolCode)
+			} else {
+				// this.$Message.warning(this.$t('utils.noShoolTip'))
+			}
+		},
+		methods: {
+			/* 区级切换时,如果时因为切换学校导致切换区域,则需要把切换的学校编码带进来 否则默认第一个学校 */
+			onAreaSelect(val,defaultSchoolCode){
+				this.curAreaIndex = val
+				let areaSchs = this.joinSchools.filter(i => i.area.name === this.areaList[this.curAreaIndex])
+				let curSchIndex = defaultSchoolCode ? areaSchs.map(i => i.schoolId).indexOf(defaultSchoolCode) : 0
+				this.onSchoolSelect(areaSchs[curSchIndex])
+				this.$EventBus.$emit('onChangeArea', {
+					areaName:this.areaList[this.curAreaIndex],
+					schoolCode:defaultSchoolCode
+				})
+				sessionStorage.setItem('areaId',areaSchs[curSchIndex].areaId)
+				sessionStorage.setItem('areaName',areaSchs[curSchIndex].area.name)
+			},
+			async onSchoolSelect(val) {
+				console.log(val)
+				console.log(this.user.schools)
+				console.log(this.joinSchools)
+				this.joinSchools = this.user.schools.filter(i => i.status === 'join')
+				this.$EventBus.$emit('onGlobalLoading', true)
+				this.curSchool = val
+				let schoolCode = val.schoolId
+				this.$EventBus.$emit('onChangeSchool', {
+					schoolCode: schoolCode,
+				})
+				// 更新当前school_code
+				this.$store.dispatch('user/setSchoolCode', schoolCode)
+				// 更新当前school_profile以及access
+				this.$store.dispatch('user/checkSchoolProfile').then(res => {
+					if (res) {
+						this.$User.freshLogin()
+					}
+				});
+				setTimeout(() => {
+					this.$EventBus.$emit('onGlobalLoading', false)
+				}, 500)
+				// this.$router.push({
+				// 	name: 'home'
+				// })
+			},
+		}
+	}
+</script>
+
+<style lang="less">
+	.base-area-select {
+		margin-left: 20px;
+		font-size: 20px;
+		font-weight: bold;
+		color: #fff;
+		// font-family: 'NotoSerif', '微软正黑体', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Sans-serif;
+		.ivu-dropdown {
+			.ivu-select-dropdown {
+				width: max-content;
+				width: -webkit-max-content;
+				left: -35%;
+			}
+
+			.ivu-dropdown-item:hover {
+				background: #83d7ff;
+			}
+
+			a {
+				color: var(--primary-textColor) !important;
+
+				&:hover {
+					color: var(--primary-textColor) !important;
+				}
+
+				.ivu-icon {
+					display: none;
+				}
+
+				&::after {
+					content: '';
+					display: inline-block;
+					width: 0;
+					height: 0;
+					border-right: solid 8px transparent;
+					border-left: solid 8px transparent;
+					border-top: solid 8px #d0d0d0;
+					margin-left: 8px;
+					margin-bottom: 3px;
+				}
+
+			}
+		}
+
+		.single-school {
+			&::after {
+				display: none !important;
+			}
+
+		}
+
+		.school-logo {
+			width: 30px;
+			border-radius: 50%;
+			margin-right: 10px;
+			margin-bottom: 5px;
+			vertical-align: middle;
+		}
+
+		.school-item {
+			display: flex;
+			align-items: center;
+
+			img {
+				width: 30px;
+				margin-right: 15px;
+			}
+
+		}
+	}
+</style>

+ 89 - 20
TEAMModelOS/ClientApp/src/common/BaseSelectSchool.vue

@@ -2,13 +2,14 @@
 	<div class="base-school-select">
 		<div v-if="!joinSchools || !joinSchools.length">{{ noJoinSchoolContent }}</div>
 		<Dropdown @on-click="onSchoolSelect" v-else>
-			<img class="school-logo" :src="curSchool.picture || defaultLogo" />
-			<a href="javascript:void(0)" :class="['base-user-post', joinSchools && joinSchools.length === 1 ? 'single-school' : '']">
+			<img class="school-logo" :src="curSchool.picture" style="width: 25px;"/>
+			<a href="javascript:void(0)"
+				:class="['base-user-post', joinSchools && joinSchools.length === 1 ? 'single-school' : '']">
 				{{ curSchool.name }}
 				<Icon type="ios-arrow-down"></Icon>
 			</a>
 			<DropdownMenu slot="list">
-				<div v-for="(item,index) in joinSchools" :key="index">
+				<div v-for="(item,index) in areaSchs" :key="index">
 					<DropdownItem :name="index">
 						<div class="school-item">
 							<img :src="item.picture || defaultLogo" alt="" style="border-radius: 50%;">
@@ -16,7 +17,6 @@
 						</div>
 					</DropdownItem>
 				</div>
-
 			</DropdownMenu>
 		</Dropdown>
 	</div>
@@ -35,46 +35,84 @@
 				user: {
 					schools: []
 				},
-				joinSchools:[],
+				joinSchools: [],
+				areaSchs:[],
+				areaList:[]
 			}
 		},
 		created() {
 			this.defaultLogo = require('@/assets/icon/default_school.png')
 			// 获取本地存储中的 用户信息
 			let user = JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8"));
-			let schoolProfile = localStorage.school_profile ? JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8")) :undefined;
+			let schoolProfile = localStorage.school_profile ? JSON.parse(decodeURIComponent(localStorage.school_profile,
+				"utf-8")) : undefined;
 			this.user.schools = user.schools
-			let joinSchools = user.schools && user.schools.length ?  user.schools.filter(i => i.status === 'join') : null
+			let joinSchools = user.schools && user.schools.length ? user.schools.filter(i => i.status === 'join') : null
+			
+			console.log(joinSchools);
+			/* 如果没有加入的学校或者加入的学校都没有归属区 */
+			if(!joinSchools || joinSchools.every(i => !i.area)){
+				console.log('object');
+			}else{
+				joinSchools.forEach(i => {
+					if(!i.area){
+						i.area = {
+							name:'其它学校'
+						}
+					}
+				})
+			}
 			this.joinSchools = joinSchools
 			// 如果本地存储已经有保存学校信息 则刷新后会直接读取之前的学校信息
 			if (schoolProfile && joinSchools.length) {
 				this.curSchool = joinSchools.filter(i => i.schoolId === schoolProfile.school_base.id)[0]
 				this.$store.commit('setSchoolCode', this.curSchool.schoolId)
-            } else if (joinSchools && joinSchools.length) {
+				this.areaList = [...new Set(this.joinSchools.map(i => i.area).map(j => j.name))]
+				this.areaSchs = this.joinSchools.filter(i => i.area.name === this.areaList[0])
+			} else if (joinSchools && joinSchools.length) {
 				// 拿到用户管理的schools 必须是已加入的学校
-				this.curSchool = user.defaultschool ? joinSchools.filter(i => i.schoolId === user.defaultschool)[0] : joinSchools[0]
+				this.curSchool = user.defaultschool ? joinSchools.filter(i => i.schoolId === user.defaultschool)[0] :
+					joinSchools[0]
 				this.$store.commit('setSchoolCode', this.curSchool.schoolId)
+				this.areaList = [...new Set(this.joinSchools.map(i => i.area).map(j => j.name))]
+				this.areaSchs = this.joinSchools.filter(i => i.area.name === this.areaList[0])
 			} else {
 				this.$Message.warning(this.$t('utils.noShoolTip'))
 			}
+			console.log(this.areaSchs)
+			console.log(this.curSchool)
 		},
 		methods: {
 			async onSchoolSelect(val) {
-				console.log(val)
+				console.error(val)
 				console.log(this.user.schools)
 				console.log(this.joinSchools)
+				/* 如果没有加入的学校或者加入的学校都没有归属区 */
+				if(this.joinSchools.length){
+					this.joinSchools.forEach(i => {
+						if(!i.area){
+							i.area = {
+								name:'其它学校'
+							}
+						}
+					})
+				}
+				let curAreaName = sessionStorage.getItem('areaName') || this.areaList[0]
 				this.joinSchools = this.user.schools.filter(i => i.status === 'join')
-				this.curSchool = this.joinSchools[val]
-				let schoolCode = this.joinSchools[val].schoolId
+				this.areaSchs = this.joinSchools.filter(i => i.area.name === curAreaName)
 				this.$EventBus.$emit('onGlobalLoading', true)
-				this.$EventBus.$emit('onChangeSchool',{ schoolCode:schoolCode })
+				this.curSchool = this.areaSchs[val]
+				let schoolCode = this.areaSchs[val].schoolId
+				this.$EventBus.$emit('onChangeSchool', {
+					schoolCode: schoolCode
+				})
 				// 更新当前school_code
 				this.$store.dispatch('user/setSchoolCode', schoolCode)
 				// 更新当前school_profile以及access
-				this.$store.dispatch('user/checkSchoolProfile').then(res=>{
-				    if(res) {
-				        this.$User.freshLogin()
-				    }
+				this.$store.dispatch('user/checkSchoolProfile').then(res => {
+					if (res) {
+						this.$User.freshLogin()
+					}
 				});
 				setTimeout(() => {
 					this.$EventBus.$emit('onGlobalLoading', false)
@@ -87,7 +125,7 @@
 			/* 获取老师所在学校的信息 */
 			getTeacherSchoolInfo(code) {
 				return new Promise((r, j) => {
-					this.$api.schoolSetting.getTeacherSchoolInfo({
+					this.$api.login.getTeacherSchoolInfo({
 						id_token: localStorage.getItem('id_token'),
 						school_code: code
 					}).then(
@@ -108,7 +146,7 @@
 			// 解绑之前的事件 防止多次触发
 			this.$EventBus.$off('onChangeSchool')
 			this.$EventBus.$on('onChangeSchool', params => {
-				if (params.schoolCode !== this.curSchool.schoolId && params.user) {
+				if (this.curSchool && params.schoolCode !== this.curSchool.schoolId && params.user) {
 					console.log('检测到切换学校')
 					console.log(params)
 					this.user = params.user
@@ -116,6 +154,37 @@
 					this.onSchoolSelect(params.isFirst ? 0 : joinSchools.map(j => j.schoolId).indexOf(params.schoolCode))
 				}
 			})
+			
+			// 监听区的切换
+			this.$EventBus.$off('onChangeArea')
+			this.$EventBus.$on('onChangeArea', params => {
+				console.log('区域切换',params);
+				console.log('区域切换',this.joinSchools);
+				if(this.joinSchools.length){
+					this.areaSchs = this.joinSchools.filter(i => i.area.name === params.areaName)
+					this.curSchool = params.schoolCode ? this.areaSchs.find(i => i.schoolId === params.schoolCode) : this.areaSchs[0]
+					// sessionStorage.setItem('areaName',params)
+					// this.onSchoolSelect(0)
+					let schoolCode = this.curSchool.schoolId
+					console.error(schoolCode)
+					this.$EventBus.$emit('onChangeSchool', {
+						schoolCode: schoolCode
+					})
+					// 更新当前school_code
+					this.$store.dispatch('user/setSchoolCode', schoolCode)
+					// 更新当前school_profile以及access
+					this.$store.dispatch('user/checkSchoolProfile').then(res => {
+						if (res) {
+							this.$User.freshLogin()
+						}
+					});
+					this.$router.push({
+						name: 'home'
+					})
+				}
+				console.error(this.curSchool)
+				
+			})
 		},
 
 		computed: {
@@ -130,7 +199,7 @@
 
 <style lang="less">
 	.base-school-select {
-		font-family: 'NotoSerif', '微软正黑体', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Sans-serif;
+		// font-family: 'NotoSerif', '微软正黑体', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Sans-serif;
 		.ivu-dropdown {
 			
 			.ivu-select-dropdown{

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

@@ -4,7 +4,7 @@
 			<div style="padding: 40px 0">
 				<Icon type="ios-cloud-upload" size="100"
 					style="color: #40A8F0;margin: 40px 0;"></Icon>
-				<p style="color: #ddd">{{ $t("knowledge.import.tip1") }}</p>
+				<p style="color: #757575">{{ $t("knowledge.import.tip1") }}</p>
 				<p style="color: #ddd" v-if="acceptTypes.length">({{ $t("knowledge.import.tip2") }}:{{ acceptTypes.join(' / ') }})</p>
 			</div>
 		</Upload>

+ 50 - 29
TEAMModelOS/ClientApp/src/common/BaseUserPoptip.vue

@@ -1,19 +1,6 @@
 <template>
     <div class="base-user-center">
         <div style="display: flex;">
-            <div class="base-user-info">
-                <!-- <p class="base-user-name" style="margin-top:6px">{{ userInfo.username }}</p> -->
-                <!-- <Dropdown @on-click="onRoleSelect">
-                    <a href="javascript:void(0)" class="base-user-post">
-                        {{ getRoleName(curRole) }}
-                        <Icon type="ios-arrow-down"></Icon>
-                    </a>
-                    <DropdownMenu slot="list">
-                        <DropdownItem v-if="curRole != 'teacher' && curRole != 'admin'" name="teacher">{{ $t('utils.teacher') }}</DropdownItem>
-                        <DropdownItem v-if="curRole != 'student'" name="student">{{ $t('utils.student') }}</DropdownItem>
-                    </DropdownMenu>
-                </Dropdown> -->
-            </div>
             <Dropdown placement="bottom-end">
                 <PersonalPhoto style="cursor: pointer;" :name="userInfo.username" :picture="user.picture" :color="userInfo.nameColor" />
                 <DropdownMenu slot="list" class="user-center-wrap">
@@ -26,9 +13,9 @@
                         <Icon type="md-swap" class="drop-item-icon" />
                         {{$t('user.toStudent')}}
                     </DropdownItem> -->
-                    <DropdownItem v-if="$access.can('area.*')" class="drop-item" @click.native="toAreaSite()">
+                    <DropdownItem v-if="hasArea" class="drop-item" @click.native="changePlatform()">
                         <Icon type="md-arrow-round-forward" class="drop-item-icon" />
-                        {{$t('user.toArea')}}
+                        {{ curPlatform === 'area' ? $t('user.toSchool') : $t('user.toArea')}}
                     </DropdownItem>
                     <DropdownItem class="drop-item" @click.native="toSettings('1')">
                         <Icon custom="iconfont icon-school" class="drop-item-icon" />
@@ -38,15 +25,22 @@
                         <Icon type="ios-settings" class="drop-item-icon" />
                         {{$t('user.systemSet')}}
                     </DropdownItem>
-                    
+
                     <DropdownItem @click.native="onQuit">
                         <Icon type="md-power" class="drop-item-icon" />
                         {{$t('utils.logout')}}
                     </DropdownItem>
-                    <DropdownItem divided class="drop-item" disabled style="cursor: text;">
-                        <Icon type="ios-information-circle-outline" class="drop-item-icon"/>
+                    <!-- <DropdownItem divided class="drop-item" disabled style="cursor: text;">
+                        <Icon type="ios-information-circle-outline" class="drop-item-icon" />
                         V {{version}}
-                    </DropdownItem>
+                    </DropdownItem> -->
+					<DropdownItem divided class="drop-item" disabled style="cursor: text;">
+						<Icon type="logo-vimeo" class="drop-item-icon"/>
+						{{version}}
+						<br>
+						<Icon type="ios-information-circle-outline" class="drop-item-icon"/>
+						能力点版本:{{ curStandard ? curStandard.replace('standard','') : '暂无' }}
+					</DropdownItem>
                 </DropdownMenu>
             </Dropdown>
         </div>
@@ -54,12 +48,15 @@
 </template>
 
 <script>
-import BlobTool from '@/utils/blobTool.js';
 import PersonalPhoto from '@/components/public/personalPhoto/Index.vue'
 export default {
+    components: {
+        PersonalPhoto
+    },
     data() {
         return {
-            version:'',
+            curPlatform: '',
+            version: '',
             curRole: '',
             userInfo: {
                 username: '',
@@ -86,10 +83,30 @@ export default {
     created() {
         this.doRefresh()
         this.version = localStorage.getItem('version')
+        this.curPlatform = localStorage.getItem('platform') || 'school'
+    },
+    mounted() {
+        this.$EventBus.$off('freshUserInfo')
+        this.$EventBus.$on('freshUserInfo', (data) => {
+            if (data && data.picture) {
+                this.$set(this.user, 'picture', '')
+                setTimeout(() => {
+                    this.$set(this.user, 'picture', data.picture)
+                })
+            } else {
+                this.doRefresh()
+            }
+        })
     },
     methods: {
-        toAreaSite(){
-            this.$Message.warning('暂未处理区级路由')
+        /* 切换校级平台或区级平台 */
+        changePlatform() {
+            let goPlatform = this.curPlatform === 'area' ? 'school' : 'area'
+            this.$router.push({
+                name: goPlatform === 'area' ? 'area' : 'home'
+            })
+            localStorage.setItem('platform', this.curPlatform === 'area' ? 'school' : 'area')
+            this.curPlatform = goPlatform
         },
         // 这里可以携带参数,直接跳转到对应的tab
         toSettings(tab) {
@@ -98,7 +115,7 @@ export default {
                 query: { tab }
             })
         },
-		// 这里可以携带参数,直接跳转到对应的tab
+        // 这里可以携带参数,直接跳转到对应的tab
         toUserCenter() {
             this.$router.push({
                 name: 'userCenter'
@@ -141,7 +158,7 @@ export default {
             let g = Math.floor(Math.random() * 255);
             let b = Math.floor(Math.random() * 255);
             return 'rgba(' + r + ',' + g + ',' + b + ',0.8)';
-        },
+        }
     },
 
     computed: {
@@ -155,11 +172,15 @@ export default {
             return val => {
                 return val === 'student' ? this.$t('utils.student') : this.$t('utils.teacher')
             }
-        }
+        },
+        hasArea() {
+            return this.$store.state.user.userProfile.areas.length > 0
+        },
+		curStandard(){
+			return this.$store.state.user.schoolProfile.school_base ? this.$store.state.user.schoolProfile.school_base.standard : ''
+		}
     },
-    components: {
-        PersonalPhoto
-    }
+
 }
 </script>
 <style scoped>

+ 23 - 6
TEAMModelOS/ClientApp/src/components/questionnaire/BaseJudge.vue

@@ -8,12 +8,13 @@
 			<IconText :text="$t('survey.judgeOption')" :color="'#FF871C'" :icon="'md-reorder'"></IconText>
 			<div v-if="options.length">
 				<div v-for="(item,index) in options" :key="index" :ref="'optionBox' + index" class="option-editor-wrap" style="margin-top:10px;display:flex">
-					<span class="fl-center option-order">{{String.fromCharCode(64 + parseInt(index+1))}}</span>
+					<span class="fl-center option-order" :id="'optionOrder' + index">{{String.fromCharCode(64 + parseInt(index+1))}}</span>
 					<div :ref="'singleOption'+index" :data-index="index" style="text-align:left" class="qn-option-editor" @click="optionClick(item)"></div>
-					<!-- <span class="fl-center option-delete" @click="deleteOption(index)">
-						<Icon type="md-close" /></span> -->
+					<span class="fl-center option-delete">
+						<Icon type="md-checkmark-circle" v-if="needAnswer" :color="trueIndex === index ? '#0bbe88' : '#ccc'" size="20" title="设置为正确答案" style="margin-left: 5px;cursor: pointer;" @click="setTrue(index)"/></span>
 				</div>
 			</div>
+			<p style="display: block;float: right;margin: 20px 20px 0 20px;font-weight: bold;color: #0bbe88;" v-if="needAnswer">正确答案:{{ answer[0] }}</p>
 			<!-- <p class="option-add"><span @click="addOption()"> + 添加选项 </span></p> -->
 		</div>
 	</div>
@@ -25,7 +26,16 @@
 		components: {
 			IconText
 		},
-		props: ['editInfo'],
+		props: {
+			editInfo:{
+				type:Object,
+				default:() => {}
+			},
+			needAnswer:{
+				type:Boolean,
+				default:false
+			}
+		},
 		data() {
 			return {
 				options: [...new Array(2).keys()], // 默认四个选项
@@ -40,11 +50,17 @@
 				defaultConfig: {
 					uploadImgShowBase64: true,
 					menus: this.$tools.wangEditorMenuSimple
-				}
+				},
+				answer:['A']
 			}
 		},
 		created() {},
 		methods: {
+			setTrue(index){
+				this.trueIndex = index
+				this.answer = [document.getElementById('optionOrder' + index).innerHTML]
+				console.log(this.answer);
+			},
 			resetContent() {
 				console.log('重置')
 				this.options = [...new Array(2).keys()],
@@ -196,7 +212,8 @@
 				})
 				this.$emit('onSave',{
 					stemContent:this.stemContent,
-					optionsContent:arr
+					optionsContent:arr,
+					answer:this.answer
 				})
 			},
 

+ 58 - 8
TEAMModelOS/ClientApp/src/components/questionnaire/BaseMultiple.vue

@@ -8,12 +8,15 @@
 			<IconText :text="$t('survey.multipleOption')" :color="'#FF871C'" :icon="'md-reorder'"></IconText>
 			<div v-if="options.length">
 				<div v-for="(item,index) in options" :key="index" :ref="'optionBox' + index" class="option-editor-wrap" style="margin-top:10px;display:flex">
-					<span class="fl-center option-order">{{String.fromCharCode(64 + parseInt(index+1))}}</span>
+					<span class="fl-center option-order" :id="'optionOrder' + index">{{String.fromCharCode(64 + parseInt(index+1))}}</span>
 					<div :ref="'singleOption'+index" :data-index="index" style="text-align:left" class="qn-option-editor" @click="optionClick(item)"></div>
-					<span class="fl-center option-delete" @click="deleteOption(index)">
-						<Icon type="md-close" /></span>
+					<span class="fl-center option-delete">
+						<Icon type="md-close"  @click="deleteOption(index)"/>
+						<Icon type="md-checkmark-circle" v-if="needAnswer" class="trueOrder" :color="trueIndexArr.includes(index) ? '#0bbe88' : '#ccc'" size="20" title="设置为正确答案" style="margin-left: 5px;cursor: pointer;" @click="setTrue(index)"/>
+					</span>
 				</div>
 			</div>
+			<p style="display: block;float: right;margin: 20px 20px 0 20px;font-weight: bold;color: #0bbe88;" v-if="needAnswer">正确答案:{{ answer.join(',') }}</p>
 			<p class="option-add"><span @click="addOption()"> + {{ $t('survey.addOption') }} </span></p>
 		</div>
 	</div>
@@ -25,13 +28,22 @@
 		components: {
 			IconText
 		},
-		props: ['editInfo'],
+		props: {
+			editInfo:{
+				type:Object,
+				default:() => {}
+			},
+			needAnswer:{
+				type:Boolean,
+				default:false
+			}
+		},
 		data() {
 			return {
 				options: [...new Array(4).keys()], // 默认四个选项
 				existOptions: [...new Array(4).keys()],
 				initFlag: true,
-				trueIndex: 0,
+				trueIndexArr: [0],
 				editSingleInfo: {},
 				stemEditor: null,
 				stemContent: '',
@@ -40,11 +52,40 @@
 				defaultConfig: {
 					uploadImgShowBase64: true,
 					menus: this.$tools.wangEditorMenuSimple
-				}
+				},
+				answer:['A']
 			}
 		},
 		created() {},
 		methods: {
+			setTrue(index){
+				if(this.trueIndexArr.includes(index)){
+					this.trueIndexArr.splice(this.trueIndexArr.indexOf(index),1)
+				}else{
+					this.trueIndexArr.push(index)
+				}
+				let curAnswer = document.getElementById('optionOrder' + index).innerHTML
+				
+				// if(this.answer.includes(curAnswer)){
+				// 	this.answer.splice(this.answer.indexOf(curAnswer),1)
+				// }else{
+				// 	this.answer.push(curAnswer)
+				// }
+				// console.log(this.answer);
+				this.$nextTick(() => {
+					this.getAnswer()
+				})
+			},
+			getAnswer(){
+				let allTrueOrder = Array.from(document.getElementsByClassName('trueOrder'))
+				let result = []
+				allTrueOrder.forEach((i,index) => {
+					if(i.style.color === 'rgb(11, 190, 136)'){
+						result.push(this.renderIndex(index))
+					}
+				})
+				this.answer = result
+			},
 			resetContent() {
 				console.log('重置')
 				this.options = [...new Array(4).keys()],
@@ -166,11 +207,19 @@
 			deleteOption(index) {
 				let wraps = Array.from(document.getElementsByClassName('qn-option-editor'))
 				if (wraps.length > 2) {
+					console.log(document.getElementById('optionOrder' + index))
+					
+					if(this.trueIndexArr.includes(index)){
+						this.trueIndexArr.splice(this.trueIndexArr.indexOf(index),1)
+					}
 					this.optionsContent.splice(index, 1)
 					let textWrap = this.$refs['optionBox' + index][0]
 					textWrap.remove()
-					
 					this.refreshOrder()
+					console.log(this.trueIndexArr)
+					this.$nextTick(() => {
+						this.getAnswer()
+					})
 				} else {
 					this.$Message.warning(this.$t('survey.optionLimitTip'))
 				}
@@ -195,7 +244,8 @@
 				})
 				this.$emit('onSave',{
 					stemContent:this.stemContent,
-					optionsContent:arr
+					optionsContent:arr,
+					answer:this.answer
 				})
 			},
 

+ 3 - 3
TEAMModelOS/ClientApp/src/components/questionnaire/BasePie.vue

@@ -37,8 +37,8 @@
 						top: 25,
 						left: 'center',
 						textStyle: {
-							color: '#f3f3f3',
-							fontSize: 12,
+							color: '#6c6c6c',
+							fontSize: 14,
 							fontWeight: 'bold'
 						}
 					},
@@ -65,7 +65,7 @@
 						}),
 						label: {
 							normal: {
-								formatter: ['{c|{c}}' + that.$t('unit.text7'), '{b|{b}}'].join('\n'),
+								formatter: ['{c|{c}}' + that.$t('unit.text7'), '{b|{b}}'].join(' '),
 								rich: {
 									c: {
 										color: '#1fb06d',

+ 10 - 9
TEAMModelOS/ClientApp/src/components/questionnaire/BaseQnForm.less

@@ -8,9 +8,10 @@
 
 .component-qn-form {
     padding: 20px 20px 50px 20px;
-	background-color: #fff;
+	// background-color: #fff;
 	
 	.ivu-input[disabled]{
+        background: none;
 		border: none !important;
 		font-size: 16px;
 		font-weight: bold;
@@ -33,7 +34,7 @@
 	}
 
     .ivu-form .ivu-form-item-label {
-        color: #5a5a5a;
+        color: var(--second-text-color);
     }
 
     .ivu-form-item:not(:first-child) {
@@ -59,13 +60,13 @@
 
     .ivu-input, .ivu-select-single .ivu-select-selection,
     .ivu-select-multiple .ivu-select-selection {
-        border: 1px solid #c1c1c1;
+        // border: 1px solid #c1c1c1;
         margin-top: 10px;
         height: 40px;
         line-height: 40px;
 		padding-left: 8px;
-        color: @primary-textColor;
-		background-color: transparent;
+        /* color: @primary-textColor;
+		background-color: transparent; */
     }
 
     .ivu-input-number-input,
@@ -74,15 +75,15 @@
         padding-left: 10px;
         height: 40px;
         line-height: 40px;
-        color: @primary-textColor;
+        // color: @primary-textColor;
 
         .ivu-input-number-handler-wrap {
-            background: none;
+            /* background: none;
             border: none;
 
             .ivu-input-number-handler-down {
                 border-top: 1px solid #6f6f6f;
-            }
+            } */
 
             .ivu-input-number-handler {
                 height: 20px;
@@ -145,7 +146,7 @@
     }
 
     .ivu-radio-inner:after {
-        background: @primary-color;
+        background: #2d8cf0;
     }
 
     .ivu-upload-drag {

+ 202 - 95
TEAMModelOS/ClientApp/src/components/questionnaire/BaseQnForm.vue

@@ -1,5 +1,5 @@
 <template>
-	<div class="component-qn-form">
+	<div class="component-qn-form light-iview-form light-el-input">
 		<Form ref="qnForm" :model="qnForm" label-position="top" :rules="ruleValidate" :disabled="!qnFormEdit">
 			<FormItem :label="$t('survey.form.name')" prop="name">
 				<Input :class="!qnFormEdit ? 'qn-form-disabled':''" v-model="qnForm.name"
@@ -14,28 +14,22 @@
 				<div v-if="!qnFormEdit && curQnItem" class="vote-class">
 					<span v-for="item in classNameArr" class="vote-class-item">{{ item.name }}</span>
 				</div>
-				<!-- <Select multiple v-model="qnForm.classes" :class="!qnFormEdit ? 'qn-form-disabled':''"
-					:placeholder="$t('survey.form.targetPlace')" v-else>
-					<Option v-for="(item,index) in classRooms.filter(i=>i.scope === classType)" :value="item.id"
-						:key="index">{{ item.name }}</Option>
-				</Select> -->
 				<div v-else>
-					<BaseClassSelect :classes="classTargets" :type="targetType" @onChange="onTargetChange" ref="classSelectRef" v-if="getCurScope === 'school' && curQnItem"></BaseClassSelect>
-					<BaseClassSelectPri :classes="classTargets" :scope="classType" @onChange="onTargetChange" ref="classSelectRef" v-if="getCurScope === 'private' && curQnItem"></BaseClassSelectPri>
+					<div v-if="isAreaSurvey">
+						<el-cascader size="small" :show-all-levels="false" clearable filterable v-model="schoolTarget"
+							:options="csOptions" :props="props" @change="treeChange" style="width:100%;">
+						</el-cascader>
+					</div>
+					<div v-else>
+						<BaseClassSelect :classes="classTargets" :type="targetType" @onChange="onTargetChange"
+							ref="classSelectRef" v-if="getCurScope === 'school' && curQnItem"></BaseClassSelect>
+						<BaseClassSelectPri :classes="classTargets" :scope="classType" @onChange="onTargetChange"
+							ref="classSelectRef" v-if="getCurScope === 'private' && curQnItem"></BaseClassSelectPri>
+					</div>
 				</div>
 			</FormItem>
 
-			<!-- <FormItem :label="$t('survey.form.time')" prop="rangeTime">
-				<RadioGroup v-model="publishModel" v-if="qnFormEdit">
-				        <Radio label="0">立即发布</Radio>
-				        <Radio label="1">定时发布</Radio>
-				</RadioGroup>
-				<DatePicker type="datetimerange" @on-change="onChangeRange" @on-open-change="onOpenChange" format="yyyy-MM-dd HH:mm" :class="!qnFormEdit ? 'qn-form-disabled':''"
-				 :editable="isDateEdit" :placeholder="$t('survey.form.endTimePlace')" :value="[qnForm.startTime,qnForm.endTime]">
-				</DatePicker>
-			</FormItem> -->
-
-			<FormItem :label="$t('learnActivity.createEv.publishType')" prop="publishModel" v-show="qnFormEdit">
+			<FormItem :label="$t('learnActivity.createEv.publishType')" prop="publishModel" v-show="qnFormEdit && !isAreaSurvey">
 				<Checkbox v-model="isImmediate">{{ $t('global.publishType1')}}</Checkbox>
 			</FormItem>
 
@@ -44,15 +38,16 @@
 				<DatePicker v-show="qnFormEdit" type="datetime" :options="startOption" format="yyyy/MM/dd HH:mm"
 					v-model="qnForm.startTime" split-panels :placeholder="$t('learnActivity.createEv.sTimeHolder')"
 					style="width:100%" @on-change="onChangeSTime"></DatePicker>
-				<div v-show="!qnFormEdit" style="margin:10px;font-size:16px;font-weight:bold;color:#6f6f6f">
+				<div v-show="!qnFormEdit" style="margin:10px;font-size:16px;font-weight:bold;">
 					{{ $tools.formatTime(qnForm.startTime,'yyyy-MM-dd hh:mm') }}
 				</div>
 			</FormItem>
 
-			<FormItem :label="$t('learnActivity.createEv.endTime')"  prop="endTime">
-				<DatePicker v-show="qnFormEdit" type="datetime" :options="endOption" format="yyyy/MM/dd HH:mm" v-model="qnForm.endTime"
-					split-panels @on-change="onChangeEndTime" :placeholder="$t('learnActivity.createEv.eTimeHolder')" style="width:100%"></DatePicker>
-				<div v-show="!qnFormEdit" style="margin:10px;font-size:16px;font-weight:bold;color:#6f6f6f">
+			<FormItem :label="$t('learnActivity.createEv.endTime')" prop="endTime">
+				<DatePicker v-show="qnFormEdit" type="datetime" :options="endOption" format="yyyy/MM/dd HH:mm"
+					v-model="qnForm.endTime" split-panels @on-change="onChangeEndTime"
+					:placeholder="$t('learnActivity.createEv.eTimeHolder')" style="width:100%"></DatePicker>
+				<div v-show="!qnFormEdit" style="margin:10px;font-size:16px;font-weight:bold;">
 					{{ $tools.formatTime(qnForm.endTime,'yyyy-MM-dd hh:mm') }}
 				</div>
 			</FormItem>
@@ -61,7 +56,7 @@
 			<FormItem :label="$t('survey.form.description')" prop="description">
 				<div ref="descriptionEditor" style="text-align:left" v-show="qnFormEdit"></div>
 				<div v-html="qnForm.description" v-show="!qnFormEdit"
-					style="margin:10px;font-size:16px;font-weight:bold;color:#6f6f6f"></div>
+					style="margin:10px;font-size:16px;font-weight:bold;"></div>
 			</FormItem>
 		</Form>
 
@@ -81,9 +76,15 @@
 			}
 		},
 		data(vm) {
-			 const _this = this
+			const _this = this
 			return {
-				classTargets:[],
+				props: {
+					multiple: true,
+					value: 'id',
+					label: 'name',
+				},
+				schoolTarget: [],
+				classTargets: [],
 				curQnItem: null,
 				classType: 'private',
 				isFalse: false,
@@ -123,12 +124,12 @@
 					code: "",
 					name: "",
 					classes: [],
-					stuLists:[],
+					stuLists: [],
 					startTime: 0,
 					endTime: 0,
 					resource: []
 				},
-				classNameArr:[],
+				classNameArr: [],
 				uploadList: [],
 				ruleValidate: {
 					name: [{
@@ -136,11 +137,11 @@
 						message: vm.$t('survey.form.ruleName'),
 						trigger: 'blur'
 					}],
-					description: [{
-						required: true,
-						message: vm.$t('survey.form.ruleDescription'),
-						trigger: 'blur'
-					}],
+					// description: [{
+					// 	required: true,
+					// 	message: vm.$t('survey.form.ruleDescription'),
+					// 	trigger: 'blur'
+					// }],
 					// classes: [{
 					// 	required: true,
 					// 	message: vm.$t('survey.form.ruleClasses')
@@ -160,39 +161,86 @@
 				},
 				startOption: {
 					disabledDate(date) {
-					    return date && date.valueOf() < Date.now() - 86400000
+						return date && date.valueOf() < Date.now() - 86400000
 					}
 				},
 				endOption: {
 					disabledDate(date) {
 						let data = _this.qnForm.startTime ? _this.qnForm.startTime : Date.now()
-					    return data && data > date.valueOf() + 86400000
+						return data && data > date.valueOf() + 86400000
 					}
 				},
-				classIds:[],
-				groupList:[],
-				targetType:''
+				classIds: [],
+				groupList: [],
+				targetType: '',
+				schList: [],
+				csOptions: [],
+				areaId: sessionStorage.getItem('areaId'),
 			}
 		},
 		created() {
-			this.findResearchList()
+			if (this.isAreaSurvey) {
+				this.getAreaTargets()
+			} else {
+				this.findResearchList()
+			}
 		},
 		methods: {
+			treeChange(data) {
+				console.log('选择数据', this.schoolTarget)
+			},
+			getAreaTargets() {
+				this.$api.ability.findAreaGroup({
+					id: this.areaId
+				}).then(
+					res => {
+						console.log(res)
+						if (res.gr && res.gr.length) {
+							this.schList = res.gr
+							this.csOptions = []
+							res.gr.forEach(sItem => {
+								let i = {
+									id: sItem.id,
+									name: sItem.sname,
+									children: []
+								}
+								sItem.name.forEach(gItem => {
+									i.children.push({
+										id: sItem.sname + '-' + gItem,
+										name: sItem.sname + '-' + gItem
+									})
+								})
+								if (!i.children.length) {
+									i.children.push({
+										id: sItem.sname + '-' + '所有老师(未分组)',
+										name: sItem.sname + '-' + '所有老师(未分组)'
+									})
+								}
+								this.csOptions.push(i)
+							})
+						}
+
+					},
+					err => {
+						console.log(err)
+					}
+				)
+			},
 			/* 查找学校检验组信息 */
-			findResearchList(){
+			findResearchList() {
 				this.$api.schoolUser.getResearchGroup({
-					code:this.$store.state.userInfo.schoolCode,
-					scope:'school'
+					code: this.$store.state.userInfo.schoolCode,
+					scope: 'school'
 				}).then(res => {
-					this.groupList = res.stuList
+					this.groupList = res.tchLists
 				})
 			},
-			
+
 			onClassTypeChange(val) {
 				this.qnForm.classes = []
 			},
-			
-			onTargetChange(data){
+
+			onTargetChange(data) {
 				this.qnForm.classes = this.getCurScope === 'school' ? data : data.map(i => i.split('/')[1])
 				this.qnForm.targets = this.getCurScope === 'school' ? [] : data
 			},
@@ -203,18 +251,18 @@
 					this.qnForm.endTime = null
 				}
 			},
-			
-			onChangeEndTime(val){
+
+			onChangeEndTime(val) {
 				if (val.indexOf('00:00') > 0) {
-				    val = val.replace('00:00', '23:59')
+					val = val.replace('00:00', '23:59')
 					this.qnForm.endTime = val
 				}
 				let startTime = this.qnForm.startTime || Date.now()
 				if (new Date(val).getTime() <= new Date(startTime).getTime()) {
 					this.qnForm.endTime = null
-					this.ruleValidate.endTime[0].message = this.$t('survey.form.ruleStartTime')
-				}else{
-					this.ruleValidate.endTime[0].message = this.$t('survey.form.ruleDate')
+					this.ruleValidate.endTime[0].message = this.$t('survey.form.ruleStartTime')
+				} else {
+					this.ruleValidate.endTime[0].message = this.$t('survey.form.ruleDate')
 				}
 			},
 
@@ -225,12 +273,16 @@
 			handleSubmit(name) {
 				return new Promise((resolve, reject) => {
 					this.$refs[name].validate((valid) => {
-						if (valid && this.getSimpleText(this.qnForm.description) && this.qnForm.classes.length) {
+						let hasTargets = (!this.isAreaSurvey && this.qnForm.classes.length) || (this.isAreaSurvey && this.schoolTarget.length)
+						if (valid && this.getSimpleText(this.qnForm.description) && hasTargets) {
 							let params = JSON.parse(JSON.stringify(this.defaultParams))
+							let areaParams = null
 							let target = []
-							let classSelectScope = this.$refs.classSelectRef.evaluationInfo.scope
-							let isSchoolClass = this.$refs.classSelectRef.evaluationInfo.scope === 'school' && this.$refs.classSelectRef.privateClassType === 'school'
-							let isPersonal = this.$route.name === 'personalSurvey' && classSelectScope  === 'private'
+							let classSelectScope = this.isAreaSurvey ? 'school' : this.$refs.classSelectRef.evaluationInfo.scope
+							let isSchoolClass = this.isAreaSurvey ? false : this.$refs.classSelectRef.evaluationInfo.scope ===
+								'school' && this.$refs.classSelectRef.privateClassType === 'school'
+							let isPersonal = this.$route.name === 'personalSurvey' && classSelectScope ===
+								'private'
 							let isSchool = this.$route.name === 'manageQuestionnaire'
 							params.code = this.getCurCode
 							// 如果个人问卷的班级是校本班级 那么也要把scope置为school
@@ -246,10 +298,10 @@
 							params.creatorId = this.$store.state.userInfo.TEAMModelId
 							params.school = params.scope === 'school' ? this.$store.state.userInfo
 								.schoolCode : null
-								
+
 							params.tchLists = []
 							params.classes = []
-							params.stuLists = []	
+							params.stuLists = []
 							// 如果是编辑状态 则直接复制ID 如果是新增 则直接赋值新ID
 							if (this.isEdit && this.editInfo.id && this.editInfo.code) {
 								params.id = this.editInfo.id
@@ -257,23 +309,65 @@
 							} else {
 								params.id = this.$tools.guid()
 							}
-							// 如果是校本投票 则需要进一步确定发布对象是教研组还是学生名单
-							if(isSchool && this.$refs.classSelectRef.targetType === 'research'){
-								params.tchLists = this.qnForm.classes
-								params.targetType = 'research'
-							}else if(isSchoolClass){
-								params.classes = this.qnForm.classes
-								params.targetType = 'student'
+							
+							// 如果是发布的区级投票 则需要修改保存参数
+							if (this.isAreaSurvey) {
+								let schArr = [...new Set(this.schoolTarget.map(i => i[0]))]
+								let para = []
+								schArr.forEach((i, index) => {
+									para.push({
+										sId: i,
+										sName: this.schList.find(j => j.id === i).sname,
+										gName: [],
+										gId:[]
+									})
+									// 如果是区级活动 需要拼接学校加教研组信息
+									this.schoolTarget.forEach(j => {
+										if (j[0] === i) {
+											let groupName = j[1].split('-')[1]
+											if (groupName === '所有老师(未分组)') {
+												para[index].gName = []
+												para[index].gId = ['default']
+											} else {
+												let curSch = this.schList.find(sch => sch.id === i)
+												let groupId = curSch.gId[curSch.name.indexOf(groupName)]
+												para[index].gName.push(groupName)
+												para[index].gId.push(groupId)
+											}
+										}
+									})
+								})
+								delete this.qnForm.classes
+								delete this.qnForm.targets
+								delete this.qnForm.teachers
+								delete this.qnForm.stuLists
+								areaParams = {
+									"id": this.areaId,
+									"para": para,
+									"survey": params
+								}
 							}else{
-								params.stuLists = this.qnForm.classes
-								params.targetType = 'student'
+								// 如果是校本投票 则需要进一步确定发布对象是教研组还是学生名单
+								if (isSchool && this.$refs.classSelectRef.targetType === 'research') {
+									params.tchLists = this.qnForm.classes
+									params.targetType = 'research'
+								} else if (isSchoolClass) {
+									params.classes = this.qnForm.classes
+									params.targetType = 'student'
+								} else {
+									params.stuLists = this.qnForm.classes
+									params.targetType = 'student'
+								}
 							}
-							console.log(params)
-							resolve(params)
+							let finalParams = this.isAreaSurvey ? areaParams : params
+							console.log(finalParams)
+							resolve(finalParams)
 						} else {
-							if(!this.qnForm.classes.length){
+							if (!hasTargets) {
 								this.$Message.error(this.$t('survey.form.ruleClasses'))
-							}else{
+							}else if(!this.getSimpleText(this.qnForm.description)){
+								this.$Message.error('问卷描述不能为空!')
+							} else {
 								this.$Message.error(this.$t('survey.form.noCompleteTip'))
 							}
 							reject(500)
@@ -324,16 +418,16 @@
 			},
 
 			/* 根据班级ID集合换取班级名称 */
-			getClassNameByIds(ids){
-				return new Promise((r,j) => {
+			getClassNameByIds(ids) {
+				return new Promise((r, j) => {
 					this.$api.learnActivity.getClassNameByIds({
-						classes:ids,
-						school:this.$store.state.userInfo.schoolCode
+						classes: ids,
+						school: this.$store.state.userInfo.schoolCode
 					}).then(res => {
-						if(!res.error){
+						if (!res.error) {
 							r(res.classInfos)
 						}
-					}).catch(e =>{
+					}).catch(e => {
 						j(e)
 					})
 				})
@@ -344,37 +438,46 @@
 			 */
 			async doRender(item) {
 				console.log(item)
-				// if(item.id){
-				// 	this.classNameArr = item.classes.length ? await this.getClassNameByIds(item.classes) : await this.getClassNameByIds(item.stuLists)
-				// }
-				if(item.targetType === 'research'){
-					console.log(this.groupList);
-					let groupNameArr = []
-					item.tchLists.forEach(i => {
-						let findObj = this.groupList.find(j => j.id === i)
-						if(findObj){
-							groupNameArr.push(findObj)
+				// 如果是区级投票
+				if(this.isAreaSurvey){
+					this.classNameArr = item.targets.map(i => {
+						return {
+							name:i
 						}
 					})
-					this.classNameArr = groupNameArr
 				}else{
-					this.classNameArr = item.classes.length ? await this.getClassNameByIds(item.classes) : item.stuLists.length ? await this.getClassNameByIds(item.stuLists) : []
+					if (item.targetType === 'research') {
+						console.log(this.groupList);
+						let groupNameArr = []
+						item.tchLists.forEach(i => {
+							let findObj = this.groupList.find(j => j.id === i)
+							if (findObj) {
+								groupNameArr.push(findObj)
+							}
+						})
+						this.classNameArr = groupNameArr
+					} else {
+						this.classNameArr = item.classes.length ? await this.getClassNameByIds(item.classes) : item
+							.stuLists.length ? await this.getClassNameByIds(item.stuLists) : []
+					}
 				}
 				console.log(this.classNameArr);
-				this.classTargets = item.targetType === 'research' ? item.tchLists :  this.getCurScope === 'school' ? item.classes : item.targets
+				this.classTargets = item.targetType === 'research' ? item.tchLists : this.getCurScope === 'school' ?
+					item.classes : item.targets
 				this.classType = item.classes.length ? 'school' : 'private'
 				this.targetType = item.targetType
 				this.qnForm = {
 					name: item.name,
-					targets:item.targets,
-					classes: item.targetType === 'research' ? item.tchLists : item.classes.length ? item.classes : item.stuLists,
+					targets: item.targets,
+					classes: item.targetType === 'research' ? item.tchLists : item.classes.length ? item.classes :
+						item.stuLists,
 					startTime: item.startTime ? new Date(item.startTime) : '',
 					endTime: item.endTime ? new Date(item.endTime) : '',
 					description: item.description,
 					rangeTime: item.endTime ? [item.startTime, item.endTime] : null
 				}
 				console.log(this.qnForm)
-				this.isImmediate = false
+				this.isImmediate = item.isImmediate || false
 				this.currentState = item.state
 				this.$nextTick(() => {
 					this.curQnItem = JSON.parse(JSON.stringify(item))
@@ -387,7 +490,8 @@
 
 			/* 根据班级ID获取班级名称 */
 			getTargetName(classId) {
-				return this.classNameArr.find(i => i.id === classId) ? this.classNameArr.find(i => i.id === classId).name : this.$t('vote.form.noMatchDataTip')
+				return this.classNameArr.find(i => i.id === classId) ? this.classNameArr.find(i => i.id === classId).name :
+					this.$t('vote.form.noMatchDataTip')
 			}
 
 		},
@@ -415,6 +519,9 @@
 			getCurScope() {
 				return this.$route.name === 'personalSurvey' ? 'private' : 'school'
 			},
+			isAreaSurvey() {
+				return this.$route.name === 'manageAreaQuestionnaire'
+			},
 		},
 		watch: {
 			editItem: {

+ 47 - 21
TEAMModelOS/ClientApp/src/components/questionnaire/BaseQuestionnaire.vue

@@ -251,17 +251,22 @@
 						if (item.type === 'subjective') {
 							let result = []
 							for (let key in curItemRecord.other) {
-								result.push({
-									id: key,
-									name: this.students.filter(i => i.id === key)[0].name,
-									value: curItemRecord.other[key]
-								})
+								let curStudent = this.students.find(i => i.id === key)
+								if(curStudent){
+									result.push({
+										id: key,
+										name: curStudent.name,
+										value: curItemRecord.other[key]
+									})
+								}
 							}
 							item.result.details = result
 						} else {
 							for (let key in curItemRecord.opt) {
-								curItemRecord.opt[key] = curItemRecord.opt[key].map(id => this.students.filter(i => i
-									.id === id)[0].name)
+								let curStudent = this.students.find(i => i.id === key)
+								if(curStudent){
+									curItemRecord.opt[key] = curItemRecord.opt[key].map(id => curStudent.name)
+								}
 							}
 							item.result.details = curItemRecord.opt
 						}
@@ -282,13 +287,19 @@
 					let sasString = qnItem.scope === 'private' ? await this.$tools.getPrivateSas() : await this
 						.$tools.getSchoolSas()
 					let promiseArr = []
-					let indexJson = await this.getBlobJsonFile(qnItem.scope, qnItem.blob)
+					
+					// 如果是区级
+					if(qnItem.owner === 'area'){
+						blobHost = this.$store.state.user.osblob_uri
+						sasString = { sas : '?' + this.$store.state.user.osblob_sas }
+					}
+					
+					let indexJson = JSON.parse(await this.$tools.getFile(blobHost + qnItem.blob + sasString.sas))
 					if (indexJson.slides.length) {
 						for (let item of indexJson.slides) {
 							promiseArr.push(new Promise(async (r, j) => {
 								try {
-									let itemJson = JSON.parse(await this.$tools.getFile(
-										blobHost + item + sasString.sas))
+									let itemJson = JSON.parse(await this.$tools.getFile(blobHost + item + sasString.sas))
 									r(itemJson)
 								} catch (e) {
 									j(e)
@@ -351,20 +362,26 @@
 					let curItemRecord = result.question[index]
 					if (item.type === 'subjective') {
 						let result = []
+						console.log(this.students.map(i => i.id));
 						for (let key in curItemRecord.other) {
-							result.push({
-								id: key,
-								name: this.students.filter(i => i.id === key)[0].name,
-								value: curItemRecord.other[key]
-
-							})
+							let curStudent = this.students.find(i => i.id === key)
+							if(curStudent){
+								result.push({
+									id: key,
+									name: curStudent.name,
+									value: curItemRecord.other[key]
+								})
+							}
+							
 						}
 						item.result.details = result
 					} else {
 						console.log(this.students)
 						for (let key in curItemRecord.opt) {
-							curItemRecord.opt[key] = curItemRecord.opt[key].map(id => this.students.filter(i => i
-								.id === id)[0].name)
+							let curStudent = this.students.find(i => i.id === key)
+							if(curStudent){
+								curItemRecord.opt[key] = curItemRecord.opt[key].map(id => curStudent.name)
+							}
 						}
 						item.result.details = curItemRecord.opt
 					}
@@ -410,6 +427,9 @@
 					disabled: this.currentQn.progress !== 'pending',
 					ghostClass: "ghost"
 				};
+			},
+			isAreaSurvey(){
+				return this.$route.name === 'manageAreaQuestionnaire'
 			}
 		},
 		watch: {
@@ -419,9 +439,15 @@
 					if (newValue && newValue.id) {
 						if (newValue.progress !== 'pending') {
 							try {
-								let records = await this.getQnRecord(newValue)
-								let items = await this.getBlobItems(newValue)
-								this.makeItemResult(records, items)
+								console.log('BaseQuestionnaire',newValue);
+								if(this.isAreaSurvey){
+									let items = await this.getBlobItems(newValue)
+									this.items = items
+								}else{
+									let records = await this.getQnRecord(newValue)
+									let items = await this.getBlobItems(newValue)
+									this.makeItemResult(records, items)
+								}
 							} catch (e) {
 								console.log(e)
 								this.$Message.error(this.$t('survey.getFileFailTip'))

+ 26 - 6
TEAMModelOS/ClientApp/src/components/questionnaire/BaseSingle.vue

@@ -8,12 +8,15 @@
 			<IconText :text="$t('survey.singleOption')" :color="'#FF871C'" :icon="'md-reorder'"></IconText>
 			<div v-if="options.length">
 				<div v-for="(item,index) in options" :key="index" :ref="'optionBox' + index" class="option-editor-wrap" style="margin-top:10px;display:flex">
-					<span class="fl-center option-order">{{String.fromCharCode(64 + parseInt(index+1))}}</span>
+					<span class="fl-center option-order" :id="'optionOrder' + index">{{String.fromCharCode(64 + parseInt(index+1))}}</span>
 					<div :ref="'singleOption'+index" :data-index="index" style="text-align:left" class="qn-option-editor" @click="optionClick(item)"></div>
-					<span class="fl-center option-delete" @click="deleteOption(index)">
-						<Icon type="md-close" /></span>
+					<span class="fl-center option-delete" >
+						<Icon type="md-close" @click="deleteOption(index)"/>
+						<Icon type="md-checkmark-circle" v-if="needAnswer" :color="trueIndex === index ? '#0bbe88' : '#ccc'" size="20" title="设置为正确答案" style="margin-left: 5px;cursor: pointer;" @click="setTrue(index)"/>
+					</span>
 				</div>
 			</div>
+			<p style="display: block;float: right;margin: 20px 20px 0 20px;font-weight: bold;color: #0bbe88;" v-if="needAnswer">正确答案:{{ answer[0] }}</p>
 			<p class="option-add"><span @click="addOption()"> + {{ $t('survey.addOption') }} </span></p>
 		</div>
 	</div>
@@ -25,7 +28,16 @@
 		components: {
 			IconText
 		},
-		props: ['editInfo'],
+		props: {
+			editInfo:{
+				type:Object,
+				default:() => {}
+			},
+			needAnswer:{
+				type:Boolean,
+				default:false
+			}
+		},
 		data() {
 			return {
 				options: [...new Array(4).keys()], // 默认四个选项
@@ -37,10 +49,16 @@
 				stemContent: '',
 				optionsContent: [],
 				optionEditors: [],
+				answer:['A']
 			}
 		},
 		created() {},
 		methods: {
+			setTrue(index){
+				this.trueIndex = index
+				this.answer = [document.getElementById('optionOrder' + index).innerHTML]
+				console.log(this.answer);
+			},
 			resetContent() {
 				console.log('重置')
 				this.options = [...new Array(4).keys()],
@@ -154,6 +172,7 @@
 			
 			/* 根据下标渲染对应的字母顺序 */
 			renderIndex(index) {
+				console.log(index);
 				return String.fromCharCode(64 + parseInt(index + 1))
 			},
 			
@@ -164,7 +183,7 @@
 					this.optionsContent.splice(index, 1)
 					let textWrap = this.$refs['optionBox' + index][0]
 					textWrap.remove()
-					
+					this.trueIndex = 0
 					this.refreshOrder()
 				} else {
 					this.$Message.warning(this.$t('survey.optionLimitTip'))
@@ -191,7 +210,8 @@
 				})
 				this.$emit('onSave',{
 					stemContent:this.stemContent,
-					optionsContent:arr
+					optionsContent:arr,
+					answer:this.answer
 				})
 			},
 

+ 6 - 6
TEAMModelOS/ClientApp/src/components/selflearn/ExerciseList.vue

@@ -54,12 +54,12 @@
                 <span class="filter-title">{{$t('evaluation.filter.level')}}:</span>
                 <CheckboxGroup v-model="filterField" border @on-change="filterFieldChange">
                     <Checkbox label="all">{{$t('evaluation.filter.all')}}</Checkbox>
-                    <Checkbox :label="1">{{$t('evaluation.level1')}}<span class="filter-count" v-if="filterOrigin === schoolCode"></span></Checkbox>
-                    <Checkbox :label="2">{{$t('evaluation.level2')}}<span class="filter-count" v-if="filterOrigin === schoolCode"></span></Checkbox>
-                    <Checkbox :label="3">{{$t('evaluation.level3')}}<span class="filter-count" v-if="filterOrigin === schoolCode"></span></Checkbox>
-                    <Checkbox :label="4">{{$t('evaluation.level4')}}<span class="filter-count" v-if="filterOrigin === schoolCode"></span></Checkbox>
-                    <Checkbox :label="5">{{$t('evaluation.level5')}}<span class="filter-count" v-if="filterOrigin === schoolCode"></span></Checkbox>
-                    <Checkbox :label="6">{{$t('evaluation.level6')}}<span class="filter-count" v-if="filterOrigin === schoolCode"></span></Checkbox>
+                    <Checkbox :label="1">{{$t('evaluation.level1')}}</Checkbox>
+                    <Checkbox :label="2">{{$t('evaluation.level2')}}</Checkbox>
+                    <Checkbox :label="3">{{$t('evaluation.level3')}}</Checkbox>
+                    <Checkbox :label="4">{{$t('evaluation.level4')}}</Checkbox>
+                    <Checkbox :label="5">{{$t('evaluation.level5')}}</Checkbox>
+                    <Checkbox :label="6">{{$t('evaluation.level6')}}</Checkbox>
                 </CheckboxGroup>
             </div>
             <div class="filter-item">

+ 1 - 1
TEAMModelOS/ClientApp/src/components/selflearn/NewChooseContent.vue

@@ -70,7 +70,7 @@
                                 <Radio class="radio-width" :key="index" v-for="(item,index) in contentTypeList" :label="item.type">{{item.label}}</Radio>
                             </RadioGroup>
                         </div>
-                        <Input v-model="keyWord" class="seach-input" suffix="ios-search" :placeholder="$t('selflearn.choose.searchHolder')" clearable style="width: 240px" size="small" @on-change="searchKeyWord" />
+                        <Input v-model="keyWord" class="seach-input light-iview-input" suffix="ios-search" :placeholder="$t('selflearn.choose.searchHolder')" clearable style="width: 240px" size="small" @on-change="searchKeyWord" />
                     </div>
                     <div class="file-content-wrap">
                         <Table ref="fileTable" :columns="fileColumns" :data="fileListShow" max-height="660" class="animated fadeIn" @on-select="selectFile" @on-select-cancel="cancelSelectFile" @on-select-all="selectAllFile" @on-select-all-cancel="cancelSelectAllFile">

+ 5 - 5
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseBar.vue

@@ -119,7 +119,7 @@
                         // data: data.datas.map(item => item.name).concat([this.$t('totalAnalysis.ach_text5'), this.$t('totalAnalysis.ach_text6')]),
                         data: this.subjectSeries.map(item => item.name).concat([this.$t('totalAnalysis.ach_text5'), this.$t('totalAnalysis.ach_text6')]),
                         textStyle: {
-                            color: '#e4eadb'
+                            color: '#303030'
                         }
                     },
                     // ---  提示框 ----
@@ -186,7 +186,7 @@
                         textStyle: {
                             color: '#fff'
                         },
-                        borderColor: '#90979c',
+                        // borderColor: '#C3C3C3',
                         borderRadius: '5px'
                     }, {
                         'type': 'inside',
@@ -241,9 +241,9 @@
                             fontFamily: 'Microsoft YaHei'
                         },
                         splitLine: {
-                            show: true,
+                            show: false,
                             lineStyle: {
-                                color: '#4c504a'
+                                color: '#C3C3C3'
                             }
                         },
                         splitArea: {
@@ -297,7 +297,7 @@
                         splitLine: {
                             show: true,
                             lineStyle: {
-                                color: '#4c504a',
+                                color: '#C3C3C3',
                                 width: 0.5,
                                 type: 'solid'
                             }

+ 8 - 4
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseEntryBar.vue

@@ -21,7 +21,7 @@
                     legend: {
                         //  data:['班级进线人数','班级总人数']
                         textStyle: {
-                            color: '#e4eadb'
+                            color: '#303030'
                         }
                     },
                     tooltip: {
@@ -84,7 +84,7 @@
                         textStyle: {
                             color: '#fff'
                         },
-                        borderColor: '#90979c'
+                        // borderColor: '#eee'
                     }, {
                         'type': 'inside',
                         'show': true,
@@ -190,7 +190,7 @@
                             splitLine: {
                                 show: true,
                                 lineStyle: {
-                                    color: '#4c504a',
+                                    color: '#C3C3C3',
                                     width: 0.5,
                                     type: 'solid'
                                 },
@@ -205,7 +205,8 @@
                                 }
                             }
                         },
-                         {
+                        {
+                            show: true,
                             type: 'value',
                             min: 0,
                             splitLine: {
@@ -217,6 +218,9 @@
                             nameTextStyle: {
                                 color: '#999'
                             },
+                            axisLine: {
+                                show: false,
+                            },
                             axisLabel: {
                                 show: true, // 是否显示
                                 inside: false, // 是否朝内

+ 43 - 37
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseMyTable.vue

@@ -8,7 +8,7 @@
 			<div class="myTable-title">{{ tableName }}</div>
 			<div>
 				<span @click="exportData(3)" class="table-export-btn">
-					<Icon type="ios-share-alt" /> {{$t('totalAnalysis.exportTable').slice(0,2)}}
+					<Icon type="ios-share-alt" /> {{$t('totalAnalysis.exportTable')}}
 				</span>
 				<span class="table-tips" v-if="tips">{{tips}}</span>
 				<span class="table-tips" v-if="!tips"></span>
@@ -245,7 +245,7 @@
 					},
 					style: {
 						cursor: 'pointer',
-						color: '#00ffd2',
+						color: '#70B1E7',
 						fontWeight: 'bold'
 					}
 				}, params.row.id)
@@ -402,7 +402,7 @@
 						style: {
 							fontSize: '16px',
 							fontWeight: '600',
-							color: '#03efdb',
+							color: '#70B1E7',
 							cursor: 'pointer',
 							display: 'inline-block',
 							float: 'left'
@@ -432,7 +432,7 @@
 						style: {
 							fontSize: '16px',
 							fontWeight: '600',
-							color: '#03efdb',
+							color: '#70B1E7',
 							cursor: 'pointer',
 							display: 'inline-block',
 							float: 'left'
@@ -545,20 +545,20 @@
 	.myTable .ivu-table td,
 	.myTable .ivu-table th {
 		/*border: none;*/
-		color: #e4eadb;
-		border-color: #595959;
+		/* color: #e4eadb; */
+		/* border-color: #595959; */
 	}
 
 	.myTable .ivu-table-wrapper {
 		/*border:none;*/
-		border-color: #595959;
-		border-right: 1px solid #595959;
+		/* border-color: #595959; */
+		/* border-right: 1px solid #595959; */
 	}
 
 	.myTable .ivu-table::before,
 	.myTable .ivu-table::after {
 		height: 1px;
-		background: #595959;
+		/* background: #595959; */
 	}
 
 	.myTable .ivu-table {
@@ -568,13 +568,13 @@
 
 	.myTable .ivu-table,
 	.myTable .ivu-table td {
-		background: #343434;
+		/* background: #343434; */
 		text-align: center;
 		position: relative;
 	}
 
 	.myTable .ivu-table th {
-		background: rgba(107, 107, 107, 0.19);
+		/* background: rgba(107, 107, 107, 0.19); */
 		text-align: center;
 		position: relative;
 	}
@@ -584,21 +584,22 @@
 	}
 
 	.myTable .ivu-table-sort i {
-		color: #fff;
+		/* color: #fff; */
 		margin-left: 1px;
 	}
 
 	.myTable .ivu-table-sort i.on {
-		color: #4cf8da;
+		/* color: #4cf8da; */
 	}
 
 	.myTable .ivu-table-header .ivu-table-cell {
 		font-size: 14px;
 		font-weight: bold;
+		word-break: break-word;
 	}
 
 	.myTable .ivu-table-header {
-		background: rgba(228, 234, 219, 0.08);
+		/* background: rgba(228, 234, 219, 0.08); */
 	}
 
 	.myTable .table-rank-value {
@@ -624,44 +625,40 @@
 	}
 
 	.myTable .ivu-page-item {
-		background: rgba(40, 40, 40, .5);
+		/* background: rgba(40, 40, 40, .5); */
 	}
 
 	.myTable .ivu-page-item:hover {
-		border-color: #e4eadb;
+		/* border-color: #e4eadb; */
 	}
 
-	.myTable .ivu-page-item-active {
-		background: #bfbfb9;
+	.myTable .ivu-page-item-active,
+	.myTable .ivu-page-item:hover {
+		background: #2d8cf0;
 	}
 
-	.myTable .ivu-page-item a {
-		color: #f1f1f1;
+	.myTable .ivu-page-item-active a,
+	.myTable .ivu-page-item:hover a {
+		/* border-color: #e4eadb; */
+		color: #FFF;
 	}
 
 	.myTable .ivu-page-next,
 	.myTable .ivu-page-prev {
-		background: rgba(0, 0, 0, 0);
+		/* background: rgba(0, 0, 0, 0); */
 	}
 
-	.myTable .ivu-page-next a,
-	.myTable .ivu-page-prev a {
-		color: #e4eadb;
+	.myTable .ivu-page-next:hover a,
+	.myTable .ivu-page-prev:hover a {
+		color: #FFF;
 	}
 
 	.myTable .ivu-page-next:hover,
 	.myTable .ivu-page-prev:hover {
-		border-color: #e4eadb;
+		background: #2d8cf0;
+		/* border-color: #e4eadb; */
 	}
 
-	.myTable .ivu-page-item-active,
-	.myTable .ivu-page-item:hover a {
-		border-color: #e4eadb;
-	}
-
-	.myTable .ivu-page-item-active a {
-		color: #595959;
-	}
 
 	.myTable .ivu-table-fixed {
 		/*padding-top:3px;*/
@@ -678,16 +675,16 @@
 		display: flex;
 		justify-content: space-between;
 		padding-right: 5px;
-		height: 40px;
+		/* height: 40px; */
 		margin-bottom: 10px;
 	}
 
 	.table-subject-select .table-tips {
 		font-size: 14px;
-		color: #4cf8da;
+		color: #70B1E7;
 		font-weight: bold;
 		position: absolute;
-		right: 65px;
+		right: 120px;
 		top: 10px;
 	}
 
@@ -717,18 +714,22 @@
 	.table-subject-select .table-export-btn {
 		font-size: 14px;
 		font-weight: bold;
-		width: 50px;
 		position: absolute;
 		right: 5px;
 		top: 10px;
 		cursor: pointer;
 	}
 
+	.table-subject-select .table-export-btn:hover{
+		color: var(--normal-icon-color);
+	}
+
 	.myTable .table-entry-status {
 		position: absolute;
 		right: 20px;
 		top: 15px;
 		background: #209a31;
+		color: #FFF;
 		width: 15px;
 		height: 15px;
 		display: flex;
@@ -759,5 +760,10 @@
 
 	.myTable .myTable-title {
 		font-size: 16px;
+		font-weight: 500;
+		color: var(--primary-text-color);
+		border-left: 5px solid var(--tabs-bottom-color);
+		padding-left: 10px;
+		margin-bottom: 10px;
 	}
 </style>

+ 2 - 2
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseRadar.vue

@@ -38,7 +38,7 @@
                         triggerEvent: true,
                         name: {
                             textStyle: {
-                                color: '#fff',
+                                color: '#303030',
                                 borderRadius: 3,
                                 fontSize: 14,
                                 padding: [13, 15]
@@ -61,7 +61,7 @@
                         },
                         axisLine: { // 指向外圈文本的分隔线样式
                             lineStyle: {
-                                color: 'rgba(255,255,255,0.2)'
+                                color: '#f1f1f1'
                             }
                         },
                         splitLine: {

+ 3 - 3
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseScoreRateBar.vue

@@ -94,7 +94,7 @@
 						textStyle: {
 							color: '#fff'
 						},
-						borderColor: '#90979c'
+						// borderColor: '#90979c'
 					}, {
 						'type': 'inside',
 						'show': true,
@@ -108,7 +108,7 @@
 							show: true
 						},
 						axisLine: {
-							show: true
+							show: false
 						},
 						axisLabel: {
 							color: '#aaaaaa',
@@ -116,7 +116,7 @@
 							align: 'left'
 						},
 						splitLine: {
-							show: true,
+							show: false,
 							lineStyle: {
 								color: '#4c504a',
 								width: 0.5,

+ 5 - 4
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue

@@ -168,10 +168,10 @@
                                             icon-class="noAns" />
                                 </div>
                             </i-col>
-                            <i-col :xs="2" :sm="2" :md="1" :lg="1">
+                            <i-col :xs="2" :sm="2" :md="1" :lg="2">
                                 <div class="qtype">{{ !question.parent ? getTestType(question.type) : getTestType(question.parentInfo.type) }}</div>
                             </i-col>
-                            <i-col :xs="18" :sm="18" :md="21" :lg="21">
+                            <i-col :xs="18" :sm="18" :md="21" :lg="19">
                                 <div class="qdesc">
                                     <div v-if="!question.parent" style="display:inline-flex">
                                         <p style="max-width:75px;font-weight:600">{{question.paperIndex}}.</p>
@@ -189,7 +189,7 @@
                                     </div>
                                 </div>
                             </i-col>
-                            <i-col :xs="2" :sm="2" :md="1" :lg="1">
+                            <i-col :xs="2" :sm="2" :md="1" :lg="2">
                                 <div class="qScore">
                                     <span v-if="examInfo.stuScore[index] != -1">{{examInfo.stuScore[index]}}/{{question.score}}</span>
                                     <span v-if="examInfo.stuScore[index] == -1">{{$t("studentWeb.exam.report.noScore")}}</span>
@@ -829,6 +829,7 @@
         border-radius: 4px;
         padding: 2px;
         text-align: center;
+        max-width: fit-content;
     }
 
     .qtypeEn {
@@ -861,7 +862,7 @@
 
     .qAnaly {
         margin-top: 0px;
-        padding-left: 8.5%;
+        padding-left: 12.5%;
     }
 
     @media screen and (max-width: 767px) {

+ 5 - 3
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperTest.vue

@@ -80,9 +80,11 @@
                 <svg-icon icon-class="logout" />
             </span>
             <span class="testTitleText">{{$t("studentWeb.home.exam")}}:{{ getItemTitle.name }}</span>
-            <div class="myProgressBar" v-if="!isWrong">
-                <span class="myTestProgresstitle">{{$t("studentWeb.exam.testpop.completion")}}</span>
-                <Progress style="margin-top:15px" :percent="completeRate" />
+            <div v-if="!isWrong">
+                <div class="myTestProgresstitle" :style="{'right': $store.getters.getCurrentLaguage == 'en-us' ? '-69%' : '-74%'}">{{$t("studentWeb.exam.testpop.completion")}}</div>
+                <div class="myProgressBar">
+                    <Progress style="margin-top:15px" :percent="completeRate" />
+                </div>
             </div>
             <button v-if="closeTest" class="submitBtn" @click="openWarmMessage(isWrong ? 5 : 2)" :class="{ hintClick: hintHandon() }">{{isWrong ? $t("studentWeb.exam.testpop.submitted1") : $t("studentWeb.exam.testpop.submitted")}}</button>
             <button v-if="!closeTest" class="submitBtn" :class="{ hintClick: hintHandon()}">{{$t("studentWeb.exam.testpop.finish")}}</button>

+ 3 - 2
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/composePaper.vue

@@ -3,7 +3,7 @@
         <div id="textArea"> </div>
         <Modal v-model="markStatus" fullscreen :title="$t('studentWeb.exam.answer')" footer-hide  ref="compose">
                 <!-- <BaseMyCanvas v-if="markStatus" :bgImg="markBg" @onCloseModal="closeModal" :isStudent="markStatus" @onSaveCanvas="saveMark"></BaseMyCanvas> -->
-                <BaseCanvas v-if="markStatus" :bgImg="markBg" @onCloseModal="closeModal" :isStudent="markStatus" @onSaveCanvas="saveMark"></BaseCanvas>
+                <BaseCanvas v-if="markStatus" :vm="vm" :bgImg="markBg" @onCloseModal="closeModal" :isStudent="markStatus" @onSaveCanvas="saveMark"></BaseCanvas>
         </Modal>
         <iframe class="frame" id="answerIframe" :srcdoc="itemInfo.question"></iframe>
     </div>
@@ -37,8 +37,9 @@
                 default: false
             }
         },
-        data() {
+        data(vm) {
             return {
+                vm:vm,
                 tabName: 'exercise',
                 editorContent: "",
                 examInfo: [],

+ 9 - 0
TEAMModelOS/ClientApp/src/components/student-web/HomeView/HomeView.vue

@@ -361,6 +361,7 @@ export default {
                     let data = []
                     for (let item of res.datas) {
                         item.eventType = item.type
+                        item.progress = this.timeStatus(item)
                         data.push(item)
                     }
                     this.testData = [...this.testData, ...data]
@@ -373,6 +374,14 @@ export default {
                 this.isLoading = false
             })
         },
+        timeStatus(data) {
+            let date = (new Date()).getTime() //当前时间
+            if (date >= data.endTime) {
+                return 'finish'
+            } else {
+                return 'going'
+            }
+        },
         // 今日截至活动
         getTodayAct() {
             let todayAct = []

+ 6 - 1
TEAMModelOS/ClientApp/src/components/syllabus/DragTree.less

@@ -7,6 +7,11 @@
     // color: #fff;
     padding-top: 10px;
     padding-bottom: 100px;
+	
+	.ivu-tooltip-inner{
+		max-width: none;
+		font-size: 12px;
+	}
   }
   
   .el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{
@@ -145,7 +150,7 @@
     margin-left: 2%;
     width: 96%;
     height: 40px;
-    background: rgb(11, 151, 117);
+    background: var(--assist-color-light);
     border: none;
     color: #fff;
     margin-top: 30px;

+ 8 - 5
TEAMModelOS/ClientApp/src/components/syllabus/DragTree.vue

@@ -8,11 +8,11 @@
 					<span class="tree-node-lable">
 						{{data.title}}
 						<!-- {{data.id}} -->
-						<Icon type="md-cube" color="#00c38d" :title="$t('syllabus.tree.hasResource')" v-if="data.rnodes && data.rnodes.length" />
-						<Icon type="md-git-compare" color="#00c38d" :title="$t('syllabus.tree.hasCoEdit')" v-if="hasEditAuth(data) && isSchool" />
-						<Tooltip placement="right">
+						<Icon type="md-cube" color="#70B1E7" :title="$t('syllabus.tree.hasResource')" v-if="data.rnodes && data.rnodes.length" />
+						<Icon type="md-git-compare" color="#70B1E7" :title="$t('syllabus.tree.hasCoEdit')" v-if="hasEditAuth(data) && isSchool" />
+						<Tooltip  placement="right" transfer  theme="light" max-width="none">
 							<Icon type="md-information-circle" color="#b9b9b9" size="18" v-if="hasEditAuth(data) && isSchool"/>
-							<div slot="content">
+							<div slot="content" style="font-size: 12px;">
 								<p>{{ $t('syllabus.latestId') }}:{{ data.creatorName || '' }}</p>
 								<p>{{ $t('syllabus.latestTime') }}:{{ $tools.formatTime(data.updateTime) }}</p>
 							</div>
@@ -24,7 +24,7 @@
 						<Icon type="ios-remove-circle-outline" style="margin-right: 5px;" size="16" />
 						<span style="color: #9f9f9f;font-size: 12px;margin-right: 20px;"  @click="onIgnoreShare(data)">忽略该章节</span>
 					</span>
-					<span class="custom-tree-tools" v-if="((hasEditAuth(data) || $access.can('admin.*|Syllabus_Edit')) && !inShareView)">
+					<span class="custom-tree-tools" v-if="((hasEditAuth(data) || $access.can('admin.*|Syllabus_Edit')) && !inShareView) && !inSchoolAbility">
 						<Icon type="md-create" size="16" :title="$t('syllabus.tree.edit')" @click="onEditItem(node,data,$event)" />
 						<Icon type="md-add" size="16" :title="$t('syllabus.tree.add')" @click="onAddNode(node,data,$event)" />
 						<Icon type="md-trash" size="16" :title="$t('syllabus.tree.remove')" @click="remove(node,data)" v-if="!isFirstLevel(data) ||  (canDeleteChapter && isFirstLevel(data))"/>
@@ -771,6 +771,9 @@
 			inShareView(){
 				return !this.isSchool && this.$parent.activeTab === 'fromShare'
 			},
+			inSchoolAbility(){
+				return this.$route.name === 'abilityMgmt'
+			},
 			volumeList(){
 				return this.$parent.myVolumeList
 			}

+ 11 - 10
TEAMModelOS/ClientApp/src/components/vote/BaseVoteForm.less

@@ -1,8 +1,8 @@
-@main-bgColor: rgb(40,40,40); //主背景颜
+@main-bgColor: rgb(40,40,40); //锟斤拷锟斤拷锟斤拷锟斤拷
 @borderColor: #424242;
 @primary-color: #1fb06d;
-@primary-textColor: #393939; //文本主颜
-@second-textColor: #636363; //文本副级颜
+@primary-textColor: #393939; //锟侥憋拷锟斤拷锟斤拷
+@second-textColor: #636363; //锟侥憋拷锟斤拷锟斤拷锟斤拷
 @primary-fontSize: 14px;
 @second-fontSize: 16px;
 
@@ -29,7 +29,7 @@
 	}
 
     .ivu-form .ivu-form-item-label {
-        color: #5a5a5a;
+        // color: #5a5a5a;
     }
 
     .ivu-form-item:not(:first-child) {
@@ -47,6 +47,7 @@
         width: 48%;
         border: none;
         height: 38px;
+        background-color: rgb(236, 236, 236);
     }
 
     .ivu-input::-webkit-input-placeholder {
@@ -55,13 +56,13 @@
 
     .ivu-input, .ivu-select-single .ivu-select-selection,
     .ivu-select-multiple .ivu-select-selection {
-        border: 1px solid #c1c1c1;
+        // border: 1px solid #c1c1c1;
         margin-top: 10px;
         height: 40px;
         line-height: 40px;
 		padding-left: 8px;
-        color: @primary-textColor;
-		background-color: transparent;
+        /* color: @primary-textColor;
+		background-color: transparent; */
     }
 
     .ivu-input-number-input,
@@ -191,20 +192,20 @@
     }
 
     .w-e-text {
-        /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
+        /*����������߿������� �߿��ֱ��Ӧ�����������ijߴ�*/
         &::-webkit-scrollbar {
             // width: 4px;
             // height: 16px;
             // background-color: #d6d6d6;
         }
-        /*定义滚动条轨道 内阴影+圆角*/
+        /*锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 锟斤拷锟斤拷影+圆锟斤拷*/
         &::-webkit-scrollbar-track {
    //          -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
    //          border-radius: 10px;
 			// width: 0;
    //          background-color: transparent;
         }
-        /*定义滑块 内阴影+圆角*/
+        /*锟斤拷锟藉滑锟斤拷 锟斤拷锟斤拷影+圆锟斤拷*/
         &::-webkit-scrollbar-thumb {
             // border-radius: 0;
             // -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);

+ 260 - 176
TEAMModelOS/ClientApp/src/components/vote/BaseVoteForm.vue

@@ -1,41 +1,36 @@
 <template>
-	<div class="component-vote-form">
+	<div class="component-vote-form light-iview-form light-el-input">
 		<Form ref="voteForm" :model="voteForm" label-position="top" :rules="ruleValidate" :disabled="!voteFormEdit"
-		 hide-required-mark>
+			hide-required-mark>
 			<FormItem :label="$t('vote.form.name')" prop="name">
-				<Input :class="!voteFormEdit ? 'vote-form-disabled':''" v-model="voteForm.name" :placeholder="$t('vote.form.namePlace')"></Input>
+				<Input :class="!voteFormEdit ? 'vote-form-disabled':''" v-model="voteForm.name"
+					:placeholder="$t('vote.form.namePlace')"></Input>
 			</FormItem>
 			<FormItem :label="$t('vote.form.target')" prop="classes">
-				<!-- <RadioGroup v-model="classType" @on-change="onClassTypeChange" v-if="voteFormEdit">
-					<Radio label="private" v-if="getCurScope === 'private'">{{ $t('vote.form.privateClass') }}</Radio>
-					<Radio label="school">{{ $t('vote.form.schoolClass') }}</Radio>
-				</RadioGroup> -->
+				<!-- 预览状态 -->
 				<div v-if="!voteFormEdit && curVoteItem" class="vote-class">
 					<span v-for="item in classNameArr" class="vote-class-item">{{ item.name }}</span>
 				</div>
-				<!-- <Select multiple v-model="voteForm.classes" :class="!voteFormEdit ? 'vote-form-disabled':''" :placeholder="$t('vote.form.targetPlace')"
-				 :not-found-text="$t('vote.form.noFoundText')" v-else>
-					<Option v-for="(item,index) in classRooms.filter(i=>i.scope === classType)" :value="item.id" :key="index">{{ item.name }}</Option>
-				</Select> -->
+				<!-- 编辑状态 -->
 				<div v-else>
-					<BaseClassSelect :classes="classTargets" :type="targetType" @onChange="onTargetChange" ref="classSelectRef" v-if="getCurScope === 'school' && curVoteItem"></BaseClassSelect>
-					<BaseClassSelectPri :classes="classTargets" :scope="classType" @onChange="onTargetChange" ref="classSelectRef" v-if="getCurScope === 'private' && curVoteItem"></BaseClassSelectPri>
+					<!-- 区级选学校 -->
+					<div v-if="isAreaVote">
+						<el-cascader size="small" :show-all-levels="false" clearable filterable v-model="schoolTarget"
+							:options="csOptions" :props="props" @change="treeChange" style="width:100%;">
+						</el-cascader>
+					</div>
+					<div v-else>
+						<!-- 校级选教研组或者学生名单 -->
+						<BaseClassSelect :classes="classTargets" :type="targetType" @onChange="onTargetChange"
+							ref="classSelectRef" v-if="getCurScope === 'school' && curVoteItem"></BaseClassSelect>
+						<BaseClassSelectPri :classes="classTargets" :scope="classType" @onChange="onTargetChange"
+							ref="classSelectRef" v-if="getCurScope === 'private' && curVoteItem"></BaseClassSelectPri>
+					</div>
 				</div>
-				
-				<!-- <el-cascader size="small" :show-all-levels="false" clearable filterable v-model="voteForm.classes" :options="csOptions" :props="props" @change="treeChange" style="width:100%;">
-				</el-cascader> -->
 			</FormItem>
-
-			<!-- <FormItem :label="$t('vote.form.time')" prop="rangeTime">
-				<DatePicker type="datetimerange" transfer @on-change="onChangeRange" @on-open-change="onOpenChange" :options="options3" format="yyyy-MM-dd HH:mm"
-				 :class="!voteFormEdit ? 'vote-form-disabled':''" :editable="isDateEdit" :value="[voteForm.startTime,voteForm.endTime]"
-				 :placeholder="$t('vote.form.endTimePlace')"></DatePicker>
-			</FormItem> -->
-			
-			<FormItem :label="$t('learnActivity.createEv.publishType')" prop="publishModel" v-show="voteFormEdit">
+			<FormItem :label="$t('learnActivity.createEv.publishType')" prop="publishModel" v-show="voteFormEdit && !isAreaVote">
 				<Checkbox v-model="isImmediate">{{$t('global.publishType1')}}</Checkbox>
 			</FormItem>
-			
 			<FormItem :label="$t('learnActivity.createEv.startTime')" v-if="!isImmediate || !voteFormEdit"
 				prop="startTime">
 				<DatePicker v-show="voteFormEdit" type="datetime" :options="startOption" format="yyyy/MM/dd HH:mm"
@@ -45,10 +40,10 @@
 					{{ $tools.formatTime(voteForm.startTime,'yyyy-MM-dd hh:mm') }}
 				</div>
 			</FormItem>
-			
-			<FormItem :label="$t('learnActivity.createEv.endTime')"  prop="endTime">
-				<DatePicker v-show="voteFormEdit" type="datetime" :options="endOption" format="yyyy/MM/dd HH:mm" v-model="voteForm.endTime"
-					split-panels @on-change="onChangeEndTime" :placeholder="$t('learnActivity.createEv.eTimeHolder')" style="width:100%"></DatePicker>
+			<FormItem :label="$t('learnActivity.createEv.endTime')" prop="endTime">
+				<DatePicker v-show="voteFormEdit" type="datetime" :options="endOption" format="yyyy/MM/dd HH:mm"
+					v-model="voteForm.endTime" split-panels @on-change="onChangeEndTime"
+					:placeholder="$t('learnActivity.createEv.eTimeHolder')" style="width:100%"></DatePicker>
 				<div v-show="!voteFormEdit" style="margin:10px;font-size:16px;font-weight:bold;">
 					{{ $tools.formatTime(voteForm.endTime,'yyyy-MM-dd hh:mm') }}
 				</div>
@@ -56,7 +51,8 @@
 
 			<FormItem :label="$t('vote.form.description')" prop="description">
 				<div ref="descriptionEditor" style="text-align:left" v-show="voteFormEdit"></div>
-				<div v-html="voteForm.description" v-show="!voteFormEdit" style="margin:10px;font-size:16px;font-weight:bold;"></div>
+				<div v-html="voteForm.description" v-show="!voteFormEdit"
+					style="margin:10px;font-size:16px;font-weight:bold;"></div>
 			</FormItem>
 
 			<FormItem :label="$t('vote.form.optionSetting')" prop="attachment" ref="optionsBox">
@@ -64,18 +60,24 @@
 					<div v-for="(item,index) in voteOptions" :key="index" class="option-editor-wrap">
 						<div v-show="voteFormEdit" style="display: flex;">
 							<span class="option-order">{{ index + 1 }}
-								<Icon type="md-trash" @click="deleteOption(index)" /></span>
-							<div :ref="'voteOption'+index" style="text-align:left" class="option-editor" @click="optionClick(index)"></div>
+								<Icon type="md-trash" @click="deleteOption(index)" />
+							</span>
+							<div :ref="'voteOption'+index" style="text-align:left" class="option-editor"
+								@click="optionClick(index)"></div>
 						</div>
 						<div v-show="!voteFormEdit">
 							<span style="margin-left: 10px;">{{ index + 1 }} .</span>
-							<div v-html="(voteOptionsContent[index]) ? voteOptionsContent[index].value : ''" v-show="!voteFormEdit" style="margin:10px;font-size:16px;font-weight:bold;display: inline-block;vertical-align: middle;"></div>
+							<div v-html="(voteOptionsContent[index]) ? voteOptionsContent[index].value : ''"
+								v-show="!voteFormEdit"
+								style="margin:10px;font-size:16px;font-weight:bold;display: inline-block;vertical-align: middle;">
+							</div>
 						</div>
 					</div>
 				</div>
 
-				<p style="float:right;color:#BDBDBD;cursor:pointer" @click="onAddOption" v-show="voteFormEdit">
-					<Icon type="md-add" />{{ $t('vote.form.addOption') }}</p>
+				<p style="float:right;color:#757575;cursor:pointer" @click="onAddOption" v-show="voteFormEdit">
+					<Icon type="md-add" />{{ $t('vote.form.addOption') }}
+				</p>
 			</FormItem>
 
 			<FormItem :label="$t('vote.form.times')">
@@ -103,8 +105,10 @@
 			</FormItem>
 
 			<FormItem v-show="voteFormEdit">
-				<Button type="primary" class="btn-save" @click="handleSubmit('voteForm')" :loading="isBtnLoading">{{ $t('vote.form.save') }}</Button>
-				<Button @click="handleCancel('voteForm')" class="btn-reset" style="margin-left: 8px">{{ $t('vote.form.cancel') }}</Button>
+				<Button type="primary" class="btn-save" @click="handleSubmit('voteForm')"
+					:loading="isBtnLoading">{{ $t('vote.form.save') }}</Button>
+				<Button @click="handleCancel('voteForm')" class="btn-reset"
+					style="margin-left: 8px">{{ $t('vote.form.cancel') }}</Button>
 			</FormItem>
 		</Form>
 	</div>
@@ -123,10 +127,16 @@
 			}
 		},
 		data(vm) {
-			 const _this = this
+			const _this = this
 			return {
-				classTargets:[],
-				classNameArr:[],
+				props: {
+					multiple: true,
+					value: 'id',
+					label: 'name',
+				},
+				schoolTarget: [],
+				classTargets: [],
+				classNameArr: [],
 				classType: 'private',
 				curVoteItem: null,
 				isAdd: true,
@@ -185,11 +195,11 @@
 						message: vm.$t('vote.form.ruleName'),
 						trigger: 'blur'
 					}],
-					description: [{
-						required: true,
-						message: vm.$t('vote.form.ruleDescription'),
-						trigger: 'blur'
-					}],
+					// description: [{
+					// 	// required: true,
+					// 	message: vm.$t('vote.form.ruleDescription'),
+					// 	trigger: 'blur'
+					// }],
 					startTime: [{
 						required: true,
 						type: 'date',
@@ -205,18 +215,21 @@
 				},
 				startOption: {
 					disabledDate(date) {
-					    return date && date.valueOf() < Date.now() - 86400000
+						return date && date.valueOf() < Date.now() - 86400000
 					}
 				},
 				endOption: {
 					disabledDate(date) {
 						let data = _this.voteForm.startTime ? _this.voteForm.startTime : Date.now()
-					    return data && data > date.valueOf() + 86400000
+						return data && data > date.valueOf() + 86400000
 					}
 				},
-				classIds:[],
-				groupList:[],
-				targetType:''
+				classIds: [],
+				groupList: [],
+				targetType: '',
+				schList: [],
+				csOptions: [],
+				areaId: sessionStorage.getItem('areaId'),
 			}
 		},
 		created() {
@@ -225,29 +238,72 @@
 				console.log(res)
 				this.classRooms = res
 			})
-			
+
 			this.findResearchList()
+			if (this.isAreaVote) {
+				this.getAreaTargets()
+			}
 		},
 		methods: {
+			treeChange(data) {
+				console.log('选择数据', this.schoolTarget)
+			},
+			getAreaTargets() {
+				this.$api.ability.findAreaGroup({
+					id: this.areaId
+				}).then(
+					res => {
+						if (res.gr && res.gr.length) {
+							this.schList = res.gr
+							this.csOptions = []
+							res.gr.forEach(sItem => {
+								let i = {
+									id: sItem.id,
+									name: sItem.sname,
+									children: []
+								}
+								sItem.name.forEach((gItem,gIndex) => {
+									i.children.push({
+										id: sItem.sname + '-' + gItem,
+										name: sItem.sname + '-' + gItem,
+									})
+								})
+								if (!i.children.length) {
+									i.children.push({
+										id: sItem.sname + '-' + '所有老师(未分组)',
+										name: sItem.sname + '-' + '所有老师(未分组)'
+									})
+								}
+								this.csOptions.push(i)
+							})
+						}
+						console.log(this.schList)
+
+					},
+					err => {
+						console.log(err)
+					}
+				)
+			},
 			onClassTypeChange(val) {
 				this.voteForm.classes = []
 			},
-			
-			onTargetChange(data){
+
+			onTargetChange(data) {
 				this.voteForm.classes = this.getCurScope === 'school' ? data : data.map(i => i.split('/')[1])
 				this.voteForm.targets = this.getCurScope === 'school' ? [] : data
 			},
-			
+
 			onChangeSTime(val) {
 				let endTime = this.voteForm.endTime || Date.now()
 				if (new Date(val).getTime() >= new Date(endTime).getTime()) {
 					this.voteForm.endTime = null
 				}
 			},
-			
-			onChangeEndTime(val){
+
+			onChangeEndTime(val) {
 				if (val.indexOf('00:00') > 0) {
-				    val = val.replace('00:00', '23:59')
+					val = val.replace('00:00', '23:59')
 					this.voteForm.endTime = val
 				}
 			},
@@ -257,25 +313,31 @@
 			 */
 			async handleSubmit(name) {
 				this.isBtnLoading = true
+				let hasTargets = (!this.isAreaVote && this.voteForm.classes.length) || (this.isAreaVote && this.schoolTarget.length)
+				let optionComplete = this.voteOptionsContent.length && this.voteOptionsContent.every(i => i.value !== '')
 				this.$refs[name].validate(async (valid) => {
-					if (valid && this.getSimpleText(this.voteForm.description) && this.voteOptionsContent.length && this.voteForm.classes.length) {
-						if(this.voteForm.selectMax > this.voteOptionsContent.length && this.voteForm.repeat.indexOf('repeat') === -1){
+					if (valid && this.getSimpleText(this.voteForm.description) && optionComplete && hasTargets) {
+						if (this.voteForm.selectMax > this.voteOptionsContent.length && this.voteForm
+							.repeat.indexOf('repeat') === -1) {
 							this.$Message.warning(this.$t('vote.optionMaxTip'))
 							this.isBtnLoading = false
-						}else{
-							if(this.voteForm.selectMax === 1){
+						} else {
+							if (this.voteForm.selectMax === 1) {
 								this.voteForm.repeat = []
 							}
 							console.log(this.voteForm)
-							let classSelectScope = this.$refs.classSelectRef.evaluationInfo.scope
-							let isSchoolClass = this.$refs.classSelectRef.evaluationInfo.scope === 'school' && this.$refs.classSelectRef.privateClassType === 'school'
+							let classSelectScope = this.isAreaVote ? 'school' : this.$refs.classSelectRef
+								.evaluationInfo.scope
+							let isSchoolClass = this.isAreaVote ? false : (this.$refs.classSelectRef.evaluationInfo.scope === 'school' && this.$refs.classSelectRef.privateClassType === 'school')
 							let params = Object.assign({}, this.defaultParams)
+							let areaParams = null
 							let target = []
 							let fileName = this.$tools.guid()
 							let isReset = this.voteForm.isReset.length > 0
-							let isPersonal = this.$route.name === 'personalVote' &&  classSelectScope === 'private'
+							let isPersonal = this.$route.name === 'personalVote' && classSelectScope ===
+								'private'
 							let isSchool = this.$route.name === 'manageVote'
-							
+
 							params.code = this.getCurCode
 							params.scope = isPersonal ? 'private' : 'school'
 							params.name = this.voteForm.name
@@ -292,28 +354,70 @@
 							params.creatorId = this.$store.state.userInfo.TEAMModelId
 							params.voteNum = this.voteForm.selectMax
 							params.times = this.voteForm.times
-							params.school = params.scope === 'school' ?  this.$store.state.userInfo.schoolCode : null
+							params.school = params.scope === 'school' ? this.$store.state.userInfo.schoolCode : null
 							params.tchLists = []
 							params.classes = []
 							params.stuLists = []
 							if (this.isEdit && this.editInfo.id && this.editInfo.code) {
 								params.id = this.editInfo.id
 							}
-							// 如果是校本投票 则需要进一步确定发布对象是教研组还是学生名单
-							if(isSchool && this.$refs.classSelectRef.targetType === 'research'){
-								params.tchLists = this.voteForm.classes
-								params.targetType = 'research'
-							}else if(isSchoolClass){
-								params.classes = this.voteForm.classes
-								params.targetType = 'student'
+
+							// 如果是发布的区级投票 则需要修改保存参数
+							if (this.curVoteItem.owner === 'area') {
+								let schArr = [...new Set(this.schoolTarget.map(i => i[0]))]
+								let para = []
+								schArr.forEach((i, index) => {
+									para.push({
+										sId: i,
+										sName: this.schList.find(j => j.id === i).sname,
+										gName: [],
+										gId:[]
+									})
+									// 如果是区级活动 需要拼接学校加教研组信息
+									this.schoolTarget.forEach(j => {
+										if (j[0] === i) {
+											let groupName = j[1].split('-')[1]
+											if (groupName === '所有老师(未分组)') {
+												para[index].gName = []
+												para[index].gId = ['default']
+											} else {
+												let curSch = this.schList.find(sch => sch.id === i)
+												let groupId = curSch.gId[curSch.name.indexOf(groupName)]
+												para[index].gName.push(groupName)
+												para[index].gId.push(groupId)
+											}
+										}
+									})
+								})
+								delete this.voteForm.classes
+								delete this.voteForm.targets
+								delete this.voteForm.teachers
+								delete this.voteForm.stuLists
+								areaParams = {
+									"id": this.areaId,
+									"para": para,
+									"vote": params
+								}
 							}else{
-								params.stuLists = this.voteForm.classes
-								params.targetType = 'student'
+								// 如果是校本投票 则需要进一步确定发布对象是教研组还是学生名单
+								if (isSchool && this.$refs.classSelectRef.targetType === 'research') {
+									params.tchLists = this.voteForm.classes
+									params.targetType = 'research'
+								} else if (isSchoolClass) {
+									params.classes = this.voteForm.classes
+									params.targetType = 'student'
+								} else {
+									params.stuLists = this.voteForm.classes
+									params.targetType = 'student'
+								}
 							}
-							console.log('提交的投票对象',params)
+							
+							let finalParams = this.isAreaVote ? areaParams : params
+							console.log('提交的投票对象', finalParams)
 							/* 保存BLOB以及COSMOS */
-							this.saveorUpdateVote(params).then(res => {
-								this.$Message.success((this.isEdit && this.editInfo.id) ? this.$t('vote.form.editSuc') : this.$t(
+							this.saveorUpdateVote(finalParams).then(res => {
+								this.$Message.success((this.isEdit && this.editInfo.id) ? this.$t(
+									'vote.form.editSuc') : this.$t(
 									'vote.form.addSuc'))
 								this.$emit('onAddSuccess')
 								this.isBtnLoading = false
@@ -324,12 +428,14 @@
 						}
 					} else {
 						this.isBtnLoading = false
-						if (!this.voteOptionsContent.length) {
-							this.$Message.error(this.$t('vote.form.noCompleteTip'))
-						} else if(!this.voteForm.classes.length){
-							this.$Message.error(this.$t('vote.form.ruleClasses'))
-						} else{
+						if (!optionComplete) {
 							this.$Message.error(this.$t('vote.form.noOptionTip'))
+						} else if (!hasTargets) {
+							this.$Message.error(this.$t('vote.form.ruleClasses'))
+						} else if(!this.getSimpleText(this.voteForm.description)){
+							this.$Message.error('投票详情不能为空!')
+						} else {
+							this.$Message.error(this.$t('vote.form.noCompleteTip'))
 						}
 					}
 				})
@@ -463,13 +569,13 @@
 					}).then(res => {
 						if (!res.error && res.courses) {
 							this.$store.dispatch('user/getSchoolProfile').then(schoolProfile => {
-							 //    let schoolClasses =  schoolProfile.school_classes
+								//    let schoolClasses =  schoolProfile.school_classes
 								// console.log(schoolClasses)
 								r(res.courses)
 							}).catch(err => {
 								r([])
 							})
-							
+
 						} else {
 							j(500)
 							this.$Message.error(this.$t('vote.form.getDataFailTip'))
@@ -526,13 +632,23 @@
 			 */
 			saveorUpdateVote(data) {
 				return new Promise((r, j) => {
-					this.$api.learnActivity.SaveorUpdataVote(data).then(res => {
-						if (!res.error) {
-							r(res)
-						} else {
-							j(res.error)
-						}
-					})
+					if (this.curVoteItem.owner === 'school') {
+						this.$api.learnActivity.SaveorUpdataVote(data).then(res => {
+							if (!res.error) {
+								r(res)
+							} else {
+								j(res.error)
+							}
+						}).catch(e => j(e))
+					} else {
+						this.$api.ability.saveAreaVote(data).then(res => {
+							if (!res.error) {
+								r(res)
+							} else {
+								j(res.error)
+							}
+						}).catch(e => j(e))
+					}
 				})
 
 			},
@@ -542,22 +658,38 @@
 			 * @param item
 			 */
 			async doRender(item) {
-				console.log('需要渲染的投票对象',item)
-				if(item.targetType === 'research'){
-					console.log(this.groupList);
-					let groupNameArr = []
-					item.tchLists.forEach(i => {
-						let findObj = this.groupList.find(j => j.id === i)
-						if(findObj){
-							groupNameArr.push(findObj)
+				console.log('需要渲染的投票对象', item)
+				
+				// 如果是区级投票
+				if(this.isAreaVote){
+					this.classNameArr = item.targets.map(i => {
+						return {
+							name:i
 						}
 					})
-					this.classNameArr = groupNameArr
 				}else{
-					this.classNameArr = item.classes.length ? await this.getClassNameByIds(item.classes) : item.stuLists.length ? await this.getClassNameByIds(item.stuLists) : []
+					if (item.targetType === 'research') {
+						console.log(this.groupList);
+						let groupNameArr = []
+						item.tchLists.forEach(i => {
+							let findObj = this.groupList.find(j => j.id === i)
+							if (findObj) {
+								groupNameArr.push(findObj)
+							}
+						})
+						this.classNameArr = groupNameArr
+					} else {
+						this.classNameArr = item.classes.length ? await this.getClassNameByIds(item.classes) : item
+							.stuLists.length ? await this.getClassNameByIds(item.stuLists) : []
+					}
 				}
+				
+				console.log(this.classNameArr);
+				
+				
 				this.classType = item.classes.length ? 'school' : 'private'
-				this.classTargets = item.targetType === 'research' ? item.tchLists : this.getCurScope === 'school' ? item.classes : item.targets
+				this.classTargets = item.targetType === 'research' ? item.tchLists : this.getCurScope === 'school' ?
+					item.classes : item.targets
 				this.targetType = item.targetType
 				console.log(this.classNameArr)
 				this.voteForm = null
@@ -568,7 +700,8 @@
 					name: item.name,
 					code: item.code,
 					targets: item.targets,
-					classes: item.targetType === 'research' ? item.tchLists : item.classes.length ? item.classes : item.stuLists,
+					classes: item.targetType === 'research' ? item.tchLists : item.classes.length ? item.classes :
+						item.stuLists,
 					startTime: item.startTime ? new Date(item.startTime) : '',
 					endTime: item.endTime ? new Date(item.endTime) : '',
 					description: item.description,
@@ -579,11 +712,11 @@
 					voteNum: item.voteNum || 1,
 					isReset: []
 				}
-				this.isImmediate = false
+				this.isImmediate = item.isImmediate || false
 				this.descriptionEditor.txt.html(item.description)
 				this.voteOptionsContent = item.options
 				this.voteOptions = item.options.map((item, index) => index)
-				
+
 				this.$nextTick(() => {
 					this.initEditors()
 					this.curVoteItem = JSON.parse(JSON.stringify(item))
@@ -592,18 +725,18 @@
 					this.$refs.voteForm.validateField('description')
 				})
 			},
-			
+
 			/* 根据班级ID集合换取班级名称 */
-			getClassNameByIds(ids){
-				return new Promise((r,j) => {
+			getClassNameByIds(ids) {
+				return new Promise((r, j) => {
 					this.$api.learnActivity.getClassNameByIds({
-						classes:ids,
-						school:this.$store.state.userInfo.schoolCode
+						classes: ids,
+						school: this.$store.state.userInfo.schoolCode
 					}).then(res => {
-						if(!res.error){
+						if (!res.error) {
 							r(res.classInfos)
 						}
-					}).catch(e =>{
+					}).catch(e => {
 						j(e)
 					})
 				})
@@ -620,16 +753,17 @@
 				// 	})
 				// }
 				console.log(classId);
-				return this.classNameArr.find(i => i.id === classId) ? this.classNameArr.find(i => i.id === classId).name : this.$t('vote.form.noMatchDataTip')
+				return this.classNameArr.find(i => i.id === classId) ? this.classNameArr.find(i => i.id === classId).name :
+					this.$t('vote.form.noMatchDataTip')
 			},
-			
+
 			/* 查找学校检验组信息 */
-			findResearchList(){
+			findResearchList() {
 				this.$api.schoolUser.getResearchGroup({
-					code:this.$store.state.userInfo.schoolCode,
-					scope:'school'
+					code: this.$store.state.userInfo.schoolCode,
+					scope: 'school'
 				}).then(res => {
-					this.groupList = res.stuList
+					this.groupList = res.tchLists
 				})
 			},
 		},
@@ -639,10 +773,10 @@
 			descriptionEditor.config.onchange = (html) => {
 				this.voteForm.description = html
 			}
-			this.$editorTools.initSimpleEditor(descriptionEditor,this)
+			this.$editorTools.initSimpleEditor(descriptionEditor, this)
 			descriptionEditor.create()
 			this.descriptionEditor = descriptionEditor
-			
+
 
 			if (this.editItem && this.editItem.name) {
 				console.log(this.editItem)
@@ -655,69 +789,19 @@
 
 		},
 		computed: {
+			isAreaVote() {
+				return this.$route.name === 'manageAreaVote'
+			},
 			getDisableDays() {
 				return this.voteForm.startTime
 			},
 			getCurCode() {
-				return this.$route.name === 'personalVote' ? this.$store.state.userInfo.TEAMModelId : this.$store.state.userInfo.schoolCode
+				return this.$route.name === 'personalVote' ? this.$store.state.userInfo.TEAMModelId : this.$store.state
+					.userInfo.schoolCode
 			},
 			getCurScope() {
 				return this.$route.name === 'personalVote' ? 'private' : 'school'
 			},
-			//级联选择年级班级
-			csOptions() {
-			    let data = []
-			    //填充行政班数据
-			    if (this.evaluationInfo.period.id && this.schoolBase.period.length && this.schoolClasses.length) {
-			        let curPd = this.schoolBase.period.find((item) => {
-			            return item.id == this.evaluationInfo.period.id
-			        })
-			        data = [
-			            {
-			                id: 'class',
-			                name: '行政班',
-			                children: []
-			            },
-			            {
-			                id: 'stulist',
-			                name: '教学班',
-			                disabled: true,
-			                children: []
-			            }
-			        ]
-			        if (curPd) {
-			            //计算学级逻辑
-			            let date = new Date()
-			            let curYear = date.getFullYear()
-			            let month = date.getMonth() + 1
-			            let start = curPd.semesters.find(item => {
-			                return item.start == 1
-			            })
-			            // 根据入学月份确定当前年级和学级的关系
-			            if (start && month < start.month) {
-			                curYear--
-			            }
-			            curPd.grades.forEach((item, index) => {
-			                let dataItem = {
-			                    id: index,  //年级使用index
-			                    name: `${item}(${curYear - index}级)`,
-			                    year: curYear - index,
-			                    children: []
-			                }
-			                let child = this.schoolClasses.filter(classItem => {
-			                    return (classItem.year == curYear - index) && classItem.periodId == this.evaluationInfo.period.id
-			                })
-			                dataItem.children = child
-			                data[0].children.push(dataItem)
-			            })
-			        }
-			        // 填充教学班数据
-			        data[1].children.push(...this.stuList)
-			        console.log('data数据', data)
-			    }
-			    return data
-			}
-
 		},
 		watch: {
 			editItem: {

+ 1 - 0
TEAMModelOS/ClientApp/src/components/vote/BaseVotePie.vue

@@ -141,6 +141,7 @@
 				deep: true,
 				handler(val) {
 					if (val.length) {
+						console.log(val);
 						this.noChooseNum = val.filter(item => item.option === null).length
 						this.chooseNum = val.length - this.noChooseNum
 						this.drawLine(val)

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

@@ -119,7 +119,7 @@
         padding: 5px 0px;
         &.active{
             font-weight: bold;
-            color: var(--primary-text-color);
+            color: var(--tabs-text-color);
             border-bottom: 2px var(--tabs-bottom-color) solid;
         }
     }

+ 1 - 1
TEAMModelOS/ClientApp/src/css/custom-animate.less

@@ -55,6 +55,6 @@
     width: 100%;
 }
 .line-bottom-active {
-    color: var(--primary-text-color) !important;
+    color: var(--tabs-text-color) !important;
     font-weight: bold;
 }

+ 123 - 0
TEAMModelOS/ClientApp/src/css/light-iview-form.less

@@ -0,0 +1,123 @@
+.light-iview-select{
+    .ivu-select-selection{
+        background-color: var(--input-bg-color);
+        border: none;
+        color: var(--primary-text-color);
+    }
+
+    .ivu-select-visible .ivu-select-selection,
+    .ivu-form-item-error .ivu-select-visible .ivu-select-selection{
+        border: none;
+        box-shadow: none;
+    }
+
+}
+
+.light-iview-input{
+    .ivu-input{
+        background-color: var(--input-bg-color);
+        border: none;
+        color: var(--primary-text-color);
+    }
+
+    .ivu-input:focus,
+    .ivu-form-item-error .ivu-input:focus{
+        border: none;
+        box-shadow: none;
+    }
+}
+
+.light-iview-input-number{
+    .ivu-input-number{
+        background: var(--input-bg-color);
+        border: none;
+    }
+    .ivu-input-number-input{
+        background: var(--input-bg-color);
+    }
+    .ivu-input-number:hover{
+        border: none;
+    }
+    .ivu-input-number-focused{
+        box-shadow: none;
+    }
+}
+
+.light-el-input{
+    .el-input__inner,
+    .el-cascader__search-input{
+        background-color: var(--input-bg-color);
+        border: none;
+    }
+
+    .el-tag.el-tag--info{
+        color: var(--primary-text-color);
+    }
+
+    .el-cascader__tags .el-tag{
+        background-color: #e4e4e4;
+    }
+}
+
+.light-iview-form {
+    .ivu-form .ivu-form-item-label {
+        color: var(--second-text-color);
+    }
+
+    .ivu-input {
+        background: var(--input-bg-color);
+        color: var(--primary-text-color);
+        border: none;
+
+        &:hover{
+            border: none;
+        }
+    }
+
+    .ivu-input[disabled], fieldset[disabled] .ivu-input{
+        color: var(--primary-text-color);
+    }
+
+    .ivu-input-number-focused{
+        box-shadow: none;
+    }
+
+    .ivu-input-number, .ivu-input-number-small input {
+        font-size: 16px;
+        background: var(--input-bg-color);
+        color: var(--primary-text-color);
+        border: none;
+    }
+
+    .ivu-input-number, .ivu-input-number-default input {
+        background: var(--input-bg-color);
+        color: var(--primary-text-color);
+        border: none;
+    }
+
+    .ivu-input:focus,
+    .ivu-form-item-error .ivu-input:focus{
+        border: none;
+        box-shadow: none;
+    }
+
+    .ivu-select-selection {
+        background: var(--input-bg-color);
+        color: var(--primary-text-color);
+        border: none;
+    }
+
+    .ivu-select-disabled .ivu-select-selection{
+        color: var(--primary-text-color);
+    }
+
+    .ivu-select-visible .ivu-select-selection,
+    .ivu-form-item-error .ivu-select-visible .ivu-select-selection{
+        border: none;
+        box-shadow: none;
+    }
+    
+    .ivu-radio-inner:after{
+        background: #1CC0F3;
+    }
+}

+ 5 - 2
TEAMModelOS/ClientApp/src/css/site.css

@@ -303,14 +303,17 @@ audio::-internal-media-controls-overflow-button {
 
 .component-title {
 	font-size: 16px;
-	font-weight: 300;
-	color: #fff;
+	font-weight: 500;
+	color: var(--primary-text-color);
 	margin: 30px 0 0 55px;
 	display: block;
+	border-left: 5px solid var(--tabs-bottom-color);
+	padding-left: 10px;
 }
 
 .common-toolTip .ivu-tooltip-inner{
 	width: 200px;
+	word-break: break-word;
 }
 
 .common-toolTip .ivu-icon{

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

@@ -112,6 +112,9 @@ export default {
     createTips1:'Note: You (have joined a school) can select students from your school to join the course, or allow students to join the course by entering the course invitation code, scanning the course QR code, or using the invitation link.',
     createTips2:'Note: You (not yet a member of a school) can allow students to join the course by entering the course invitation code, scanning the course QR code, or using the invitation link.',
     renameListTitle:'Edit List Name',
+    selectListTips:'請選擇名單',
+    alreadyExist:'已在課程名單',
+    listAPIErr:'名單列表獲取失敗',
     //ManageClass.vue
     classLabel:'Class:',
     stuCount:'Student Number: ',

+ 8 - 8
TEAMModelOS/ClientApp/src/locale/lang/en-US/global.js

@@ -13,35 +13,35 @@ export default {
     testType: [
         {
             label: "Single Answer",
-            value: "single Answer"
+            value: "single"
         },
         {
             label: "Multiple Answers",
-            value: "multiple Answers"
+            value: "multiple"
         },
         {
             label: "True-false",
-            value: "True-false"
+            value: "judge"
         },
         {
             label: "Cloze",
-            value: "Cloze"
+            value: "complete"
         },
         {
             label: "Short answer",
-            value: "Short answer"
+            value: "subjective"
         },
         {
             label: "Question Set",
-            value: "Question Set"
+            value: "compose"
         },
         {
             label: "Correcting",
-            value: "correcting"
+            value: "correct"
         },
         {
             label: "Matching",
-            value: "Matching"
+            value: "connector"
         },
     ],
 }

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

@@ -1,8 +1,9 @@
 export default{
     error500:'Server error!',
     error401:'Login status has expired! Please log in again!',
+	error400:'API ERROR',
     error404:'API address not accessed!',
-	error:'API error!',
+	error:'Network Error! please try again later!',
 	loading:'Loading...',
 	error403:'Authorization expired or authorization abnormal, please try again later!'
 }

+ 19 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/jyzx.js

@@ -180,4 +180,23 @@ export default{
         message2: "存在未作答的题目!",
         message3: "已作答的问卷无法修改!",
     },
+    homePage: {
+        totalTime: '总学时',
+        online: "线上研修",
+        offline: "线下研修",
+        application: "应用考核",
+        classRecord: "课堂实录",
+        studyPoint: "已学能力点",
+        okPoint: "检测合格能力点",
+        achievements: "成果提交",
+        area: "区级研修",
+        areaQue: "区级问卷",
+        areaVote: "区级投票",
+        school: "校本研修",
+        schoolQue: "校本问卷",
+        schoolVote: "校本投票",
+        time: "学时",
+        remarks1: "总学时:线上研修 + 校本研修 + 应用考核 + 课堂实录",
+        remarks2: "注:各指标达到要求后,多余学时不再计入总学时",
+    }
 }

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

@@ -82,5 +82,6 @@ export default {
     stuCli:'For Student',
     beian1:'',
     beian2:'',
-    copyright:'2021 HABOOK Group TEAM Model'
+    copyright:'2021 HABOOK Group TEAM Model',
+    loginErr:'登錄信息異常,請重新登錄'
 }

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

@@ -29,7 +29,7 @@ export default {
     notifyDetail:'公告详情',
     delNotifyTitle:'删除公告',
     delNotifyContent:'是否确认删除',
-    ok:'是',
+    yes:'是',
     no:'否',
     delOk:'删除成功',
     delErr:'删除失败'

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

@@ -126,6 +126,7 @@ export default {
   setGrade: "Set classroom's grade",
   setHiteachCode: 'HiTeach Serial Number',
   addClassroom: 'Add Classroom',
+  editClassroom: 'Edit Classroom',
   schoolPlan: 'School floor plan and classroom location settings',
   uploadPlan: 'Upload Floor Plan',
   hiteachList: 'HiTeach Serial Number List',

+ 2 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/system.js

@@ -4,6 +4,8 @@ export default {
     loading:'Loading',
     authErr:'Insufficient authorization!',
     development:'Features are under development, stay tuned!',
+	goHome:'Return To Home Page',
+	changePlat:'Switching Platform',
     menu:{
         school:'School',
         private:'Personal',

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

@@ -61,7 +61,7 @@ export default {
   startDown: 'Start Downloading',
   videoTips:'Friendly reminder: Only MP4 format is supported for online video playing! ',
   spaceTips: 'School Available Space = Total School Space - Space Allocated To Teachers',
-  common:'通用',
+  common:'通用(未關聯學段資源)',
   renameTitle:'重命名',
   fileName:'文件名:'
   

+ 26 - 2
TEAMModelOS/ClientApp/src/locale/lang/en-US/teachermgmt.js

@@ -9,10 +9,12 @@ export default {
     table:{
         text1: 'Basic',
         text2: 'Advance',
+        text3: '系統管理員',
         th1: 'ID',
         th2: 'Name',
         th3: 'Title',
-        th4: 'Authorization Status'
+        th4: 'Authorization Status',
+        th5: '教研组',
     },
     authSet:{
         title:'Authorization Settings',
@@ -140,6 +142,7 @@ export default {
             text3: 'Successfully Imported Account:',
             text4: 'Repeated Account:',
             text5: 'Failed Import Account:',
+            text6: 'ID格式錯誤',
             unit: '',
             error1: 'Found repeated accounts',
             error2: 'Duplicate invitations or account not found'
@@ -153,5 +156,26 @@ export default {
     },
     saveWarning:'Reminder',
     warningCnt:'The the current space data is not yet saved. If you leave, the modified data will not be retained!',
-    leaveText:'Exit'
+    leaveText:'Exit',
+    transferTitle:'轉讓管理員',
+    transferTo:'轉讓給:',
+    transferTips1:'請選擇需要將管理員身份轉讓給哪位老師? ',
+    transferTips2:'不能將管理員身份轉讓給自己',
+    trOk:'轉讓成功',
+    trErr:'轉讓失敗',
+    trOkContent:'您的管理員身份將在退出登錄後失效',
+    peopleNum:'人數:',
+    peopleUnit:'人',
+    addMember:'添加成員',
+    noTeacher:'暫無老師',
+    rmvTch:'移除教師',
+    rmvTchContent:'是否確認移除',
+    yes:'是',
+    no:'否',
+    addOk:'添加成功',
+    addErr:'添加失敗',
+    rmvOk:'移除成功',
+    rmvErr:'移除失敗',
+    groupInfoErr:'教研組查詢失敗',
+    delGroup:'刪除教研組',
 }

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

@@ -90,7 +90,7 @@ export default {
     module3: 'Question Analysis',
     module4: 'Key Concept Mastery',
     module5: 'Cognitive Level Mastery',
-    exportTable: 'Export Table',
+    exportTable: 'Export',
     currentSubject: 'Current Subject',
     goExamList: 'View More Assessments',
 

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

@@ -4,7 +4,7 @@ export default{
     noSet:'Not set',
     edit:'Edit',
     setting:'Set',
-    psw:'Password',
+    psw:'Password',
     mobile:'Phone',
     email:'Email',
     pswErr1:'The passwords you entered do not match',
@@ -36,6 +36,7 @@ export default{
     cancel:'Cancel',
     toStudent:'Switching to Student',
     toArea:'Go To District Platform',
+	toSchool:'Go To School Platform',
     schoolMgt:'School Management',
     systemSet:'System Settings',
 }

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

@@ -5,7 +5,12 @@ export default {
 	fileReadFail:'There is test data reading failure!',
 	uploadLoading:'Uploading...',
 	choose:"Select",
-	draw:'Mark',
+	draw:'Draw',
+	arrow:'Arrow',
+	circle:'Circle',
+	rect:'Rect',
+	star:'Star',
+	upload:'Choose Image',
 	text:'Text input',
 	clear:'Clear',
 	undo:'Undo',

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

@@ -49,7 +49,7 @@ export default {
 		editSuc:'Edit successfully',
 		addSuc:'Add successfully',
 		noCompleteTip:'Please fill in the information completely',
-		noOptionTip:'The number of voting options cannot be zero!',
+		noOptionTip:'Voting options cannot be empty!',
 		attachmentMaxTip:'Maximum of 5 attachments can be uploaded',
 		optionNumsTip:'Maximum of 10 options only',
 		noMatchDataTip:'No matching data',

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

@@ -112,6 +112,9 @@ export default {
     createTips1:'温馨提示:您(已加入学校)可以挑选学校学生加入课程或让学生通过输入课程邀请码、扫描课程二维码、课程链接方式主动加入课程。',
     createTips2:'温馨提示:您(暂未加入学校)可让学生通过输入课程邀请码、扫描课程二维码、课程链接方式主动加入课程。',
     renameListTitle:'修改名称',
+    selectListTips:'请选择名单',
+    alreadyExist:'已在课程名单',
+    listAPIErr:'名单列表获取失败',
     //ManageClass.vue
     classLabel:'班级:',
     stuCount:'学生人数:',

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

@@ -2,7 +2,8 @@ export default{
     error500:'服务器错误!',
     error401:'登录状态已过期!请重新登录!',
     error404:'未访问到API地址!',
-	error:'API异常!',
+	error400:'请求异常,请稍后重试!',
+	error:'网络异常,请稍后重试!',
 	loading:'加载中',
 	error403:'授权过期或授权异常,请稍后重试!'
 }

+ 19 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/jyzx.js

@@ -180,4 +180,23 @@ export default{
         message2: "存在未作答的题目!",
         message3: "已作答的问卷无法修改!",
     },
+    homePage: {
+        totalTime: '总学时',
+        online: "线上研修",
+        offline: "线下研修",
+        application: "应用考核",
+        classRecord: "课堂实录",
+        studyPoint: "已学能力点",
+        okPoint: "检测合格能力点",
+        achievements: "成果提交",
+        area: "区级研修",
+        areaQue: "区级问卷",
+        areaVote: "区级投票",
+        school: "校本研修",
+        schoolQue: "校本问卷",
+        schoolVote: "校本投票",
+        time: "学时",
+        remarks1: "总学时:线上研修 + 校本研修 + 应用考核 + 课堂实录",
+        remarks2: "注:各指标达到要求后,多余学时不再计入总学时",
+    }
 }

+ 3 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/login.js

@@ -7,7 +7,7 @@ export default {
         ies5: '醍摩豆云平台'
     },
     subTitle: {
-        IDLogin: '系统管理者、教师、学生与家长登入口',
+        IDLogin: '系统管理者或教师登入口',
         QRLogin: '使用HiTA或AClassONE扫描进行登入',
         schoolLogin: '由学校统一分配给学生使用的帐号登入口',
         selectType: '请选择您的身份进行登入',
@@ -82,5 +82,6 @@ export default {
     stuCli:'学生端',
     beian1:'蜀ICP备18027363号-1',
     beian2:'川公网安备 51010402000615',
-    copyright:'2021 HABOOK Group 醍摩豆'
+    copyright:'2021 HABOOK Group 醍摩豆',
+    loginErr:'登录信息异常,请重新登录'
 }

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

@@ -29,7 +29,7 @@ export default {
     notifyDetail:'公告详情',
     delNotifyTitle:'删除公告',
     delNotifyContent:'是否确认删除',
-    ok:'是',
+    yes:'是',
     no:'否',
     delOk:'删除成功',
     delErr:'删除失败'

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

@@ -126,6 +126,7 @@ export default {
   setGrade: '设置教室年级',
   setHiteachCode: 'HiTeach软件序号',
   addClassroom: '新增教室',
+  editClassroom: '修改教室',
   schoolPlan: '学校平面图与教室位置设置',
   uploadPlan: '上传平面图',
   hiteachList: 'HiTeach序号列表',

+ 2 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/stuAccount.js

@@ -102,6 +102,8 @@ export default {
   idRepErr: '账号已存在,将覆盖原有账号',
   stuYearErr: '学生学级数据错误',
   classYearErr: '班级年级错误',
+  noFormatErr: '座号格式错误',
+  classFormatErr: '班级格式错误',
   importOk: '导入成功',
   
   // Authorization.vue

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

@@ -5,7 +5,7 @@ export default {
         setting: '个人设定',
         logout: '登出',
         joinClass: '加入课程',
-        classPla: "请输入课程代码",
+        classPla: "请输入邀请码",
         exam: '评量',
         vote: '投票',
         survey: '问卷'
@@ -93,11 +93,11 @@ export default {
     todaydeadlineList: '今日截止活动提醒 ',
     endsToday: "今日",
     endsTodayTime: '截止',
-    addCourse: "输入课程代码,加入课程",
+    addCourse: "输入邀请码,加入课程",
     courseType: {
         success: "课程加入成功",
         warning: "重复加入课程!",
-        error: "课程代码不存在,请重新输入",
+        error: "邀请码不存在,请重新输入",
         api: "API错误",
     },
     coursesCardTitle: '我的课程清单',

+ 2 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/system.js

@@ -4,6 +4,8 @@ export default {
     loading:'加载中',
     authErr:'权限不足!',
     development:'功能正在开发中',
+	goHome:'返回主页',
+	changePlat:'切换平台',
     menu:{
         school:'学校',
         private:'个人',

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

@@ -61,7 +61,7 @@ export default {
   startDown: '开始下载',
   videoTips: '温馨提示:视频只支持MP4格式在线播放!',
   spaceTips: '学校可用空间 = 学校总空间 - 分配给教师的空间',
-  common:'通用',
+  common:'通用(未关联学段资源)',
   renameTitle:'重命名',
   fileName:'文件名:'
 

+ 27 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachermgmt.js

@@ -9,10 +9,12 @@ export default {
     table: {
         text1: '基本',
         text2: '进阶',
+        text3: '系统管理员',
         th1: '醍摩豆ID',
         th2: '姓名',
         th3: '职称',
-        th4: '权限状态'
+        th4: '权限状态',
+        th5: '教研组',
     },
     authSet:{
         title:'权限设定',
@@ -140,6 +142,7 @@ export default {
             text3: '成功导入账号数',
             text4: '重复账号资料数',
             text5: '导入失败账号数',
+            text6: 'ID格式错误',
             unit: '笔',
             error1: '检索到相同账号',
             error2: '重复邀请或找不到账号'
@@ -153,5 +156,27 @@ export default {
     },
     saveWarning:'保存提醒',
     warningCnt:'当前空間数据尚未保存。如果离开,修改的数据将不会保存!',
-    leaveText:'离开'
+    leaveText:'离开',
+    transferTitle:'转让管理员',
+    transferTo:'转让给:',
+    transferTips1:'请选择需要将管理员身份转让给哪位老师?',
+    transferTips2:'不能将管理员身份转让给自己',
+    trOk:'转让成功',
+    trErr:'转让失败',
+    trOkContent:'您的管理员身份将在退出登录后失效',
+    peopleNum:'人数:',
+    peopleUnit:'人',
+    addMember:'添加成员',
+    noTeacher:'暂无老师',
+    rmvTch:'移除教师',
+    rmvTchContent:'是否确认移除',
+    yes:'是',
+    no:'否',
+    addOk:'添加成功',
+    addErr:'添加失败',
+    rmvOk:'移除成功',
+    rmvErr:'移除失败',
+    groupInfoErr:'教研组查询失败',
+    delGroup:'删除教研组',
+
 }

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

@@ -36,6 +36,7 @@ export default{
     cancel:'取消',
     toStudent:'切换为学生',
     toArea:'前往区级平台',
+	toSchool:'前往校级平台',
     schoolMgt:'学校管理',
     systemSet:'系统设置'
 }

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


Неке датотеке нису приказане због велике количине промена