Browse Source

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

Li 3 years ago
parent
commit
f4ff084647
53 changed files with 920 additions and 458 deletions
  1. 73 32
      TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs
  2. 31 1
      TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs
  3. 3 3
      TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj
  4. 2 0
      TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs
  5. 1 0
      TEAMModelOS.SDK/Models/Cosmos/Teacher/Teacher.cs
  6. 1 1
      TEAMModelOS.SDK/TEAMModelOS.SDK.csproj
  7. 1 0
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/CourseListView.vue
  8. 2 2
      TEAMModelOS/ClientApp/src/locale/lang/en-US/auth.js
  9. 8 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js
  10. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/home.js
  11. 4 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/learnActivity.js
  12. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/lessonRecord.js
  13. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolBaseInfo.js
  14. 2 2
      TEAMModelOS/ClientApp/src/locale/lang/en-US/studentWeb.js
  15. 2 3
      TEAMModelOS/ClientApp/src/locale/lang/en-US/teachContent.js
  16. 7 2
      TEAMModelOS/ClientApp/src/locale/lang/en-US/teachermgmt.js
  17. 8 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/cusMgt.js
  18. 4 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/learnActivity.js
  19. 7 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachermgmt.js
  20. 2 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/auth.js
  21. 8 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/cusMgt.js
  22. 4 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/learnActivity.js
  23. 9 9
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/lessonRecord.js
  24. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/settings.js
  25. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/studentWeb.js
  26. 7 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/teachermgmt.js
  27. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/tip.js
  28. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/train.js
  29. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/unit.js
  30. 21 0
      TEAMModelOS/ClientApp/src/store/module/user.js
  31. 1 1
      TEAMModelOS/ClientApp/src/utils/excel.js
  32. 17 22
      TEAMModelOS/ClientApp/src/utils/js-fn.js
  33. 1 1
      TEAMModelOS/ClientApp/src/view/ability/Review.vue
  34. 41 6
      TEAMModelOS/ClientApp/src/view/assessment/Assessment.vue
  35. 5 1
      TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.less
  36. 161 138
      TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.vue
  37. 1 1
      TEAMModelOS/ClientApp/src/view/learnactivity/Scoring.vue
  38. 11 5
      TEAMModelOS/ClientApp/src/view/learnactivity/echarts/KngPoint.vue
  39. 18 13
      TEAMModelOS/ClientApp/src/view/learnactivity/tabs/AnswerTable.vue
  40. 10 5
      TEAMModelOS/ClientApp/src/view/learnactivity/tabs/DataView.vue
  41. 25 2
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.less
  42. 138 36
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue
  43. 1 1
      TEAMModelOS/ClientApp/src/view/student-account/stuMgt/AddStudent.vue
  44. 0 1
      TEAMModelOS/ClientApp/src/view/teachermgmt/Index.less
  45. 29 11
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/import/Import.vue
  46. 8 8
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/mgt/TeacherMgt.vue
  47. 69 8
      TEAMModelOS/Controllers/Common/ExamController.cs
  48. 72 110
      TEAMModelOS/Controllers/School/SchoolController.cs
  49. 2 2
      TEAMModelOS/Controllers/System/BlobController.cs
  50. 62 10
      TEAMModelOS/Controllers/Teacher/InitController.cs
  51. 1 1
      TEAMModelOS/Controllers/XTest/FixDataController.cs
  52. 29 0
      TEAMModelOS/Controllers/XTest/TestController.cs
  53. 3 3
      TEAMModelOS/TEAMModelOS.csproj

+ 73 - 32
TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs

@@ -304,7 +304,7 @@ namespace TEAMModelOS.FunctionV4
                                                 result.studentScores.Add(ansPoint);
                                                 result.ans.Add(anses);
                                                 result.sum.Add(0);
-                                                result.status.Add(0);
+                                                result.status.Add(1);
                                             }
 
                                             //result.progress = info.progress;
@@ -417,26 +417,15 @@ namespace TEAMModelOS.FunctionV4
                                     await createClassResultAsync(info, examClassResults, subject, fno, _azureCosmos, _dingDing, _azureStorage);
                                     fno++;
                                 }
-
-                                //info.lostStu = losStu;
-                                /*//补充历史数据的容器名称
-                                if (string.IsNullOrEmpty(info.cn)) {
-                                    if (info.scope.Equals("school"))
-                                    {
-                                        info.cn = info.school;
-                                    }
-                                    else {
-                                        info.cn = info.creatorId;
-                                    }
-                                }*/
                                 //判断均分是否发生变化,便于实时的更新评测基本信息
-                                if (info.sRate != settlement.rate || info.average != settlement.score || info.sStatus != newStatus)
+                                if (info.sRate != settlement.rate || info.average != settlement.score || info.sStatus != newStatus || info.qRate != settlement.qrate)
                                 {
                                     info.sRate = settlement.rate;
                                     info.average = settlement.score;
                                     info.sStatus = newStatus;
                                     info.lostStu = settlement.stus;
                                     info.stuCount = settlement.total;
+                                    info.qRate = settlement.qrate;
                                     await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync<ExamInfo>(info, info.id, new Azure.Cosmos.PartitionKey(info.code));
                                 }
                             }
@@ -483,28 +472,63 @@ namespace TEAMModelOS.FunctionV4
                     List<double> newSumScore = new List<double>();
                     var scount = classResult.studentIds.Count;
                     int index = 0;
-                    foreach (var ans in classResult.studentAnswers) {
-                        //该学生缺考
-                        if (ans.Count == 0)
+                    if (classResult.status.Count > 0)
+                    {
+                        foreach (var sta in classResult.status)
                         {
-                            for (int i = 0; i < classResult.studentScores[index].Count; i++)
+                            if (sta == 1)
+                            {
+                                for (int i = 0; i < classResult.studentScores[index].Count; i++)
+                                {
+                                    if (classResult.studentScores[index][i] == -1)
+                                    {
+                                        classResult.studentScores[index][i] = 0;
+                                    }
+                                }
+                            }
+                            else if (sta == 0)
                             {
-                                if (classResult.studentScores[index][i] == -1) {
-                                    classResult.studentScores[index][i] = 0;
-                                }                               
+                                var ans = classResult.studentScores[index];
+                                //该学生缺考,历史数据的判定
+                                if (ans.Count == 0)
+                                {
+                                    for (int i = 0; i < classResult.studentScores[index].Count; i++)
+                                    {
+                                        if (classResult.studentScores[index][i] == -1)
+                                        {
+                                            classResult.studentScores[index][i] = 0;
+                                        }
+                                    }
+                                    classResult.status[index] = 1;
+                                }
+
                             }
-                            classResult.status[index] = 1;
+                            index++;
                         }
-                       /* else {
-                            for (int i = 0; i < classResult.studentScores[index].Count; i++)
+                    }
+                    else
+                    {
+                        List<int> sta = new();
+                        foreach (var id in classResult.studentIds) {
+                            sta.Add(0);
+                        }
+                        classResult.status = sta;
+                        foreach (var ans in classResult.studentAnswers)
+                        {
+                            //该学生缺考,历史数据的判定
+                            if (ans.Count == 0)
                             {
-                                if (classResult.studentScores[index][i] == -1)
+                                for (int i = 0; i < classResult.studentScores[index].Count; i++)
                                 {
-                                    classResult.studentScores[index][i] = 0;
+                                    if (classResult.studentScores[index][i] == -1)
+                                    {
+                                        classResult.studentScores[index][i] = 0;
+                                    }
                                 }
+                                classResult.status[index] = 1;
                             }
-                        } */                       
-                        index++;
+                            index++;
+                        }
                     }
                     foreach (List<double> sc in classResult.studentScores)
                     {
@@ -568,8 +592,22 @@ namespace TEAMModelOS.FunctionV4
                     allScore += simple.point.Sum();
                 }
                 //计算全科标准差
+                double qk = 0;
                 foreach (string id in examResults[0].studentIds)
                 {
+                    //计算整体缺考人数
+                    foreach (var ec in examClassResults)
+                    {
+                        int index = ec.studentIds.IndexOf(id);
+                        if (index > -1)
+                        {
+                            if (ec.status[index] == 1)
+                            {
+                                qk++;
+                                break;
+                            }
+                        }
+                    }
                     double sc = 0;
                     foreach (ExamResult result in examResults)
                     {
@@ -579,10 +617,12 @@ namespace TEAMModelOS.FunctionV4
                 }
                 info.standard = Math.Round(total > 0 ? Math.Pow(powSum / total, 0.5) : 0, 2);
                 double NewsRate = allScore > 0 ? Math.Round(NewsRateScore / allScore * 100, 2) : 0;
+                double qrate = Math.Round(qk / total * 100, 2);
                 settlement.rate = NewsRate;
                 settlement.score = NewsRateScore;
                 settlement.stus = losStu;
                 settlement.total = total;
+                settlement.qrate = qrate;
             }
             return settlement;
         }
@@ -610,8 +650,8 @@ namespace TEAMModelOS.FunctionV4
                 List<string> plId = new List<string>();
                 List<List<List<string>>> opth = new List<List<List<string>>>();
                 List<List<List<string>>> optl = new List<List<List<string>>>();
-                List<double> akp  =  await knowledgeCount(info, subject, _dingDing, no, classResults, rhwCount, rhw, rhlCount, rhl, _azureCosmos);
-                List<double> afp  = await fieldCount(info, subject, _dingDing, no, classResults, rhwCount, rhw, rhlCount, rhl, _azureCosmos);
+                List<double> akp = await knowledgeCount(info, subject, _dingDing, no, classResults, rhwCount, rhw, rhlCount, rhl, _azureCosmos);
+                List<double> afp = await fieldCount(info, subject, _dingDing, no, classResults, rhwCount, rhw, rhlCount, rhl, _azureCosmos);
                 int PHCount = 0;
                 int PLCount = 0;
                 foreach (ExamClassResult classResult in classResults)
@@ -900,7 +940,7 @@ namespace TEAMModelOS.FunctionV4
                                             {
                                                 if (classResult.studentScores[index].Count > 0)
                                                 {
-                                                    score += classResult.studentScores[index][n] == -1 ? 0 : classResult.studentScores[index][n]* itemPersent;
+                                                    score += classResult.studentScores[index][n] == -1 ? 0 : classResult.studentScores[index][n] * itemPersent;
                                                     if (classResult.studentScores[index].Sum() >= rhw && phcount < rhwCount)
                                                     {
                                                         if (classResult.studentScores[index][n] <= 0)
@@ -1084,7 +1124,7 @@ namespace TEAMModelOS.FunctionV4
                 {
                     double score = 0;
                     double allScore = 0;
-                    
+
                     int count = 0;
                     foreach (ExamClassResult result in classResults)
                     {
@@ -1333,6 +1373,7 @@ namespace TEAMModelOS.FunctionV4
             public double score { get; set; }
             public List<string> stus { get; set; } = new List<string>();
             public int total { get; set; }
+            public double qrate { get; set; }
         }
     }
 }

+ 31 - 1
TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs

@@ -1070,6 +1070,34 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                             }
                                         }
                                     }
+                                    #region
+                                    //start处理历史数据
+                                    var blobclient = _azureStorage.GetBlobContainerClient(blobname);
+                                    List<BlobItem> blobItems = new List<BlobItem>();
+                                    HashSet<string> ids = new HashSet<string>();
+                                    string path = $"records";
+                                    await foreach (BlobItem item in blobclient.GetBlobsAsync(BlobTraits.None, BlobStates.None, path))
+                                    {
+                                        var p = item.Name.Split("/");
+                                        if (p.Length > 2)
+                                        {
+                                            ids.Add(p[1]);
+                                        }
+                                    }
+                                    List<string> lessonIds = new List<string>();
+                                    string sql = "select value(c.id) from c ";
+                                    await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname)
+                                        .GetItemQueryIterator<string>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey(code) }))
+                                    {
+                                        lessonIds.Add(item);
+                                    }
+                                    var notdata = ids.Except(lessonIds);
+                                    var notblob = lessonIds.Except(ids).ToList();
+                                    List<string> paths = notdata.Select(x => $"records/{x}").ToList();
+                                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname).DeleteItemsStreamAsync(notblob, code);
+                                    await _azureStorage.GetBlobServiceClient().DeleteBlobs(_dingDing, blobname, paths);
+                                    //end 处理历史数据
+                                    #endregion
                                     await client.GetContainer(Constant.TEAMModelOS, tbname).DeleteItemAsync<LessonRecord>(lessonId, new PartitionKey(code));
                                     await _azureStorage.GetBlobServiceClient().DeleteBlobs(_dingDing, blobname, new List<string> { $"records/{_lessonId}" });
                                     await client.GetContainer(Constant.TEAMModelOS, tbname).DeleteItemStreamAsync(lessonRecord.id,new PartitionKey ($"Bloblog-{blobname}"));
@@ -1089,6 +1117,8 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                             case "create":
                                 oldlessonRecord = null;
                                 //处理课堂选用的课程信息
+                                Teacher teacher = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>(tmdid, new PartitionKey("Base"));
+                                lessonRecord.show = teacher.lessonShow;
                                 if (!string.IsNullOrEmpty(lessonRecord.courseId))
                                 {
                                     Course course = null;
@@ -1195,7 +1225,7 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                 try {
                                     if (scope.Equals("private"))
                                     {
-                                        Teacher teacher = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>(tmdid, new PartitionKey("Base"));
+                                       
                                         if (teacher.lessonLimit != -1)
                                         {
 

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

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

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

@@ -107,6 +107,8 @@ namespace TEAMModelOS.SDK.Models
         public double average { get; set; } = -1;
         //得分率
         public double sRate { get; set; }
+        //缺考率
+        public double qRate { get; set; }
         //缺考人数
         public List<string> lostStu { get; set; } = new List<string>();
         public double standard { get; set; }

+ 1 - 0
TEAMModelOS.SDK/Models/Cosmos/Teacher/Teacher.cs

@@ -15,6 +15,7 @@ namespace TEAMModelOS.SDK.Models
         public List<TeacherArea> areas { get; set; } = new List<TeacherArea>();
         public List<ThirdBind> binds { get; set; } = new List<ThirdBind>();
         public int lessonLimit { get; set; } = 0;
+        public List<string> lessonShow { get; set; } = new List<string>();
         public class TeacherSchool
         {
             public string schoolId { get; set; }

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

@@ -27,7 +27,7 @@
     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.3" />
     <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
     <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="6.0.3" />
-    <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.3" />
+    <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.4" />
     <PackageReference Include="Microsoft.Identity.Client" Version="4.39.0" />
     <PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
     <PackageReference Include="NUnit" Version="3.13.2" />

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

@@ -1011,6 +1011,7 @@ export default {
         */
         clickCell(row, index, type) {
             this.name = "tab5"
+            this.continuationToken = null
             let nowClassInfor = undefined
             if(type) {
                 nowClassInfor = this._.cloneDeep(row)

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

@@ -15,10 +15,10 @@ export default {
     homework: 'Homework',
     train: 'Seminar',
     records:'課堂記錄',
-    over: '剩余空間',
+    over: 'Remaining',
     syllabus:'課綱',
     itemAndPaper:'試題試卷',
-    appData:'其他應用數據',
+    appData:'Application Data',
     content:'Content Module',
     used:'Used:',
     expired:'Service Due Date:',

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

@@ -160,6 +160,14 @@ export default {
     unfvtOk: 'Removed from collection',
     unfvtErr: 'Failed to remove',
     recordTips: 'Note: Only the last 30 records will be kept for personal courses. The earliest records will be deleted automatically if exceed 30.',
+    shareToStu:'發布給學生',
+    unShare:'取消發布',
+    shareOk:'發布成功',
+    shareErr:'發布失敗',
+    unShareOk:'已取消發布給學生',
+    unShareErr:'取消失敗',
+    autoShare:'自動發布:',
+    autoShareTips:'開啟後,上傳課堂課堂記錄的同時將發布給學生',
 
     //ManageClass.vue
     stuMgt: 'Student Management',

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

@@ -1,7 +1,7 @@
 export default{
     previewStudy:'Previews before class',
     classData:'Lesson Data',
-    recentRecord:'近期7日課堂記錄',
+    recentRecord:'Recent Lesson Record',
     acCount:'Activities Overview',
     goingList:'List Of Ongoing Activities',
     scNotice:'School Announcement',

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

@@ -81,7 +81,8 @@ export default {
         copyTitle: 'Copy Assessment',
         copyContent: 'Are you sure to copy the assessment?',
         copyContent1: 'Smarter Classroom Assessment cannot be copied.',
-        paperExam:'紙本測驗'
+        paperExam:'紙本測驗',
+        loadAll:'已加載所有數據'
     },
 
     //CreateEv
@@ -287,6 +288,8 @@ export default {
     simple: {
         totalPeople: 'Total No. of people',
         missExam: 'No. of absentee',
+        missExamRate: '缺考率',
+        ccRate:'及格率',
         classLabel: 'Class',
         sjLabel: 'Subject',
         avgScore: 'Average Score',

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

@@ -20,7 +20,7 @@ export default {
 		place2: 'Please enter teacher name...'
 	},
 	count1: 'Total Lesson',
-	count2: 'Participating Teachers',
+	count2: 'Teacher No.',
 	count3: 'Accumulated Task',
 	count4: 'Accumulated Work',
 	count5: 'Accumulated Test Question',

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

@@ -110,7 +110,7 @@ export default {
   profNameTips:'Please set the professional name',
   anaNameTips:'Please complete the learning status analysis setting',
   campNameTips:'Please enter the school district name',
-  subjectNameTips:'Please enter the subject name',
+  subjectNameTips:'Please enter the subject/professional subject name',
   delTimeTitle:'Delete Schedule',
   delTimeContent:'Are you sure you want to delete the current schedule?',
   setStartTitps:'Set as enrollment semester',

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

@@ -198,8 +198,8 @@ export default {
     newAddCourse: 'The latest addition',
     addTime: "Join time",
     missionListCardTitle: 'Activity Task List',
-    missionListCardTitle1: '評測工作任務',
-    missionListCardTitle2: '投票問卷活動',
+    missionListCardTitle1: 'Task List',
+    missionListCardTitle2: 'Activity List',
     choiceTime: "Filter Time",
     missionListCardPlace: "Default display activities within 30 days",
     missionListCardLoading: 'Loading',

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

@@ -34,10 +34,9 @@ export default {
   uploadText: 'Tap or drag to upload',
 
   resTips: 'HiTeach generates teaching materials that only support HTEX format previews',
-  space: '可用空間:',
   calcing: 'Calculating...',
   blobFull: '(Full)',
-  otherType: 'Other',
+  otherType: 'Other types',
   appData: 'Application Data',
   delBatch: 'Delete',
   viewport1: 'List Mode',
@@ -60,7 +59,7 @@ export default {
   public: 'Public Resources',
   startDown: 'Start Downloading',
   videoTips:'Friendly reminder: Only MP4 format is supported for online video playing! ',
-  spaceTips: '可用空間 = 學校總空間 - 分配給教師的空間 - 學校已使用空間',
+  spaceTips: 'School Available Space = Total School Space - Space Allocated To Teachers',
   common:'General',
   renameTitle:'Rename',
   fileName:'File Name:',

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

@@ -207,6 +207,9 @@ export default {
     setSubjTitle: 'Set Subject',
     sltSubjTips: 'Please select a subject',
     subjectFilter: 'Subject Filter',
+    statusFilter: '狀態篩選',
+    jobFilter: '職稱篩選',
+    authFilter: '權限篩選',
     search: 'Search',
     //老師帳號分配空間授權控件teachermgmt/index.vue 空間欄位部分
     allocationSpace: 'Allocate Teaching Space',
@@ -276,7 +279,8 @@ export default {
     importTips7: '5. note: 教師備註信息,選填;',
     importTips8: '溫馨提示:如果導入教師醍摩豆ID,或者導入的手機或郵箱已註冊醍摩豆ID,系統會自動邀請老師加入學校。',
     importTips9: '點擊或者拖拽文件導入',
-    impText1: '導入總人數:',
+    impText:'無效數據(沒有名字):',
+    impText1: '有效導入數據:',
     impText2: '僅導入姓名:',
     impText3: '系統將自動邀請:',
     impText4: '重新導入',
@@ -293,5 +297,6 @@ export default {
     joinTips2: '綁定學校尚未加入的老師:',
     hasLeader: '當前老師已經是組長了',
     export: '導出名單',
-    teacherList: '教師名單'
+    teacherList: '教師名單',
+    noIpmtData:'暫無可導入數據'
 }

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

@@ -160,6 +160,14 @@ export default {
     unfvtOk:'已取消收藏',
     unfvtErr:'取消失败',
     recordTips:'温馨提示:个人课程课堂记录只保留最近30条记录,超过30条会自动删除最早的记录。',
+    shareToStu:'发布给学生',
+    unShare:'取消发布',
+    shareOk:'发布成功',
+    shareErr:'发布失败',
+    unShareOk:'已取消发布给学生',
+    unShareErr:'取消失败',
+    autoShare:'自动发布:',
+    autoShareTips:'开启后,上传课堂课堂记录的同时将发布给学生',
 
     //ManageClass.vue
     stuMgt:'学生管理',

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

@@ -81,7 +81,8 @@ export default {
         copyTitle: '复制评测',
         copyContent: '确认复制当前评测吗?',
         copyContent1: '课中评测不能进行复制操作。',
-        paperExam:'纸本测验'
+        paperExam:'纸本测验',
+        loadAll:'已加载所有数据',
     },
 
     //CreateEv
@@ -287,6 +288,8 @@ export default {
     simple: {
         totalPeople: '总人数',
         missExam: '缺考数',
+        missExamRate: '缺考率',
+        ccRate:'及格率',
         classLabel: '班级',
         sjLabel: '学科',
         avgScore: '平均分',

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

@@ -206,6 +206,9 @@ export default {
     setSubjTitle: '设置学科',
     sltSubjTips: '请选择学科',
     subjectFilter: '学科筛选',
+    statusFilter: '状态筛选',
+    jobFilter: '职称筛选',
+    authFilter: '权限筛选',
     search: '搜索',
     //老師帳號分配空間授權控件teachermgmt/index.vue 空間欄位部分
     allocationSpace: '分配教学空间',
@@ -275,7 +278,8 @@ export default {
     importTips7:'5. note: 教师备注信息,选填;',
     importTips8:'温馨提示:如果导入教师醍摩豆ID,或者导入的手机或邮箱已注册醍摩豆ID,系统会自动邀请老师加入学校。',
     importTips9:'点击或者拖拽文件导入',
-    impText1:'导入总人数:',
+    impText:'无效数据(没有名字):',
+    impText1:'有效导入数据:',
     impText2:'仅导入姓名:',
     impText3:'系统将自动邀请:',
     impText4:'重新导入',
@@ -292,5 +296,6 @@ export default {
     joinTips2:'绑定学校尚未加入的老师:',
     hasLeader:'当前老师已经是组长了',
     export:'导出名单',
-    teacherList:'教师名单'
+    teacherList:'教师名单',
+    noIpmtData:'暂无可导入数据'
 }

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

@@ -15,10 +15,10 @@ export default {
     homework: '作業',
     train: '研修',
     records:'課堂記錄',
-    over: '剩余空間',
+    over: '剩',
     syllabus:'課綱',
     itemAndPaper:'試題試卷',
-    appData:'其他應用數據',
+    appData:'應用數據',
     content: '內容模塊',
     used: '已使用:',
     expired: '服務到期日:',

+ 8 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/cusMgt.js

@@ -160,6 +160,14 @@ export default {
     unfvtOk:'已取消收藏',
     unfvtErr:'取消失敗',
     recordTips:'溫馨提示:個人課程課堂記錄只保留最近30條記錄,超過30條會自動刪除最早的記錄。',
+    shareToStu:'發布給學生',
+    unShare:'取消發布',
+    shareOk:'發布成功',
+    shareErr:'發布失敗',
+    unShareOk:'已取消發布給學生',
+    unShareErr:'取消失敗',
+    autoShare:'自動發布:',
+    autoShareTips:'開啟後,上傳課堂課堂記錄的同時將發布給學生',
 
     //ManageClass.vue
     stuMgt: '學生管理',

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

@@ -81,7 +81,8 @@ export default {
         copyTitle: '複製評量',
         copyContent: '確認複製當前評量嗎?',
         copyContent1: '課中評量不能進行複製操作。',
-        paperExam:'紙本測驗'
+        paperExam:'紙本測驗',
+        loadAll:'已加載所有數據',
     },
 
     //建立評量學校/個人
@@ -287,6 +288,8 @@ export default {
     simple: {
         totalPeople: '總人數',
         missExam: '缺考數',
+        missExamRate: '缺考率',
+        ccRate:'及格率',
         classLabel: '班級',
         sjLabel: '學科',
         avgScore: '平均分',

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

@@ -8,7 +8,7 @@ export default {
 	edit:'編輯記錄',
 	editTitle:'編輯課例',
 	addTitle:'新增課例',
-	week:'本',
+	week:'本',
 	month:'本月',
 	semester:'本學期',
 	custom:'自定義範圍',
@@ -68,7 +68,7 @@ export default {
 	echarts:{
 		count1:'課例總數',
 		count2:'今日課例',
-		count3:'本課例',
+		count3:'本課例',
 		count4:'本月課例',
 		count5:'本學期課例',
 		count6:'教師數',
@@ -86,14 +86,14 @@ export default {
 		title4:'常用科技手段統計',
 		noData:'暫無數據',
 		weekUtil:'第',
-		week:'',
+		week:'',
 		count:'課例數量',
-		ac1:'線上評(校)',
-		ac2:'課中評(校)',
-		ac3:'閱卷評(校)',
-		ac4:'線上評(個)',
-		ac5:'課中評(個)',
-		ac6:'閱卷評(個)',
+		ac1:'線上評(校)',
+		ac2:'課中評(校)',
+		ac3:'閱卷評(校)',
+		ac4:'線上評(個)',
+		ac5:'課中評(個)',
+		ac6:'閱卷評(個)',
 		ac7:'作業活動',
 		ac8:'自主學習',
 		online:'線上',

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

@@ -5,7 +5,7 @@ export default {
     schoolList: '已加入或申請學校',
     langSetting: '網站語言設定',
     langTips: '請選擇網站要用來顯示選單、互動頁面以及通知資訊的語言',
-    langCheck: '使用瀏覽器語系示',
+    langCheck: '使用瀏覽器語系示',
     themeSetting: '網站色彩模式',
     themeTips: '請選擇網站顯示的色彩模式,以便提供最佳的用戶體驗',
     menuSetting: '選單顯示設定',

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

@@ -201,7 +201,7 @@ export default {
     missionListCardTitle1: '評測工作任務',
     missionListCardTitle2: '投票問卷活動',
     choiceTime: "篩選時間",
-    missionListCardPlace: "預設示近30天的活動",
+    missionListCardPlace: "預設示近30天的活動",
     missionListCardLoading: '載入中',
     missionListCardReachBottom: '已經最底,沒活動啦!',
     myProgressBar: {

+ 7 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/teachermgmt.js

@@ -206,6 +206,9 @@ export default {
     setSubjTitle: '設置學科',
     sltSubjTips: '請選擇學科',
     subjectFilter: '學科篩選',
+    statusFilter: '狀態篩選',
+    jobFilter: '職稱篩選',
+    authFilter: '權限篩選',
     search: '搜尋',
     //老師帳號分配空間授權控件teachermgmt/index.vue 空間欄位部分
     allocationSpace: '分配教學空間',
@@ -275,7 +278,8 @@ export default {
     importTips7:'5. note: 教師備註信息,選填;',
     importTips8:'溫馨提示:如果導入教師醍摩豆ID,或者導入的手機或郵箱已註冊醍摩豆ID,系統會自動邀請老師加入學校。',
     importTips9:'點擊或者拖拽文件導入',
-    impText1:'導入總人數:',
+    impText:'無效數據(沒有名字):',
+    impText1:'有效導入數據:',
     impText2:'僅導入姓名:',
     impText3:'系統將自動邀請:',
     impText4:'重新導入',
@@ -292,5 +296,6 @@ export default {
     joinTips2:'綁定學校尚未加入的老師:',
     hasLeader:'當前老師已經是組長了',
     export:'導出名單',
-    teacherList:'教師名單'
+    teacherList:'教師名單',
+    noIpmtData:'暫無可導入數據'
 }

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

@@ -16,6 +16,6 @@ export default {
 	cusInfo:'依據學校定義的學科,建立所屬歸類的課程 Ex:”語文”學科下的 “閱讀理解”',
 	cusTea:'加入負責該類課程授課的所有授課教師',
 	sCusClass:'加入教師於該課程所負責的學生班級',
-	examMode:'進行評量的方式有三種:\n1.線上自主評量,具備授權的學生可直接登入醍摩豆雲平台學生帳號,直接於平台上選擇評量活動進行測驗。\n2.智慧教室評量,教師於課堂上使用HiTeach智慧教學系統的測驗模式直接進行評。\n3.	卷卡合一評量,透過紙本考試的方式進行測驗,作答紙本透過閱卷方式導入平台運用。',
+	examMode:'進行評量的方式有三種:\n1.線上自主評量,具備授權的學生可直接登入醍摩豆雲平台學生帳號,直接於平台上選擇評量活動進行測驗。\n2.智慧教室評量,教師於課堂上使用HiTeach智慧教學系統的測驗模式直接進行評。\n3.	卷卡合一評量,透過紙本考試的方式進行測驗,作答紙本透過閱卷方式導入平台運用。',
 	targetTips:'溫馨提示:\n1.班級類型:編制班和選課班只能選其一; \n2.課程數量:只能選擇一個課程; \n3.班級數量:同一個課程的班級可以多選;\n4.個人名單:跨校名單(含其他學校的學生)不可選擇。'
 }

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

@@ -119,7 +119,7 @@ export default {
         signQrCode: '簽到碼',
         isStart: '是否開始簽到:',
         autoFresh: '定時刷新(10s):',
-        fullScreen: '全顯示',
+        fullScreen: '全螢幕顯示',
         signCount: '簽到統計',
         signRate: '簽到率',
         hwCount: '作業統計',

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

@@ -20,7 +20,7 @@ export default {
 	day: '天',
 	week: '週',
 	diffTip1: '月前',
-	diffTip2: '前',
+	diffTip2: '前',
 	diffTip3: '天前',
 	diffTip4: '小時前',
 	diffTip5: '分鐘前',

+ 21 - 0
TEAMModelOS/ClientApp/src/store/module/user.js

@@ -18,6 +18,8 @@ export default {
             blob_uri: undefined,    // 老師Blob網址
             courses: undefined,     // 老師的個人課程
             syllabus: undefined,    // 老師的個人課綱
+            lessonShow: undefined,    // 课堂记录是否自动发布
+            lessonLimit: undefined,    // 个人课程课堂记录最多保存的数量
         },
         schoolProfile: { // 老師在學校的設定檔
             blob_uri: undefined,    // 學校Blob網址
@@ -39,6 +41,13 @@ export default {
         curPeriod: undefined
     },
     getters: {
+        getTeacherLessonShow: state => {
+            if (state.userProfile.lessonShow) {
+                return state.userProfile.lessonShow
+            } else {
+                return []
+            }
+        },
         getTeacherAll: state => {
             if (state.teachers !== undefined) {
                 return state.teachers
@@ -109,6 +118,16 @@ export default {
         }
     },
     mutations: {
+        setLessonShow(state, data) {
+            state.userProfile.lessonShow = data
+            //更新本地数据
+            let user_profile = localStorage.getItem('user_profile')
+            if (user_profile) {
+                let userProfile = JSON.parse(decodeURIComponent(user_profile, "utf-8"))
+                userProfile.lessonShow = data
+                localStorage.setItem('user_profile', encodeURIComponent(JSON.stringify(userProfile)))
+            }
+        },
         /* 设置当前学段 */
         setCurPeriod(state, data) {
             state.curPeriod = data
@@ -183,6 +202,8 @@ export default {
             state.userProfile.osblob_sas = data.osblob_sas // 老師加入的學校清單
             state.userProfile.osblob_uri = data.osblob_uri // 老師加入的學校清單
             state.userProfile.syllabus = data.syllabus // 老師的個人課綱
+            state.userProfile.lessonShow = data.lessonShow
+            state.userProfile.lessonLimit = data.lessonLimit
         },
         setSchoolProfile(state, data) {
             state.schoolProfile.blob_sas = data.blob_sas // 老師在學校的Blob金鑰,讀寫

+ 1 - 1
TEAMModelOS/ClientApp/src/utils/excel.js

@@ -7,7 +7,7 @@ function auto_width(ws, data) {
     const colWidth = data.map(row => row.map(val => {
         /*if null/undefined*/
         if (val == null) {
-            return { 'wch': 10 };
+            return { 'wch': 140 };
         }
         /*if chinese*/
         else if (val.toString().charCodeAt(0) > 255) {

+ 17 - 22
TEAMModelOS/ClientApp/src/utils/js-fn.js

@@ -1,7 +1,7 @@
 
 import store from '@/store'
 import {
-	app
+    app
 } from '@/boot-app.js'
 /*
  * 根据某个属性进行分组
@@ -100,7 +100,7 @@ function createVideoPoster(url, name, quality) {
                 video.setAttribute('crossOrigin', 'Anonymous')
                 video.setAttribute('src', url)
                 video.currentTime = 1
-				console.log(url)
+                console.log(url)
                 video.addEventListener('loadeddata', () => {
                     let canvas = document.createElement('canvas')
                     canvas.width = 300
@@ -127,7 +127,7 @@ function createVideoPoster(url, name, quality) {
  *dataUrl转文件 
  */
 function dataURLtoFile(dataurl, filename) {
-	console.log(...arguments);
+    console.log(...arguments);
     let arr = dataurl.split(',')
     let mime = arr[0].match(/:(.*?);/)[1]
     let bstr = atob(arr[1])
@@ -264,26 +264,21 @@ function getGradeNameByYear(data, curPd, year) {
  * @param curPd 当前学段id
  * @param grade 年级index
  */
-function getYearByGrade(data, curPd, grade) {
+function getYearByGrade(grade) {
     let date = new Date()
     let curYear = date.getFullYear()
     let month = date.getMonth() + 1
-    if (grade > -1 && data && data.period && curPd) {
-        let pData = data.period.find(item => {
-            return item.id == curPd
+    grade = parseInt(grade)
+    let curPeriod = store.state.user?.curPeriod
+    if (grade > -1 && curPeriod) {
+        let start = curPeriod.semesters.find(item => {
+            return item.start == 1
         })
-        if (pData) {
-            let start = pData.semesters.find(item => {
-                return item.start == 1
-            })
-            // 根据入学月份确定当前年级和学级的关系
-            if (start && month < start.month) {
-                curYear--
-            }
-            return curYear - grade
-        } else {
-            return curYear
+        // 根据入学月份确定当前年级和学级的关系
+        if (start && month < start.month) {
+            curYear--
         }
+        return curYear - grade
     } else {
         return curYear
     }
@@ -310,10 +305,10 @@ function getTeacherSubjects(ids) {
                 let subjectInfo = schoolPeriod[i].subjects.find(subject => subject.id === sid)
                 if (subjectInfo) {
                     data.push({
-                        periodId:schoolPeriod[i].id,
-                        periodName:schoolPeriod[i].name,
-                        subjectId:subjectInfo.id,
-                        subjectName:subjectInfo.name
+                        periodId: schoolPeriod[i].id,
+                        periodName: schoolPeriod[i].name,
+                        subjectId: subjectInfo.id,
+                        subjectName: subjectInfo.name
                     })
                     break
                 }

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

@@ -498,7 +498,7 @@
 					abilityDetail.targetName = this.reviewData.targetName
 				}
 				if(this.mode === 'edit'){
-					this.curTaskIndexArr = abilityDetail.stds.map((i,index) => i.task.findIndex(j => j.id === abilityDetail.uploads[index].taskid))
+					this.curTaskIndexArr = abilityDetail.stds.map((i,index) => abilityDetail.uploads[index] ? i.task.findIndex(j => j.id === abilityDetail.uploads[index].taskid) : 0)
 				}
 				return abilityDetail
 			},

+ 41 - 6
TEAMModelOS/ClientApp/src/view/assessment/Assessment.vue

@@ -12,21 +12,21 @@
 						</Option>
 					</Select>
 					<!-- 状态选择 -->
-					<Select v-model="curStatus" style="width:200px;margin-left: 15px;" @on-change="doFilter">
+					<Select v-model="curStatus" style="width:150px;margin-left: 15px;" @on-change="doFilter">
 						<Option v-for="(item,index) in statusList" :value="index" :key="index">
 							{{ item }} 
 							<span v-if="index > 0">( {{ getStatusCount(index - 2) }}人 )</span>
 						</Option>
 					</Select>
 					<!-- 特殊选择 -->
-					<Select v-model="curNoSubmit" style="width:200px;margin-left: 15px;" @on-change="doFilter" placeholder="选择更多条件" clearable>
+					<Select v-model="curNoSubmit" style="width:150px;margin-left: 15px;" @on-change="doFilter" placeholder="选择更多条件" clearable>
 						<Option v-for="(item,index) in noSubmitList" :value="index" :key="index">
 							{{ item }} 
 						</Option>
 					</Select>
 					<!-- 搜索框 -->
 					<Input v-special-char v-model="searchVal" suffix="ios-search" :placeholder="$t('ability.place1')"
-						style="width: auto;margin-left: 15px;" @on-click="doFilter" @on-enter="doFilter" />
+						style="width: 150px;margin-left: 15px;" @on-click="doFilter" @on-enter="doFilter" />
 					<!-- 人数统计 -->
 					<span style="margin-left: 10px;">
@@ -43,6 +43,10 @@
 					</span>
 				</div>
 				<div class="assessment-header-right">
+					<span class="tool-item" @click="onExportTable">
+						<Icon type="md-download"></Icon>
+						<span>导出</span>
+					</span>
 					<span class="tool-item">
 						<i-switch size="large" @on-change="onExpandAllChange">
 							<span slot="open">收起</span>
@@ -50,9 +54,12 @@
 						</i-switch>
 					</span>
 					<span class="tool-item">
-						<span>开启互评</span>
-						<i-switch v-model="isOpenAppraise" @on-change="onSwitchChange"
-							:before-change="beforeHpAppraiseChange" />
+						<span>互评</span>
+						<i-switch v-model="isOpenAppraise" size="large" @on-change="onSwitchChange"
+							:before-change="beforeHpAppraiseChange">
+							<span slot="open">开启</span>
+							<span slot="close">关闭</span>
+						</i-switch>	
 					</span>
 					<span class="tool-item" @click="doUploadProvince" v-if="hasAreaAccess">
 						<Icon type="ios-paper-plane" size="18"/> {{ `推送省平台` }}
@@ -301,6 +308,7 @@
 <script>
 	import Review from '@/view/ability/Review'
 	import VideoReview from '@/view/video/VideoReview'
+	import excel from '@/utils/excel.js'
 	export default {
 		components: {
 			Review,
@@ -619,6 +627,33 @@
 			this.getAssessmentList()
 		},
 		methods: {
+			/* 导出表格数据 */
+			onExportTable(){
+				let header = ['姓名','总学时','线上研修学时','认证材料学时','校本研修学时','课堂实录学时','认证材料需提交数','认证材料未提交数','作业未提交数','课堂实录是否提交']
+				let keys = ['name','totalTime','online','ability','offline','video','abilityCount','noAbilityCount','noHwCount','isSubmitVideo']
+				let datas = this.assessmentList.map(i => {
+					return {
+						name:i.userInfo.name,
+						totalTime:i.totalTime,
+						online:i.hoursArr[0],
+						ability:i.hoursArr[1],
+						offline:i.hoursArr[2],
+						video:i.hoursArr[3],
+						abilityCount:i.abilities.length,
+						noAbilityCount:i.abilities.filter(i => i.zpscore === -1).length,
+						noHwCount:i.trains.filter(item => item.haswork && !item.url).length,
+						isSubmitVideo:i.video ? '已提交':'未提交'
+					}
+				})
+				const params = {
+					title: header,
+					key:keys,
+					data: datas,
+					autoWidth:true,
+					filename: this.$store.state.user.schoolProfile.school_base.name + '研修情况统计表'
+				}
+				excel.export_array_to_excel(params)
+			},
 			/* 全部展开或收起 */
 			onExpandAllChange(val){
 				this.expandedArr = val ? this.assessmentList.map((i,index) => index) : []

+ 5 - 1
TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.less

@@ -34,7 +34,7 @@
 
     .evaluation-list-main {
         width: 100%;
-        height: ~"calc(100% - 45px)";
+        height: ~"calc(100% - 50px)";
 
         .evaluation-item {
             padding: 15px 10px 15px 15px;
@@ -176,4 +176,8 @@
     &:hover{
         color: #2db7f5;
     }
+}
+.ev-list-scroll{
+    width: 100%;
+    height: 100%;
 }

+ 161 - 138
TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.vue

@@ -9,9 +9,9 @@
                         {{ scope == 'school' ? $t('learnActivity.mgtScEv.listLabel1') : $t('learnActivity.mgtScEv.listLabel2') }}
                     </b>
                     <div style="float:right" v-if="!isSearch">
-                        <Icon type="md-add" class=" to-create-icon" @click="goToCreate" :title="$t('learnActivity.mgtScEv.create')" v-if="$access.can('admin.*|schoolAc-upd')" />
+                        <Icon type="md-add" class=" to-create-icon" @click="goToCreate" :title="$t('learnActivity.mgtScEv.create')" v-if="evAuthStatus" />
                         <Icon type="md-copy" class=" to-create-icon" @click="copyEv" :title="$t('learnActivity.mgtScEv.copy')" />
-                        <Icon type="md-trash" v-show="evaListShow.length" class="to-create-icon" :title="$t('learnActivity.mgtScEv.delete')" @click="deleteEvaluation" v-if="$access.can('admin.*|schoolAc-upd')" />
+                        <Icon type="md-trash" v-show="evaListShow.length" class="to-create-icon" :title="$t('learnActivity.mgtScEv.delete')" @click="deleteEvaluation" v-if="evAuthStatus" />
                         <!-- <Icon type="md-create" v-show="evaListShow.length && evaListShow[curEvaIndex] && evaListShow[curEvaIndex].progress == 'pending'" class="to-create-icon" @click="editEvaluation" :title="$t('learnActivity.mgtScEv.edit')" v-if="$access.can('admin.*|schoolAc-upd')" /> -->
                         <!-- 筛选 -->
                         <Poptip style="float:right" trigger="click" :offset="-10" theme="light">
@@ -19,7 +19,7 @@
                             <div slot="content">
                                 <div class="filter-item">
                                     <span>{{$t('learnActivity.mgtScEv.ftStatus')}}</span>
-                                    <Select v-model="filter.status" style="width:100px" size="small" clearable @on-change="filterEv">
+                                    <Select v-model="filter.progress" style="width:100px" size="small" clearable @on-change="filterEv">
                                         <Option value="pending">{{$t('learnActivity.mgtScEv.pending')}}</Option>
                                         <Option value="going">{{$t('learnActivity.mgtScEv.going')}}</Option>
                                         <Option value="finish">{{$t('learnActivity.mgtScEv.finish')}}</Option>
@@ -27,50 +27,43 @@
                                 </div>
                                 <div class="filter-item">
                                     <span>{{$t('learnActivity.mgtScEv.ftMode')}}</span>
-                                    <Select v-model="filter.mode" style="width:100px" size="small" clearable @on-change="filterEv">
+                                    <Select v-model="filter.source" style="width:100px" size="small" clearable @on-change="filterEv">
                                         <Option v-for="(item,index) in $GLOBAL.EV_MODE()" :value="item.value" :key="index">{{ item.label }}</Option>
                                     </Select>
                                 </div>
-                                <!-- <div class="filter-item">
-                                    <span>{{$t('learnActivity.mgtScEv.ftType')}}</span>
-                                    <Select v-model="filter.type" style="width:100px" size="small" clearable @on-change="filterEv">
-                                        <Option v-for="(item,index) in $GLOBAL.EV_TYPE()" :value="item.value" :key="index">{{ item.label }}</Option>
-                                    </Select>
-                                </div> -->
                             </div>
                         </Poptip>
                         <Icon type="md-search" class="to-create-icon" @click="isSearch = !isSearch" :title="$t('learnActivity.mgtScEv.search')" />
                     </div>
                     <div v-else style="float:right;width:calc(100% - 150px);padding-right:10px;" class="light-iview-input">
-                        <Input v-special-char icon="ios-close" v-model="keyword" :placeholder="$t('schoolBaseInfo.codeSearchHolder')" autofocus style="width:100%" @on-click="closeKeySearch" @on-change="filterByName" />
+                        <Input v-special-char icon="ios-close" v-model="filter.name" :placeholder="$t('schoolBaseInfo.codeSearchHolder')" autofocus style="width:100%" @on-click="closeKeySearch" @on-change="$jsFn.debounce(filterEv,1000)()" />
                     </div>
                 </div>
-                <div class="evaluation-list-main">
-                    <vuescroll>
-                        <div v-for="(item,index) in evaListShow" @click.capture="selectEvaluation(index)" :class="['evaluation-item','block-bg',index == curEvaIndex ? 'block-bg-active':'']" :key="index">
-                            <p class="evaluation-name">
-                                {{item.name}}
-                                <!-- 修改评测名称 -->
-                                <Icon type="md-create" class="edit-end-time" @click="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
-                            </p>
-                            <div class="all-tag-box">
-                                <div class="tags-wrap">
-                                    <!-- 活动进度状态 -->
-                                    <!-- <span class="evaluation-status-tag ev-tag-common" :style="{ background:item.progColor, color: item.progColor}">
+                <Scroll class="evaluation-list-main" :on-reach-bottom="handleReachBottom">
+                    <div v-for="(item,index) in evaListShow" @click.capture="selectEvaluation(index)" :class="['evaluation-item','block-bg',index == curEvaIndex ? 'block-bg-active':'']" :key="index">
+                        <p class="evaluation-name">
+                            {{item.name}}
+                            <!-- 修改评测名称 -->
+                            <Icon type="md-create" class="edit-end-time" @click="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
+                        </p>
+                        <div class="all-tag-box">
+                            <div class="tags-wrap">
+                                <!-- 活动进度状态 -->
+                                <!-- <span class="evaluation-status-tag ev-tag-common" :style="{ background:item.progColor, color: item.progColor}">
                                     {{ item.progText }}
                                 </span> -->
-                                    <!-- 评测模式 -->
-                                    <span class="ev-info-tag ev-tag-common">{{getModeLabel(item.source)}}</span>
-                                    <span class="ev-info-tag ev-tag-common" v-if="item.examType && item.examType.name">
-                                        {{item.examType.name}}
-                                    </span>
-                                    <!-- <span class="ev-info-tag ev-tag-common">{{getTypeLabel(item.type)}}</span> -->
-                                    <!-- 活动评分状态 -->
-                                    <span class="evaluation-status-tag ev-tag-common" :style="{ color: item.scoreColor}">
-                                        {{ item.scoreText }}
-                                    </span>
-                                    <Icon class="exam-target" size="20" type="ios-people" @click="getExamTarget(item)" />
-                                    <!-- <Tooltip @on-popper-show="getExamTarget(item)">
+                                <!-- 评测模式 -->
+                                <span class="ev-info-tag ev-tag-common">{{getModeLabel(item.source,item.qamode)}}</span>
+                                <span class="ev-info-tag ev-tag-common" v-if="item.examType && item.examType.name">
+                                    {{item.examType.name}}
+                                </span>
+                                <!-- <span class="ev-info-tag ev-tag-common">{{getTypeLabel(item.type)}}</span> -->
+                                <!-- 活动评分状态 -->
+                                <span class="evaluation-status-tag ev-tag-common" :style="{ color: item.scoreColor}">
+                                    {{ item.scoreText }}
+                                </span>
+                                <Icon class="exam-target" size="20" type="ios-people" @click="getExamTarget(item)" />
+                                <!-- <Tooltip @on-popper-show="getExamTarget(item)">
                                         <Icon class="exam-target" size="20" type="ios-people" />
                                         <div slot="content" style="padding-left:15px;min-width:180px">
                                             <p style="margin-left:-15px">
@@ -83,36 +76,35 @@
                                             </ul>
                                         </div>
                                     </Tooltip> -->
-                                </div>
-                                <!-- 立即结束 和评测状态 按钮-->
-                                <span v-if="item.progress == 'going'" class="handle-end-tag ev-tag-common" @click="handleEnd(index)">
-                                    {{$t('learnActivity.mgtScEv.stop')}}
-                                </span>
-                                <span v-else class="handle-end-tag ev-tag-common" :style="{ background:'#c0c0c0', color: item.progColor}">
-                                    {{ item.progText }}
-                                </span>
                             </div>
-
-                            <p class="evaluation-type" style="margin-top:10px">
-                                <Icon type="md-time" style="margin-right:5px;" size="16" />
-                                <span>{{$jsFn.timeFormat(item.startTime)}}</span>
-                                -
-                                <span>{{$jsFn.timeFormat(item.endTime)}}</span>
-                                <!-- 修改评测结束时间 -->
-                                <Icon type="md-create" class="edit-end-time" v-if="item.progress == 'going'" @click="editEvEndtime(index)" :title="$t('learnActivity.mgtScEv.editEndTime')" />
-                            </p>
-                            <!-- 二维码分享 -->
-                            <span class="ev-qr-tag" style="top:50%" @click="openQrcode(index)" v-show="item.source == '0' && item.progress == 'going'">
-                                <Icon size="20" custom="iconfont icon-qr-code" class="qr-code-icon" />
+                            <!-- 立即结束 和评测状态 按钮-->
+                            <span v-if="item.progress == 'going'" class="handle-end-tag ev-tag-common" @click="handleEnd(index)">
+                                {{$t('learnActivity.mgtScEv.stop')}}
                             </span>
-                            <!-- 立即结束 图标-->
-                            <!-- <span class="ev-qr-tag" style="top:65%" @click="handleEnd(index)" :title="$t('learnActivity.mgtScEv.stop')">
+                            <span v-else class="handle-end-tag ev-tag-common" :style="{ background:'#c0c0c0', color: item.progColor}">
+                                {{ item.progText }}
+                            </span>
+                        </div>
+
+                        <p class="evaluation-type" style="margin-top:10px">
+                            <Icon type="md-time" style="margin-right:5px;" size="16" />
+                            <span>{{$jsFn.timeFormat(item.startTime)}}</span>
+                            -
+                            <span>{{$jsFn.timeFormat(item.endTime)}}</span>
+                            <!-- 修改评测结束时间 -->
+                            <Icon type="md-create" class="edit-end-time" v-if="item.progress == 'going'" @click="editEvEndtime(index)" :title="$t('learnActivity.mgtScEv.editEndTime')" />
+                        </p>
+                        <!-- 二维码分享 -->
+                        <span class="ev-qr-tag" style="top:50%" @click="openQrcode(index)" v-show="item.source == '0' && item.progress == 'going'">
+                            <Icon size="20" custom="iconfont icon-qr-code" class="qr-code-icon" />
+                        </span>
+                        <!-- 立即结束 图标-->
+                        <!-- <span class="ev-qr-tag" style="top:65%" @click="handleEnd(index)" :title="$t('learnActivity.mgtScEv.stop')">
                                 <Icon size="20" type="md-power" class="qr-code-icon" />
                             </span> -->
-                        </div>
-                        <EmptyData v-if="evaListShow.length == 0" style="margin-top:100px;" :textContent="`${$t('learnActivity.mgtScEv.nodata')}`"></EmptyData>
-                    </vuescroll>
-                </div>
+                    </div>
+                    <EmptyData v-if="evaListShow.length == 0" style="margin-top:100px;" :textContent="`${$t('learnActivity.mgtScEv.nodata')}`"></EmptyData>
+                </Scroll>
             </div>
             <div slot="right" class="evaluation-detail-wrap">
                 <!--顶部菜单-->
@@ -135,14 +127,14 @@
                     </span>
                 </div>
                 <!-- 评测数据 -->
-                <DataView v-show="curBarIndex == 0" :examInfo="examDetaiInfo" :correctData="correctData" :simpleData="simpleData" :dataErr="dataErr" class="evaluation-base-info"></DataView>
+                <DataView v-if="curBarIndex == 0" :examInfo="examDetaiInfo" :correctData="correctData" :simpleData="simpleData" :dataErr="dataErr" class="evaluation-base-info"></DataView>
                 <!-- 作答详情 -->
-                <AnswerTable v-show="curBarIndex == 3" :examInfo="examDetaiInfo" :correctData="correctData" class="evaluation-base-info"></AnswerTable>
+                <AnswerTable v-else-if="curBarIndex == 3" :examInfo="examDetaiInfo" :correctData="correctData" class="evaluation-base-info"></AnswerTable>
                 <!-- 评测试卷 -->
-                <ExamPaper v-show="curBarIndex == 1" :examInfo="examDetaiInfo" class="evaluation-base-info"></ExamPaper>
+                <ExamPaper v-else-if="curBarIndex == 1" :examInfo="examDetaiInfo" class="evaluation-base-info"></ExamPaper>
                 <!-- 阅卷任务 -->
                 <!-- <ExamTask v-show="curBarIndex == 2" class="evaluation-base-info"></ExamTask> -->
-                <MarkSetting v-show="curBarIndex == 2" ref="markSetting" v-if="examDetaiInfo" :evInfo="examDetaiInfo" v-model="isSetting"></MarkSetting>
+                <MarkSetting v-else-if="curBarIndex == 2 && examDetaiInfo" ref="markSetting" :evInfo="examDetaiInfo" v-model="isSetting"></MarkSetting>
             </div>
         </Split>
         <!-- 修改评测名称 -->
@@ -187,6 +179,8 @@ export default {
     },
     data() {
         return {
+            ctnToken: '',
+            pageCount: 20,
             dataErr: false,
             isSetting: false,
             examTargets: [],
@@ -212,7 +206,6 @@ export default {
             curSubIndex: 0,
             curBarIndex: 0,
             curEvaIndex: 0,
-            evaluationList: [],
             evaListShow: [],
             examDetaiInfo: {},
             targetList: [],
@@ -220,9 +213,9 @@ export default {
             filterPeriod: undefined,
             curPdInfo: {},
             filter: {
-                status: '',
-                mode: '',
-                type: ''
+                progress: '',
+                source: '',
+                name: ''
             }
         }
     },
@@ -235,17 +228,43 @@ export default {
                     return d && d > date.valueOf() + 86400000
                 }
             }
+        },
+        evAuthStatus(){
+            if(this.scope == 'school'){
+                return this.$access.can('admin.*|schoolAc-upd')
+            }else{
+                return true
+            }
         }
     },
+    mounted() {
+        this.$EventBus.$off('onStatusChange')
+        this.$EventBus.$on('onStatusChange', () => {
+            if (this.evaListShow[this.curEvaIndex] && this.evaListShow[this.curEvaIndex].sStatus != 1) {
+                this.evaListShow[this.curEvaIndex].sStatus = 1
+                this.evaListShow[this.curEvaIndex].scoreText = this.$t('learnActivity.mgtScEv.scoreStatus1')
+                this.evaListShow[this.curEvaIndex].scoreColor = '#515a6e'
+            }
+        })
+    },
     created() {
         if (this.$route.name === 'schoolExam') {
             this.scope = 'school'
         } else {
             this.scope = 'private'
         }
-        this.findEvaluation()
+        this.filterPeriod = this.$store.state.user.curPeriod?.id
+        this.findEvaluation(true)
     },
     methods: {
+        handleReachBottom() {
+            return this.findEvaluation()
+        },
+        closeKeySearch() {
+            this.isSearch = false
+            this.filter.name = ''
+            this.filterEv()
+        },
         getExamTarget(data) {
             let ids = data.classes && data.classes.length ? data.classes : data.stuLists
             this.$api.common.getGroupListByIds({
@@ -331,7 +350,6 @@ export default {
             } else {
                 this.correctData = []
             }
-            console.log('错题率分析:', this.correctData)
         },
         //获取已结束评测简要数据分析
         findSimpleAna() {
@@ -412,46 +430,68 @@ export default {
             this.qrConfig.shareContent = `${this.$t('learnActivity.mgtScEv.shareText1')}\n\n${soc}${socName}\n${this.$t('learnActivity.mgtScEv.shareText3')}${evType}\n${this.$t('cusMgt.inviteInfo8')}${this.$store.state.userInfo.name}\n${this.$t('learnActivity.mgtScEv.shareText2')}${evName}\n\n${this.$t('learnActivity.mgtScEv.shareText6')}\n${shortUrl.result || encodeURI(this.shareUrl)}\n\n${this.$t('learnActivity.mgtScEv.shareText7')}\nURL:https://${window.location.host}/login/student`
             this.showQrStatus = true
         },
-        //查询评测列表
-        findEvaluation() {
-            this.isLoading = true
-            let requestData = {
-                code: this.scope == 'school' ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId
-            }
-            this.$api.learnActivity.FindExamList(requestData).then(
-                res => {
-                    if (!res.error) {
-                        res.examInfo = res.examInfo.sort((a, b) => {
-                            return a.createTime - b.createTime > 0 ? -1 : 1
-                        })
-                        res.examInfo.forEach(item => {
-                            let statusInfo = this.getEvStatusInfo(item.progress, item.sStatus)
-                            item.progText = statusInfo.progText
-                            item.progColor = statusInfo.progColor
-                            item.scoreText = statusInfo.scoreText
-                            item.scoreColor = statusInfo.scoreColor
-                        })
-                        this.evaluationList = res.examInfo
-                        this.evaListShow = res.examInfo
-                        if (this.scope == 'school') {
-                            this.filterByPeriod()
-                        } else {
+        /**
+         * @param isFresh 是否清空当前列表 如果是筛选条件变化需要清空,如果是只是下拉刷新则不需要
+         */
+        findEvaluation(isFresh) {
+            // 下拉加载需要返回一个Promise
+            return new Promise((r, j) => {
+                if (isFresh) {
+                    this.evaListShow = []
+                    this.ctnToken = ''
+                }
+                let requestData = {
+                    code: this.scope == 'school' ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId,
+                    count: this.pageCount
+                }
+                //判断是否加载完所有数据
+                if(this.ctnToken == 'end'){
+                    this.$Message.success(this.$t('learnActivity.mgtScEv.loadAll'))
+                    r()
+                    return
+                }
+                if(this.ctnToken) requestData.token = this.ctnToken
+                //校本评测根据学段查询
+                if (this.scope == 'school') requestData.period = this.filterPeriod
+                //添加其他查询条件
+                if (this.filter.progress) requestData.progress = this.filter.progress
+                if (this.filter.source) requestData.source = this.filter.source
+                if (this.filter.name) requestData.name = this.filter.name
+                this.isLoading = true
+                this.$api.learnActivity.FindExamList(requestData).then(
+                    res => {
+                        if (!res.error) {
+                            res.examInfo = res.examInfo.sort((a, b) => {
+                                return a.createTime - b.createTime > 0 ? -1 : 1
+                            })
+                            res.examInfo.forEach(item => {
+                                let statusInfo = this.getEvStatusInfo(item.progress, item.sStatus)
+                                item.progText = statusInfo.progText
+                                item.progColor = statusInfo.progColor
+                                item.scoreText = statusInfo.scoreText
+                                item.scoreColor = statusInfo.scoreColor
+                            })
+                            this.evaListShow.push(...res.examInfo)
                             if (res.examInfo.length) {
                                 this.selectEvaluation(0)
                             } else {
                                 this.isLoading = false
                             }
+                            this.ctnToken = res.token || 'end' //返回token为null代表已经查完所有数据了
+                            r()
+                        } else {
+                            // this.$Message.error('API ERROR!')
+                            this.$Message.error(this.$t('learnActivity.mgtScEv.evListErr'))
+                            this.isLoading = false
+                            j()
                         }
-                    } else {
-                        // this.$Message.error('API ERROR!')
-                        this.$Message.error(this.$t('learnActivity.mgtScEv.evListErr'))
+                    },
+                    err => {
                         this.isLoading = false
+                        j()
                     }
-                },
-                err => {
-                    this.isLoading = false
-                }
-            )
+                )
+            })
         },
         getEvStatusInfo(progress, isScore) {
             let info = {}
@@ -465,30 +505,18 @@ export default {
                 info.progText = this.$t('learnActivity.mgtScEv.finish')
                 info.progColor = '#75787d'
             }
+            // 待评分
             if (isScore === 0) {
                 info.scoreText = this.$t('learnActivity.mgtScEv.scoreStatus')
                 info.scoreColor = '#ff9900'
-            } else if (isScore === 1) {
+            }
+            //已评分
+            else if (isScore === 1) {
                 info.scoreText = this.$t('learnActivity.mgtScEv.scoreStatus1')
                 info.scoreColor = '#515a6e'
             }
             return info
         },
-        //根据学段筛选评测
-        filterByPeriod() {
-            this.curEvaIndex = 0
-            sessionStorage.setItem('evPeriod', this.filterPeriod)
-            if (this.filterPeriod) {
-                this.evaListShow = this.evaluationList.filter(item => item.period.id === this.filterPeriod)
-            } else {
-                this.evaListShow = [...this.evaluationList]
-            }
-            if (this.evaListShow.length) {
-                this.selectEvaluation(0)
-            } else {
-                this.isLoading = false
-            }
-        },
         selectEvaluation(index) {
             this.checkScoreSave(this.toEvaluation, index)
         },
@@ -518,7 +546,7 @@ export default {
             this.$api.learnActivity.FindExamInfo(requestData).then(
                 async res => {
                     this.dataErr = false
-                    
+
                     if (!res.error) {
                         let resData = res.examInfo[0]
                         resData.score = 0
@@ -619,7 +647,6 @@ export default {
                     quNo: data
                 })
             })
-            console.log('评测所有题号信息:', this.paperQuInfo)
         },
         checkScoreSave(fn, index) {
             let compStu = this.$refs['score-box'] ? this.$refs['score-box'].$refs['byStuMark'] : null
@@ -726,22 +753,14 @@ export default {
         },
         //筛选评测
         filterEv() {
-            let curPdEv = this.evaluationList.filter(item => item.period.id === this.filterPeriod)
-            this.evaListShow = curPdEv.filter(item => {
-                let status = !this.filter.status || (this.filter.status == item.progress)
-                let type = !this.filter.type || (this.filter.type == item.type)
-                let mode = !this.filter.mode || (this.filter.mode == item.source)
-                return status && type && mode
-            })
-        },
-        filterByName() {
-            let curPdEv = this.evaluationList.filter(item => item.period.id === this.filterPeriod)
-            this.evaListShow = curPdEv.filter(item => {
-                return item.name.indexOf(this.keyword) > -1
-            })
+            this.ctnToken = ''
+            this.findEvaluation(true)
         },
         /**获取mode对应的label */
-        getModeLabel(code) {
+        getModeLabel(code, qamode) {
+            if (qamode == 1) {
+                return this.$t('learnActivity.mgtScEv.paperExam')
+            }
             for (let item of this.$GLOBAL.EV_MODE()) {
                 if (item.value == code) {
                     return item.label
@@ -839,12 +858,10 @@ export default {
         },
         '$store.state.user.curPeriod': {
             deep: true,
-            immediate: true,
             handler(n, o) {
                 if (n) {
                     this.filterPeriod = n.id
-                    this.curPdInfo = n
-                    if (this.scope == 'school') this.filterByPeriod()
+                    this.findEvaluation(true)
                 }
             }
         }
@@ -856,4 +873,10 @@ export default {
 @import "./ExamMgt.less";
 </style>
 <style lang="less">
+.evaluation-list-main {
+    .ivu-scroll-container {
+        width: 100%;
+        height: 100% !important;
+    }
+}
 </style>

+ 1 - 1
TEAMModelOS/ClientApp/src/view/learnactivity/Scoring.vue

@@ -1018,7 +1018,7 @@ export default {
                     //TODO 处理年级选项
                     data = this.examInfo.grades
                     data.forEach(item => {
-                        let year = this.$jsFn.getYearByGrade(this.schoolBase, this.periodId, item.id)
+                        let year = this.$jsFn.getYearByGrade(item.id)
                         item.children = []
                         this.examClassLilst.forEach(classItem => {
                             if (classItem.year == year) {

+ 11 - 5
TEAMModelOS/ClientApp/src/view/learnactivity/echarts/KngPoint.vue

@@ -1,13 +1,13 @@
 <template>
     <div class="recognize-perform-chart">
-        <div :id="'knowledge'+id" style="width: 306px; height: 300px;margin:auto" v-if="knowledge.kn.length"></div>
-        <div v-else class="no-kn-point">
+        <div v-if="!knowledge.kn || !knowledge.kn.length" class="no-kn-point">
             <p class="chart-title">{{$t('studentWeb.exam.chart.keyPointPerformance')}}</p>
             <img src="@/assets/image/none.png" alt="" class="tips-img">
             <p class="chart-text">
                 {{$t('learnActivity.simple.noKn')}}
             </p>
         </div>
+        <div :id="'knowledge'+id" style="width: 306px; height: 300px;margin:auto" v-else></div>
     </div>
 </template>
 
@@ -30,6 +30,7 @@ export default {
             id: '',
             categories: [],
             akps: [], //个人
+            myChart: undefined
         }
     },
     created() {
@@ -44,7 +45,7 @@ export default {
                     name: item
                 })
             })
-            let myChart = this.$echarts.init(document.getElementById("knowledge" + this.id), 'macarons')
+            if (!this.myChart) this.myChart = this.$echarts.init(document.getElementById("knowledge" + this.id), 'macarons')
             let option = {
                 title: {
                     text: this.$t('studentWeb.exam.chart.keyPointPerformance'),
@@ -76,7 +77,7 @@ export default {
                     }
                 ],
             }
-            myChart.setOption(option)
+            this.myChart.setOption(option)
         },
         getFiled() {
             let akps = []
@@ -103,6 +104,11 @@ export default {
                         this.getFiled()
                         this.setMap()
                     })
+                } else {
+                    if (this.myChart) {
+                        this.myChart.dispose()
+                        this.myChart = undefined
+                    }
                 }
             }
         }
@@ -125,7 +131,7 @@ export default {
         width: 120px;
         margin-top: 30px;
     }
-    .chart-text{
+    .chart-text {
         font-size: 12px;
         color: #808695;
     }

+ 18 - 13
TEAMModelOS/ClientApp/src/view/learnactivity/tabs/AnswerTable.vue

@@ -352,7 +352,7 @@ export default {
                     //TODO 处理年级选项
                     data = this.examInfo.grades
                     data.forEach(item => {
-                        let year = this.$jsFn.getYearByGrade(this.schoolBase, this.periodId, item.id)
+                        let year = this.$jsFn.getYearByGrade(item.id)
                         item.children = []
                         this.examClassLilst.forEach(classItem => {
                             if (classItem.year == year) {
@@ -433,7 +433,7 @@ export default {
                 this.schoolClassList = res.school_classes
             }
         )
-        if (this.$route.name == 'privateEvaluation') {
+        if (this.$route.name == 'privExam') {
             this.routerScope = 'private'
         } else {
             this.routerScope = 'school'
@@ -442,6 +442,7 @@ export default {
     watch: {
         examInfo: {
             handler(n, o) {
+                if (!n) return
                 if (n.subjects && n.subjects.length) {
                     this.chooseSubject = n.subjects[0].id;
                 }
@@ -462,7 +463,7 @@ export default {
                 this.examStuList = []
                 this.chooseClass = ''
                 //这里统一获取名单数据(教学班、行政班、个人名单)
-                let ids = this.examInfo.stuLists.length ? this.examInfo.stuLists : this.examInfo.classes
+                let ids = n.stuLists?.length ? n.stuLists : n.classes
                 let params = {
                     'schoolId': this.$store.state.userInfo.schoolCode,
                     'ids': ids
@@ -478,7 +479,8 @@ export default {
                 )
 
             },
-            deep: true
+            deep: true,
+            immediate: true
         },
         targetsData: {
             handler(n, o) {
@@ -1140,14 +1142,6 @@ export default {
          * }
          */
         getStatusInfo(answer, score, status) {
-            //评测结束,学生缺考
-            if (status == 1) {
-                return {
-                    status: 1,
-                    statusText: this.$t('learnActivity.score.status4'),
-                    statusColor: '#ed4014'
-                }
-            }
             //评测设置学生可以补考
             if (status == 2 || status == 3) {
                 return {
@@ -1156,14 +1150,25 @@ export default {
                     statusColor: '#2db7f5'
                 }
             }
+
+            //评测结束,学生缺考
+            if (status == 1 && this.examInfo.progress == 'finish') {
+                return {
+                    status: 1,
+                    statusText: this.$t('learnActivity.score.status4'),
+                    statusColor: '#ed4014'
+                }
+            }
+
             //评测进行中,未作答
-            if (!answer.length) {
+            if (status == 1 && this.examInfo.progress == 'going') {
                 return {
                     status: 0,
                     statusText: this.$t('learnActivity.score.status1'),
                     statusColor: '#808695'
                 }
             }
+            // status:0
             //已作答,未评分
             if (score.includes(-1)) {
                 return {

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

@@ -31,22 +31,25 @@
                         {{$t('learnActivity.simple.totalPeople')}}
                     </p>
                 </div>
-                <!-- 缺考人数 -->
+                <!-- 缺考人数 (缺考率)-->
                 <div class="data-count-item">
                     <p class="data-value" style="color:#ed4014">
-                        {{examInfo.lostStu ? examInfo.lostStu.length : 0}}
+                        {{examInfo.qRate}}
+                        <span style="font-size:13px">%</span>
                     </p>
                     <p class="data-text">
-                        {{$t('learnActivity.simple.missExam')}}
+                        {{$t('learnActivity.simple.missExamRate')}}
                     </p>
                 </div>
                 <!-- 及格人数 -->
                 <div class="data-count-item" v-show="examInfo.subjects && examInfo.subjects.length == 1">
                     <p class="data-value">
-                        {{complyData[0] ? complyData[0].passCount : 0}}
+                        <!-- {{complyData[0] ? complyData[0].passRate : 0}} -->
+                        {{complyData[0] ? complyData[0].passRate : 0}}
+                        <span style="font-size:13px">%</span>
                     </p>
                     <p class="data-text">
-                        {{$t('learnActivity.simple.cc')}}
+                        {{$t('learnActivity.simple.ccRate')}}
                     </p>
                 </div>
                 <!-- 平均分 -->
@@ -261,10 +264,12 @@ export default {
                     let passScore = item.paperScore * 0.6
                     let pass = item.total.filter(i => i >= passScore)
                     let passCount = pass.length
+                    let passRate = item.total.length ? (passCount * 100 / item.total.length).toFixed(1) : 0
                     data.push({
                         id: item.subjectId,
                         name: item.subjectName,
                         passCount: passCount,
+                        passRate: passRate,
                         failCount: item.total.length - passCount
                     })
                 })

+ 25 - 2
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.less

@@ -440,14 +440,21 @@
     display: flex;
     justify-content: space-between;
 }
-.edit-ev-name{
+.common-item-icon{
     display: none;
     font-size: 16px;
     color: #2d8cf0;
     vertical-align: baseline;
     margin-left: 10px;
+    position: absolute;
+}
+.delete-item{
+    right: 60px;
+}
+.ed-name{
+    right: 90px;
 }
-.ac-item-warp:hover .edit-ev-name{
+.ac-item-warp:hover .common-item-icon{
     display: inline-block;
 }
 .has-other-school{
@@ -457,10 +464,26 @@
 .action-text{
     color: #2d8cf0;
 }
+.item-icon-wrap{
+    float:right;
+    margin-right:20px;
+    position: relative;    
+}
+.heart-item{
+    right: 2px;
+}
 .heart-active{
     display: inline-block;
     color: #ed4014;
 }
+.share-student{
+    right: 30px;
+    top: -4px;
+}
+.share-active{
+    display: inline-block;
+    color: #2d8cf0;
+}
 .rcd-item{
     cursor: pointer;
     display: flex;

+ 138 - 36
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue

@@ -61,9 +61,7 @@
                                         <span class="attr-label">{{$t('cusMgt.stuCount')}}</span>
                                         <span class="class-name">{{item.allStu ? item.allStu.length : 0}}{{$t('unit.text7')}}</span>
                                     </p>
-                                    <Icon size="25" custom="iconfont icon-qr-code" :class="['qr-code-icon', {'qr-code-icon-color': item.joinLock}]" @click="showQrCode(index)"
-                                            v-if="listType == 'private'" :title="$t('cusMgt.qrCodeLabel')"
-                                    />
+                                    <Icon size="25" custom="iconfont icon-qr-code" :class="['qr-code-icon', {'qr-code-icon-color': item.joinLock}]" @click="showQrCode(index)" v-if="listType == 'private'" :title="$t('cusMgt.qrCodeLabel')" />
                                 </div>
                                 <EmptyData v-if="teaClassList.length == 0" :top="160" :textContent="$t('cusMgt.noClassList')"></EmptyData>
                             </vuescroll>
@@ -97,15 +95,22 @@
                                 <Button icon="md-download" class="save-btn action-btn-wrap" style="margin-top:6px" @click="generateQrcodes" :loading="btnLoading">
                                     {{$t('schoolBaseInfo.exportQrCode')}}
                                 </Button>
-								<Button icon="md-download" class="save-btn action-btn-wrap" style="margin-top:6px" @click="generatePDF" :loading="pdfLoading">
-								    {{$t('schoolBaseInfo.exportList')}}
-								</Button>
+                                <Button icon="md-download" class="save-btn action-btn-wrap" style="margin-top:6px" @click="generatePDF" :loading="pdfLoading">
+                                    {{$t('schoolBaseInfo.exportList')}}
+                                </Button>
                             </div>
                             <!-- 课堂记录相关信息、操作 -->
-                            <div style="float:right;" v-show="tabName == 'record'">
-                                <span v-show="listType == 'private'" style="color:#ff9900;padding-top:5px;display:inline-block">
+                            <div style="float:right;padding-right:30px" v-show="tabName == 'record'">
+                                <!-- <span v-show="listType == 'private'" style="color:#ff9900;display:inline-block">
                                     {{$t('cusMgt.recordTips')}}
+                                </span> -->
+                                <span>
+                                    <Tooltip :max-width="180" :content="$t('cusMgt.autoShareTips')">
+                                        <Icon type="ios-information-circle-outline" />
+                                    </Tooltip>
+                                    {{$t('cusMgt.autoShare')}}
                                 </span>
+                                <i-switch :loading="sLoading" v-model="isAuto" size="small" @on-change="setAutoPublish" />
                             </div>
                             <span v-show="tabName == 'stus' && listType == 'school' && teaClassList[curClassIndex] && teaClassList[curClassIndex].classId" class="group-tips">{{$t('cusMgt.groupTips')}}</span>
                             <div style="float:right;" v-if="tabName == 'activity'">
@@ -159,15 +164,19 @@
                         <!-- 课堂记录 -->
                         <div v-show="tabName == 'record'" class="animated fadeIn class-record-wrap">
                             <vuescroll>
+                                <Alert v-show="listType == 'private'" show-icon type="warning" closable>
+                                    {{$t('cusMgt.recordTips')}}
+                                </Alert>
                                 <div class="rcd-item" v-for="(item,index) in curRecordList" :key="index" @click="toClassRecoerd(index)">
                                     <RcdPoster class="record-poster-wrap" :poster="item.poster"></RcdPoster>
                                     <div style="flex:1">
                                         <p class="record-name" style="padding-left:10px">
                                             {{item.name}}
-                                            <span style="float:right;margin-right:20px">
-                                                <Icon type="md-create" class="edit-ev-name" @click.stop="editRecordName(index)" :title="$t('cusMgt.edRdName')" />
-                                                <Icon type="md-trash" class="edit-ev-name" @click.stop="delRecord(item.id)" :title="$t('cusMgt.delRcd')" />
-                                                <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" :class="['edit-ev-name',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
+                                            <span class="item-icon-wrap">
+                                                <Icon type="md-create" class="common-item-icon ed-name" @click.stop="editRecordName(index)" :title="$t('cusMgt.edRdName')" />
+                                                <Icon type="md-trash" class="common-item-icon delete-item" @click.stop="delRecord(item.id)" :title="$t('cusMgt.delRcd')" />
+                                                <Icon :type="item.isShare ? 'ios-share-alt':'ios-share-alt-outline'" :size="20" :class="['common-item-icon','share-student',item.isShare ? 'share-active':'']" @click.stop="toggleShare(item)" :title="item.isShare ? $t('cusMgt.unShare') : $t('cusMgt.shareToStu')" />
+                                                <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" :class="['common-item-icon','heart-item',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
                                             </span>
                                         </p>
                                         <div style="padding-left:10px;margin-top:10px">
@@ -242,11 +251,11 @@
                                                 {{item.name}}
                                                 <span style="float:right;margin-right:20px">
                                                     <!-- 修改评测名称 -->
-                                                    <Icon v-show="item.owner === 'teacher'" type="md-create" class="edit-ev-name" @click.stop="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
+                                                    <Icon v-show="item.owner === 'teacher'" type="md-create" class="common-item-icon" @click.stop="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
                                                     <!-- 删除记录 -->
-                                                    <Icon v-show="item.owner === 'teacher'" type="md-trash" class="edit-ev-name" @click.stop="delEv(item)" :title="$t('cusMgt.delRcd')" />
+                                                    <Icon v-show="item.owner === 'teacher'" type="md-trash" class="common-item-icon" @click.stop="delEv(item)" :title="$t('cusMgt.delRcd')" />
                                                     <!-- 收藏 -->
-                                                    <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" :class="['edit-ev-name',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
+                                                    <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" :class="['common-item-icon',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
                                                 </span>
                                             </p>
                                             <span slot="avatar" style="margin-top:12px;display: inline-block;margin-left:10px;">
@@ -503,6 +512,8 @@ export default {
             }
         }
         return {
+            sLoading: false,
+            isAuto: false,//是否自动发布课堂记录
             fIds: [],//收藏列表ids
             qrConfig: {
                 title: this.$t('cusMgt.qrCodeLabel'),
@@ -516,7 +527,7 @@ export default {
             editNameStatus: false,
             viewIndex: -1,
             btnLoading: false,
-			pdfLoading:false,
+            pdfLoading: false,
             filterPeriod: '',
             editIrs: null,
             setIrsStatus: false,
@@ -699,6 +710,33 @@ export default {
         }
     },
     methods: {
+        //切换是否自动发布课堂记录
+        setAutoPublish() {
+            this.sLoading = true
+            let show = this.lessonShow
+            if (this.isAuto) {
+                show.push('student')
+            } else {
+                let index = show.findIndex(item => item === 'student')
+                if (index > -1) show.splice(index, 1)
+            }
+            let params = {
+                "opt": "UpdateLessonShow",
+                "lessonShow": show
+            }
+            this.$api.schoolUser.setTeacherInfo(params).then(
+                res => {
+                    this.$Message.success(this.$t('teachermgmt.setOk'))
+                    this.$store.commit('user/setLessonShow', show)
+                },
+                err => {
+                    this.$Message.error(this.$t('teachermgmt.setErr'))
+                    this.isAuto = !this.isAuto
+                }
+            ).finally(() => {
+                this.sLoading = false
+            })
+        },
         isFavorite(id) {
             return this.fIds.includes(id)
         },
@@ -717,6 +755,7 @@ export default {
                 }
             )
         },
+        //收藏 取消
         toggleFavorite(data) {
             if (data && data.id) {
                 if (this.isFavorite(data.id)) {
@@ -726,6 +765,53 @@ export default {
                 }
             }
         },
+        //分享、取消分享给学生
+        toggleShare(data) {
+            if (data && data.id) {
+                let show = []
+                if (!data.isShare) show = ['student']
+                this.$api.lessonRecord.updateLesson({
+                    "lesson_id": data.id,
+                    "tmdid": data.tmdid,
+                    "school": data.school,
+                    "scope": data.scope,
+                    "grant_types": [{
+                        "grant_type": "up-baseinfo",
+                        "data": {
+                            "show": show
+                        }
+                    }]
+                }).then(
+                    res => {
+                        if (!res.error) {
+                            if (data.isShare) {
+                                this.$Message.success(this.$t('cusMgt.unShareOk'))
+                            } else {
+                                this.$Message.success(this.$t('cusMgt.shareOk'))
+                            }
+                            let info = this.recordList.find(item => item.id == data.id)
+                            if (info) {
+                                info.show = show
+                                info.isShare = !info.isShare
+                            }
+                        } else {
+                            if (data.isShare) {
+                                this.$Message.error(this.$t('cusMgt.unShareErr'))
+                            } else {
+                                this.$Message.error(this.$t('cusMgt.shareErr'))
+                            }
+                        }
+                    },
+                    err => {
+                        if (data.isShare) {
+                            this.$Message.error(this.$t('cusMgt.unShareErr'))
+                        } else {
+                            this.$Message.error(this.$t('cusMgt.shareErr'))
+                        }
+                    }
+                )
+            }
+        },
         collection(data) {
             let params = {
                 favorite: {
@@ -899,7 +985,6 @@ export default {
         // 修改记录名称
         confirmEditRd() {
             if (this.editName) {
-                console.log(this.curRecordList[this.edRdIndex])
                 let recordInfo = this.curRecordList[this.edRdIndex]
                 this.btnLoading = true
                 this.$api.lessonRecord.updateLesson({
@@ -1138,21 +1223,21 @@ export default {
                 this.btnLoading = false
             })
         },
-		/* 快速生成名单清单 */
-		async generatePDF() {
-			this.pdfLoading = true
-			let listName = this.teaClassList[this.curClassIndex].listName || this.teaClassList[this.curClassIndex].classInfo.name
-			this.$tools.batchStuList(this.students, this.courseListShow[this.curCusIndex].name + ' - ' + listName).then(
-				res => {
-					this.$Message.success(this.$t('common.generatOk'))
-				},
-				err => {
-					this.$Message.error(this.$t('common.generateErr'))
-				}
-			).finally(() => {
-				this.pdfLoading = false
-			})
-		},
+        /* 快速生成名单清单 */
+        async generatePDF() {
+            this.pdfLoading = true
+            let listName = this.teaClassList[this.curClassIndex].listName || this.teaClassList[this.curClassIndex].classInfo.name
+            this.$tools.batchStuList(this.students, this.courseListShow[this.curCusIndex].name + ' - ' + listName).then(
+                res => {
+                    this.$Message.success(this.$t('common.generatOk'))
+                },
+                err => {
+                    this.$Message.error(this.$t('common.generateErr'))
+                }
+            ).finally(() => {
+                this.pdfLoading = false
+            })
+        },
         cancelSetNo() {
             this.editIrs = null
             this.editIndex = -1
@@ -2185,6 +2270,10 @@ export default {
                 }
                 this.$api.lessonRecord.getLessonList(params).then(
                     res => {
+                        res.lessonRecords.forEach(item => {
+                            item.show = item.show ? item.show : []
+                            item.isShare = item.show.includes('student')
+                        })
                         this.recordList = res.lessonRecords
                         let sasInfo = {}
                         let blobInfo = this.listType === 'school' ? this.$store.state.user.schoolProfile : this.$store.state.user.userProfile
@@ -2263,13 +2352,26 @@ export default {
                     this.tabClick(this.listType)
                 }
             }
+        },
+        lessonShow: {
+            deep: true,
+            immediate: true,
+            handler(n, o) {
+                console.log(typeof n)
+                if (n && Array.isArray(n)) {
+                    this.isAuto = n.includes('student')
+                } else {
+                    this.isAuto = false
+                }
+            }
         }
     },
     computed: {
         ...mapGetters({
             classList: 'user/getClasses', // 教室ID,
             schoolBase: 'user/getSchoolBase', // 学校基础设置
-            periods: 'user/getPeriods'
+            periods: 'user/getPeriods',
+            lessonShow: 'user/getTeacherLessonShow'//是否自动发布课堂记录
         }),
         //判断是否可以添加学生
         canAddStu() {
@@ -2453,12 +2555,12 @@ export default {
 }
 .class-record-wrap .ivu-list-item:hover {
     background: var(--active-item-start);
-    .edit-ev-name {
+    .common-item-icon {
         display: inline-block;
     }
 }
-.rcd-item:hover{
-    .edit-ev-name {
+.rcd-item:hover {
+    .common-item-icon {
         display: inline-block;
     }
 }

+ 1 - 1
TEAMModelOS/ClientApp/src/view/student-account/stuMgt/AddStudent.vue

@@ -282,7 +282,7 @@ export default {
         filterClasses() {
             var data = this.classes
             if (this.searchGrade > -1) {
-                let year = this.$jsFn.getYearByGrade(this.schoolBase, this.searchPeriod, this.searchGrade)
+                let year = this.$jsFn.getYearByGrade(this.searchGrade)
                 console.log(year)
                 data = data.filter((item) => {
                     return item.year == year && item.periodId == this.searchPeriod

+ 0 - 1
TEAMModelOS/ClientApp/src/view/teachermgmt/Index.less

@@ -10,7 +10,6 @@
         background-color: var(--body-bg);
         .tab-box {
             display: inline-block;
-            width: 30%;
             min-width: 303px;
             .pane{
                 margin-right: 40px;

+ 29 - 11
TEAMModelOS/ClientApp/src/view/teachermgmt/components/import/Import.vue

@@ -42,24 +42,35 @@
             </div>
             <div class="excel-data-wrap" v-else-if="viewStatus === 'review'">
                 <div class="import-info-wrap">
-                    <span>
+                    <!-- 无效数据 无Name -->
+                    <span style="color:#ed4014" v-show="allData.length - importData.length">
+                        {{$t('teachermgmt.impText')}}
+                    </span>
+                    <span class="count-value" style="color:#ed4014" v-show="allData.length - importData.length">
+                        {{allData.length - importData.length}}
+                    </span>
+                    <!-- 有效数据 -->
+                    <span style="color:#19be6b">
                         {{$t('teachermgmt.impText1')}}
                     </span>
-                    <span class="count-value">
-                        {{importData.length}}人
+                    <span class="count-value" style="color:#19be6b">
+                        {{importData.length}}
                     </span>
+                    <!-- 仅导入名字 -->
                     <span>
                         {{$t('teachermgmt.impText2')}}
                     </span>
                     <span class="count-value">
-                        {{onlyName.length}}
+                        {{onlyName.length}}
                     </span>
+                    <!-- 有ID 自动邀请 -->
                     <span>
                         {{$t('teachermgmt.impText3')}}
                     </span>
                     <span class="count-value">
-                        {{inviteData.length}}
+                        {{inviteData.length}}
                     </span>
+
                     <div class="imp-action-wrap">
                         <span @click="importAgain">
                             <Icon type="md-refresh" size="16" />
@@ -85,7 +96,7 @@
                     <Button type="primary" style="width:240px" size="large" @click="importAgain">
                         {{$t('teachermgmt.impText7')}}
                     </Button>
-                    <br/>
+                    <br />
                     <Button type="success" style="width:240px;margin-top:15px" size="large" @click="toMgt">
                         {{$t('teachermgmt.impText8')}}
                     </Button>
@@ -126,19 +137,24 @@ export default {
                     key: 'note'
                 }
             ],
-            importData: [],
+            importData: [],//可导入数据
+            allData: [],//所有数据
             onlyName: [],
             inviteData: [],
         }
     },
     methods: {
-        toMgt(){
+        toMgt() {
             this.$router.push({
-                name:'mgt'
+                name: 'mgt'
             })
         },
         //确认导入教师信息
         confirmImport() {
+            if(!this.importData.length){
+                this.$Message.warning(this.$t('teachermgmt.noIpmtData'))
+                return 
+            }
             let params = {
                 opt: 'upsert',
                 schoolId: this.$store.state.userInfo.schoolCode,
@@ -211,11 +227,12 @@ export default {
                 let flag = columns.includes('name') //name为必填
                 if (flag) {
                     // 处理表格导入数据类型
-                    results.forEach(item => {
+                    this.allData = results
+                    this.importData = this.allData.filter(item => !!item.name)
+                    this.importData.forEach(item => {
                         if (item.phone) item.phone = item.phone.toString()
                         if (item.tmdid) item.tmdid = item.tmdid.toString()
                     })
-                    this.importData = results
                     this.onlyName = this.importData.filter(item => !item.phone && !item.email && !item.id)
                     this.inviteData = this.importData.filter(item => item.phone || item.email || item.id)
                     this.$Message.info(this.$t('stuAccount.importTips11'))
@@ -291,6 +308,7 @@ export default {
 }
 .count-value {
     margin-right: 30px;
+    font-weight: 600;
 }
 .import-info-wrap {
     width: 100%;

+ 8 - 8
TEAMModelOS/ClientApp/src/view/teachermgmt/components/mgt/TeacherMgt.vue

@@ -4,17 +4,17 @@
         <div class="teacher-mgt-main">
             <div class="mgt-tools-wrap light-iview-form">
                 <!-- 状态筛选 -->
-                <Select v-model="filters.status" style="width:130px;margin-right:5px" clearable placeholder="状态筛选">
+                <Select v-model="filters.status" style="width:130px;margin-right:5px" clearable :placeholder="$t('teachermgmt.statusFilter')">
                     <Option v-for="item in statusFilters" :value="item.value" :key="item.value">{{ item.label }}</Option>
                 </Select>
                 <!-- 学科筛选 -->
                 <Cascader :data="subjectData" v-model="filters.subject" :placeholder="$t('teachermgmt.subjectFilter')" style="width:130px;margin-right:5px;display: inline-block;"></Cascader>
                 <!-- 职称筛选 -->
-                <Select v-model="filters.job" style="width:130px;margin-right:5px" clearable placeholder="职称筛选">
+                <Select v-model="filters.job" style="width:130px;margin-right:5px" clearable :placeholder="$t('teachermgmt.jobFilter')">
                     <Option v-for="item in jobs" :value="item" :key="item">{{ item }}</Option>
                 </Select>
                 <!-- 权限筛选 -->
-                <Select v-model="filters.auth" style="width:130px;margin-right:5px" clearable placeholder="权限筛选">
+                <Select v-model="filters.auth" style="width:130px;margin-right:5px" clearable :placeholder="$t('teachermgmt.authFilter')">
                     <Option v-for="item in authFilter" :value="item.value" :key="item.value">{{ item.label }}</Option>
                 </Select>
                 <!-- 关键字搜索 -->
@@ -64,9 +64,9 @@
                             </span>
                         </template>
                         <template slot-scope="{ row }" slot="action" v-if="!activePanel">
-                            <icon v-show="!row.roles.includes('admin') && row.status == 'join'" icon="shield-alt" style="font-size: 13px; color: var(--normal-icon-color); margin-right: 20px; cursor: pointer;" @click="openPanel('single',row)" />
-                            <Icon v-show="!row.roles.includes('admin')" size="16" type="md-trash" style="color: var(--normal-icon-color); cursor: pointer" @click="removeUser(row)" />
-                            <Icon v-show="row.roles.includes('admin') && row.id == $store.state.userInfo.TEAMModelId && row.status == 'join'" type="md-repeat" style="color: var(--normal-icon-color); font-size: 14px; cursor: pointer" @click="transferAdmin(row)" />
+                            <icon v-show="row.roles && !row.roles.includes('admin') && row.status == 'join'" icon="shield-alt" style="font-size: 13px; color: var(--normal-icon-color); margin-right: 20px; cursor: pointer;" @click="openPanel('single',row)" />
+                            <Icon v-show="row.roles && !row.roles.includes('admin')" size="16" type="md-trash" style="color: var(--normal-icon-color); cursor: pointer" @click="removeUser(row)" />
+                            <Icon v-show="row.roles && row.roles.includes('admin') && row.id == $store.state.userInfo.TEAMModelId && row.status == 'join'" type="md-repeat" style="color: var(--normal-icon-color); font-size: 14px; cursor: pointer" @click="transferAdmin(row)" />
                         </template>
                         <!---手動輸入空間欄位-->
                         <template slot-scope="{ row }" slot="spaceShare">
@@ -1066,12 +1066,12 @@ export default {
                 this.$Modal.confirm({
                     title: this.$t('teachermgmt.model.delTeacher.title'),
                     // content: '<p>' + this.$t('teachermgmt.model.delTeacher.text1') + ' ' + val.name + '(' + val.id + ') ?</p>',
-                    content: `<p> ${this.$t('teachermgmt.model.delTeacher.text1')}  ${val.name} ${idText}?</p>`,
+                    content: `<p> ${this.$t('teachermgmt.model.delTeacher.text1')}  ${val.name || val.iname} ${idText}?</p>`,
                     onOk: () => {
                         this.$api.schoolUser.rmvSchoolUser({
                             school_code: this.$store.state.userInfo.schoolCode,
                             id: val.id || undefined,
-                            name: val.id ? undefined : val.name
+                            name: val.id ? undefined : val.iname || val.name
                         }).then(
                             res => {
                                 this.$store.commit('user/delTeacher', [val.id || val.name])

+ 69 - 8
TEAMModelOS/Controllers/Common/ExamController.cs

@@ -420,8 +420,8 @@ namespace TEAMModelOS.Controllers
         /// <param name="request"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
-        /*[Authorize(Roles = "IES")]
-        [AuthToken(Roles = "teacher,admin")]*/
+        [Authorize(Roles = "IES")]
+        [AuthToken(Roles = "teacher,admin")]
         [HttpPost("find")]
         public async Task<IActionResult> Find(JsonElement requert)
         {
@@ -466,7 +466,7 @@ namespace TEAMModelOS.Controllers
                     stringBuilder.Append($" and c.source = '{source}' ");
                 }
                 stringBuilder.Append("order by c.createTime desc");
-                string continuationToken = string.Empty;
+                //string token = null;
                 string token = default;
                 //默认不指定返回大小
                 int? topcout = null;
@@ -486,10 +486,9 @@ namespace TEAMModelOS.Controllers
                 //如果指定了返回大小
                 if (requert.TryGetProperty("token", out JsonElement token_1))
                 {
-                    //指定了cancellationToken continuationSchool
                     if (!token_1.ValueKind.Equals(JsonValueKind.Null) && token_1.ValueKind.Equals(JsonValueKind.String))
                     {
-                        continuationToken = token_1.GetString();
+                        token = token_1.GetString();
 
                     }
                 }
@@ -508,12 +507,12 @@ namespace TEAMModelOS.Controllers
                     }
                     if (iscontinuation)
                     {
-                        continuationToken = item.GetContinuationToken();
+                        token = item.GetContinuationToken();
                         break;
                     }
 
                 }
-                return Ok(new { examInfo, token = continuationToken });
+                return Ok(new { examInfo, token = token });
             }
             catch (Exception e)
             {
@@ -1612,6 +1611,12 @@ namespace TEAMModelOS.Controllers
                         }
                     }
                 }
+                //查询结果
+                List<ExamResult> results = new();
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamResult>(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamResult-{id}") }))
+                {
+                    results.Add(item);
+                }
                 List<List<string>> stuAns = new();
                 List<List<double>> stuScore = new();
                 List<List<List<Details>>> mark = new();
@@ -1647,12 +1652,22 @@ namespace TEAMModelOS.Controllers
                     know = s.know;
                     fp = s.filed;
                 }
+                List<List<double>> wno = new();
+                foreach (ExamResult exam in results) {
+                    int num = 0;
+                    //确定当前循环科目索引位置
+                    int index = subId.IndexOf(exam.subjectId);
+                    //根据索引找到试卷分数
+                    List<double> points = papers[index].point;
+                    List<double> wn = await getWrongNum(exam, points);
+                    wno.Add(wn);
+                }
                 if (papers.IsNotEmpty())
                 {
                     var knowledge = know.Select(k => new { k.kn, k.kps, k.ckps, k.akps });
                     var filed = fp.Select(k => new { k.fs, k.fps, k.cfps, k.afps });
                     //papers = papers
-                    return Ok(new { papers, subjects, stuScore, stuAns, mark, total, claId = infoIds, knowledge, filed, average, status = 200 });
+                    return Ok(new { papers, subjects, stuScore, stuAns, mark, total, claId = infoIds, knowledge, filed, average, wno, status = 200 });
                 }
                 else
                 {
@@ -3494,6 +3509,52 @@ namespace TEAMModelOS.Controllers
             }
             return (ansBlob, scores);
         }
+
+        private Task<List<double>> getWrongNum(ExamResult result, List<double> points)
+        {
+            int num = 0;
+            List<double> wn = new List<double>();
+            foreach (var point in points)
+            {
+                int wnum = 0;
+                double p = point * 0.8;
+                foreach (ClassRange range in result.classes)
+                {
+                    for (int i = range.range[0]; i <= range.range[1]; i++)
+                    {
+                        //判断推送的数据中,学生正常得分数据
+                        if (result.studentScores[i].Count > 0)
+                        {
+                            if (result.studentScores[i][num] < point)
+                            {
+                                if (result.studentScores[i][num] < p)
+                                {
+                                    wnum++;
+                                }
+                                else
+                                {
+                                    continue;
+                                }
+                            }
+                            else
+                            {
+                                continue;
+                            }
+                        }
+                        else
+                        {
+                            wnum++;
+                        }
+
+
+                    }
+                }
+                wn.Add(wnum);
+                num++;
+            }
+            return Task.FromResult(wn);
+        }
+
     }
     public class stus
     {

+ 72 - 110
TEAMModelOS/Controllers/School/SchoolController.cs

@@ -26,6 +26,7 @@ using Microsoft.AspNetCore.Authorization;
 using System.Net.Http.Headers;
 using System.Net.Http.Json;
 using HTEXLib.COMM.Helpers;
+using TEAMModelOS.SDK.Models.Service;
 
 namespace TEAMModelOS.Controllers
 {
@@ -47,7 +48,8 @@ namespace TEAMModelOS.Controllers
         private readonly int redisAclassoneDbNum = 8; //AclassOne Redis DB號
         private readonly IConfiguration _configuration;
         private readonly CoreAPIHttpService _coreAPIHttpService;
-        public SchoolController(CoreAPIHttpService coreAPIHttpService,AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration)
+        private readonly NotificationService _notificationService;
+        public SchoolController(CoreAPIHttpService coreAPIHttpService, NotificationService notificationService, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration)
         {
             _azureCosmos = azureCosmos;
             _azureStorage = azureStorage;
@@ -56,6 +58,7 @@ namespace TEAMModelOS.Controllers
             _option = option?.Value;
             _configuration = configuration;
             _coreAPIHttpService = coreAPIHttpService;
+            _notificationService = notificationService;
         }
         /// <summary>
         /// 修改学校信息
@@ -1542,6 +1545,7 @@ namespace TEAMModelOS.Controllers
         [Authorize(Roles = "IES")]
         [AuthToken(Roles = "admin,teacher")]
         public async Task<IActionResult> TeacherImportManage(JsonElement request) {
+          (string adminId,string adminName,string pic ,string schoolId)=  HttpContext.GetAuthTokenInfo();
             if (!request.TryGetProperty("opt", out JsonElement _opt)) { return BadRequest(); }
             if (!request.TryGetProperty("schoolId", out JsonElement _schoolId)) { return BadRequest(); }
             long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
@@ -1567,7 +1571,6 @@ namespace TEAMModelOS.Controllers
                     {
                         keys.AddRange(emails);
                     }
-                   
                     teachers.ForEach(x => { x.status = "import";x.time = now;x.iname = x.name;x.name = null; });
                     if (keys.Any()) {
                         try
@@ -1592,10 +1595,12 @@ namespace TEAMModelOS.Controllers
                         {
                             idsInSchool.Add(item);
                         }
+
                     }
+                    List<string> inviteids = new List<string>();
+                    School schoolBase = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>($"{_schoolId}", new PartitionKey("Base"));
                     if (coreUsers.Any())
                     {
-                        School schoolBase = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>($"{_schoolId}", new PartitionKey("Base"));
                         foreach (var t in teachers) {
                             if (!string.IsNullOrWhiteSpace(t.tmdid))
                             {
@@ -1682,6 +1687,7 @@ namespace TEAMModelOS.Controllers
                                         pk= "Teacher",
                                         code=$"Teacher-{_schoolId}"
                                     };
+                                    inviteids.Add(t.id);
                                     await  _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(teacher, new PartitionKey (teacher.code));
                                     Azure.Response responseTeacher = await  _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemStreamAsync(t.id, new PartitionKey("Base"));
                                     if (responseTeacher.Status == 200)
@@ -1705,131 +1711,87 @@ namespace TEAMModelOS.Controllers
                                         } };
                                         await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).CreateItemAsync(teacherBase, new PartitionKey("Base"));
                                     }
+
                                 }
                             }
                         }
                     }
-                    teacherImport = new TeacherImport {id = $"{_schoolId}", code = "TeacherImport", pk = "TeacherImport", teachers=teachers};
-                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).UpsertItemAsync(teacherImport, new PartitionKey("TeacherImport"));
-                    break;
-                    /*
-                case "find":
-                    Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync($"{_schoolId}", new PartitionKey("TeacherImport"));
+
+                    Azure .Response response=  await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync($"{_schoolId}", new PartitionKey("TeacherImport"));
                     if (response.Status == 200)
                     {
-                        teacherImport = JsonDocument.Parse(response.Content).RootElement.ToObject<TeacherImport>();
-                        var idsIn = teacherImport.teachers.Where(x => !string.IsNullOrWhiteSpace(x.id));
-                        //id是空 其他不是空的
-                        var tmdidsi = teacherImport.teachers.Where(x => string.IsNullOrWhiteSpace(x.id) && !string.IsNullOrWhiteSpace(x.tmdid)).Select(z => z.tmdid);
-                        var phonesi = teacherImport.teachers.Where(x => string.IsNullOrWhiteSpace(x.id) && !string.IsNullOrWhiteSpace(x.phone)).Select(z => z.phone);
-                        var emailsi = teacherImport.teachers.Where(x => string.IsNullOrWhiteSpace(x.id) && !string.IsNullOrWhiteSpace(x.email)).Select(z => z.email);
-                        List<string> skeys = new List<string>();
-                        if (tmdidsi.Any())
-                        {
-                            skeys.AddRange(tmdidsi);
-                        }
-                        if (phonesi.Any())
-                        {
-                            skeys.AddRange(phonesi);
-                        }
-                        if (emailsi.Any())
-                        {
-                            skeys.AddRange(emailsi);
-                        }
-                        if (idsIn.Any())
-                        {
-                            skeys.AddRange(idsIn.Select(x=>x.id));
-                            string sqlInSchool = $"select c.id,c.status from c where c.id in ({string.Join(",", idsIn.Select(x => $"'{x.id}'"))}) ";
-                            await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
-                                .GetItemQueryIterator<SchoolTeacher>(queryText: sqlInSchool, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Teacher-{_schoolId}") }))
-                            {
-                                idsInSchool.Add(item);
-                            }
-                        }
-                        if (skeys.Any())
+                        teacherImport = JsonDocument.Parse(response.Content).RootElement.Deserialize<TeacherImport>();
+                        if (teacherImport != null && teacherImport.teachers.Any())
                         {
-                            try {
-                                var content = new StringContent(skeys.ToJsonString(), Encoding.UTF8, "application/json");
-                                string json = await _coreAPIHttpService.GetUserInfos(content);
-                                if (!string.IsNullOrWhiteSpace(json))
+                            teachers.ForEach(x => {
+                                ImportTeacher tch = null;
+                                if (string.IsNullOrWhiteSpace(x.id))
                                 {
-                                    coreUsers = json.ToObject<List<CoreUser>>();
-                                }
-                            } catch (Exception ex) {
-                                //await _dingDing.SendBotMsg($"{_option.Location},导入名单时,查验key信息错误{ex.Message}\n{ex.StackTrace}\n{skeys.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
-                            }
-                        }
-                        if (coreUsers.Any()) {
-                            teacherImport.teachers.ForEach(t => {
-                                if (!string.IsNullOrWhiteSpace(t.id))
-                                {
-                                    CoreUser coreUser = coreUsers.Find(x => x.searchKey.Equals(t.id) || x.id.Equals(t.id));
-                                    if (coreUser != null)
-                                    {
-                                        t.id = coreUser.id;
-                                        t.picture = coreUser.picture;
-                                    }
-                                    else
-                                    {
-                                        t.id = null;
-                                    }
+                                    tch = teacherImport.teachers.Find(t => t.iname.Equals(x.iname));
                                 }
-                                if (string.IsNullOrWhiteSpace(t.id)) {
-                                    if (!string.IsNullOrWhiteSpace(t.tmdid))
-                                    {
-                                        CoreUser coreUser = coreUsers.Find(x => x.id.Equals(t.tmdid));
-                                        if (coreUser != null)
-                                        {
-                                            t.id = coreUser.id;
-                                            t.picture = coreUser.picture;
-                                        }
-                                    }
-                                    if (string.IsNullOrWhiteSpace(t.id))
-                                    {
-                                        if (!string.IsNullOrWhiteSpace(t.phone))
-                                        {
-                                            CoreUser coreUser = coreUsers.Find(x => x.mobile.Equals(t.phone));
-                                            if (coreUser != null)
-                                            {
-                                                t.id = coreUser.id;
-                                                t.picture = coreUser.picture;
-                                            }
-                                        }
-                                    }
-                                    if (string.IsNullOrWhiteSpace(t.id))
-                                    {
-                                        if (!string.IsNullOrWhiteSpace(t.email))
-                                        {
-                                            CoreUser coreUser = coreUsers.Find(x => x.mail.Equals(t.email));
-                                            if (coreUser != null)
-                                            {
-                                                t.id = coreUser.id;
-                                                t.picture = coreUser.picture;
-                                            }
-                                        }
-                                    }
+                                else {
+                                    tch = teacherImport.teachers.Find(t => t.id.Equals(x.id));
                                 }
-                                
-                                if (!string.IsNullOrWhiteSpace(t.id))
+                                if (tch != null)
                                 {
-                                    SchoolTeacher teacher = idsInSchool.Find(x => x.id.Equals(t.id));
-                                    if (teacher != null)
-                                    {
-                                        t.status = teacher.status;
-                                    }
-                                    else
-                                    {
-                                        t.status = "import";
-                                    }
+                                    tch.time = now;
+                                    tch.status = x.status;
+                                    tch.name = x.name;
+                                    tch.iname = x.iname;
+                                    tch.picture = x.picture;
+                                    tch.phone = x.phone;
+                                    tch.tmdid = x.tmdid;
+                                    tch.email = x.email;
+                                    tch.note = x.note;
+                                    tch.id=x.id;
+                                }
+                                else {
+                                    teacherImport.teachers.Add(new ImportTeacher {
+                                        time = now,
+                                        status = x.status,
+                                        name = x.name,
+                                        iname = x.iname,
+                                        picture = x.picture,
+                                        phone = x.phone,
+                                        tmdid = x.tmdid,
+                                        email = x.email,
+                                        note = x.note,
+                                        id = x.id
+                                    });
                                 }
                             });
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(teacherImport, $"{_schoolId}", new PartitionKey("TeacherImport"));
+                        }
+                        else {
+                            teacherImport = new TeacherImport { id = $"{_schoolId}", code = "TeacherImport", pk = "TeacherImport", teachers = teachers };
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(teacherImport,$"{_schoolId}", new PartitionKey("TeacherImport"));
                         }
                     }
                     else {
-                        teacherImport= new TeacherImport { id=$"{_schoolId}",code= "TeacherImport",pk= "TeacherImport",teachers= new List<ImportTeacher>() };
+                        teacherImport = new TeacherImport { id = $"{_schoolId}", code = "TeacherImport", pk = "TeacherImport", teachers = teachers };
+                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(teacherImport, new PartitionKey("TeacherImport"));
+                    }
+
+                   
+                    if (inviteids.Any()) {
+                        string bizcode = "invite";
+                        Notification notification = new Notification
+                        {
+                            hubName = "hita",
+                            type = "msg",
+                            from = $"ies5:{_option.Location}:private",
+                            to = inviteids.Select(x => x).ToList(),
+                            label = $"{bizcode}_school",
+                            body = new { location = _option.Location, biz = bizcode, tmdid = adminId, tmdname = adminName, schoolcode = $"{_schoolId}", schoolname = $"{schoolBase.name}", status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
+                            expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
+                        };
+                        var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
+                        var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                        var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
+                        var location = _option.Location;
+                        var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
                     }
                     break;
-                    */
             }
             return Ok(new { teacherImport });
         

+ 2 - 2
TEAMModelOS/Controllers/System/BlobController.cs

@@ -181,9 +181,9 @@ namespace TEAMModelOS.Controllers
             try
             {
                 //学校已经分配给所有教师的空间大小GB。
-                long teach = 0;
+                long teach = 0; 
                 request.TryGetProperty("scope", out JsonElement _scope);
-                request.TryGetProperty("containerName", out JsonElement containerName);
+                if (!request.TryGetProperty("containerName", out JsonElement containerName)) return BadRequest() ;
                 if (_scope.ValueKind.Equals(JsonValueKind.String) && _scope.GetString().Equals("school")) {
                     var client = _azureCosmos.GetCosmosClient();
                     await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: $"SELECT sum(c.size) as size FROM c ",

+ 62 - 10
TEAMModelOS/Controllers/Teacher/InitController.cs

@@ -130,7 +130,17 @@ namespace TEAMModelOS.Controllers
                         {
                             return BadRequest(new { status = -1, msg = "您未加入该学校!" });
                         }
-                        //设置教师的科目信息
+                    //修改教师的最大课例保存数量
+                    case bool when $"{_opt}".Equals("UpdateLessonLimit", StringComparison.OrdinalIgnoreCase) && (request.TryGetProperty("lessonLimit", out JsonElement _lessonLimit)):
+                        teacher.lessonLimit = int.Parse($"{_lessonLimit}");
+                        await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, userid, new PartitionKey("Base"));
+                        return Ok(new { teacher, status = 1 });
+                    //修改教师设置自动将课例发布给谁的设置
+                    case bool when $"{_opt}".Equals("UpdateLessonShow", StringComparison.OrdinalIgnoreCase) && (request.TryGetProperty("lessonShow", out JsonElement _lessonShow)):
+                        teacher.lessonShow = _lessonShow.Deserialize<List<string>>();
+                        await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, userid, new PartitionKey("Base"));
+                        return Ok(new { teacher, status = 1 });
+                    //设置教师的科目信息
                     case bool when $"{_opt}".Equals("SetTeacherSubject", StringComparison.OrdinalIgnoreCase) && request.TryGetProperty("targerTecher", out JsonElement _targetTecher) 
                         && request.TryGetProperty("subjectIds", out JsonElement _subjectIds):
                         if (_subjectIds.ValueKind.Equals(JsonValueKind.Array))
@@ -252,12 +262,21 @@ namespace TEAMModelOS.Controllers
                 TeacherInfo teacherInfo= await TeacherService.TeacherInfo(_azureCosmos, teacher, $"{name}", $"{picture}", id, _azureStorage, _option);
                 teacherInfo.areas.ForEach(x => { if (x.setting != null) { x.setting.accessConfig=x.setting.accessConfig; } });
                 LoginLog(id, $"{name}", 200);
+                int lessonLimit = teacherInfo.teacher.lessonLimit;
+                if (teacherInfo.teacher.lessonLimit == 0)
+                {
+                    //未设置的的采用系统设置的默认值30
+                    lessonLimit = Constant.private_lesson_limit;
+                }
                 return Ok(new { location = _option.Location, teacherInfo. auth_token, teacherInfo. blob_uri, teacherInfo.blob_sas, teacherInfo.schools, teacherInfo.defaultschool, teacherInfo. courses,
                     teacherInfo.total,
                     teacherInfo.osblob_uri,
                     teacherInfo.osblob_sas,
                     teacherInfo.tsize, status = 200,
-                    teacherInfo. areas });
+                    teacherInfo. areas ,
+                    lessonLimit,
+                    teacherInfo.teacher.lessonShow
+                });
             }
             catch (CosmosException ex)
             {
@@ -550,10 +569,19 @@ namespace TEAMModelOS.Controllers
                 ///https://teammodelstorage.blob.core.chinacloudapi.cn/teammodelos
                 var (osblob_uri, osblob_sas) = roles.Contains("area") ? _azureStorage.GetBlobContainerSAS("teammodelos", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete) : _azureStorage.GetBlobContainerSAS("teammodelos", BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
                 areas.ForEach(x => { { if (x.setting != null) { x.setting.accessConfig = x.setting.accessConfig; } } });
+
+                int lessonLimit =teacher.lessonLimit;
+                if (teacher.lessonLimit == 0)
+                {
+                    //未设置的的采用系统设置的默认值30
+                    lessonLimit = Constant.private_lesson_limit;
+                }
                 return Ok(new { auth_token, blob_uri, blob_sas, school_base, 
                     school_courses,  school_classes, school_rooms, size, 
                     osblob_uri, osblob_sas, status = 200, areas , currArea , 
-                    productSum= new {
+                    lessonLimit,
+                    teacher.lessonShow,
+                    productSum = new {
                         serial = serials,
                         service= services
                     } });
@@ -764,7 +792,16 @@ namespace TEAMModelOS.Controllers
                     }
                     await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, id, new PartitionKey("Base"));
                     var sresponse = await client.GetContainer(Constant.TEAMModelOS, "School").DeleteItemStreamAsync(id, new PartitionKey($"Teacher-{school_code}"));
-                    //await TmdUserService.LeaveSchool(client, teacher.id, school.schoolId);
+
+                    Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync($"{school_code}", new PartitionKey("TeacherImport"));
+                    TeacherImport teacherImport = null;
+                    if (response.Status == 200)
+                    {
+                        teacherImport = JsonDocument.Parse(response.Content).RootElement.Deserialize<TeacherImport>();
+                        var tchs = teacherImport?.teachers?.RemoveAll(x => !string.IsNullOrWhiteSpace(x.id)  && x.id.Equals(id));
+                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(teacherImport, $"{school_code}", new PartitionKey("TeacherImport"));
+                    }
+
                     return Ok(new { stauts = 1 });
                 }
                 else
@@ -820,13 +857,14 @@ namespace TEAMModelOS.Controllers
                         };
                         var response = await client.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync(st, new PartitionKey($"Teacher-{school_code}"));
                     }
+                    Azure.Response responseImport = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync($"{school_code}", new PartitionKey("TeacherImport"));
+                    TeacherImport teacherImport = null;
                     if ($"{grant_type}".Equals("request")) {
-                        Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync($"{school_code}", new PartitionKey("TeacherImport"));
-                        TeacherImport teacherImport = null;
-                        if (response.Status == 200)
+                       
+                        if (responseImport.Status == 200)
                         {
-                            teacherImport = JsonDocument.Parse(response.Content).RootElement.Deserialize<TeacherImport>();
-                            var tchs = teacherImport.teachers.FindAll(x => x.iname.Equals($"{name}") && string.IsNullOrWhiteSpace(x.id));
+                            teacherImport = JsonDocument.Parse(responseImport.Content).RootElement.Deserialize<TeacherImport>();
+                            var tchs = teacherImport?.teachers?.FindAll(x =>  string.IsNullOrWhiteSpace(x.iname) && x.iname.Equals($"{name}") && string.IsNullOrWhiteSpace(x.id));
                             if (tchs.IsNotEmpty())
                             {
                                 var tch  = tchs[0];
@@ -855,7 +893,21 @@ namespace TEAMModelOS.Controllers
                     }
                     if (grant_type.ToString().Equals("join"))
                     {
-                        await TmdUserService.JoinSchool(client, teacher.id, teacher.picture, teacher.name, school.schoolId, school.name);
+                        if (responseImport.Status == 200)
+                        {
+                            teacherImport = JsonDocument.Parse(responseImport.Content).RootElement.Deserialize<TeacherImport>();
+                            teacherImport?.teachers.ForEach(x => {
+                                if (x.id.Equals(teacher.id)) { 
+                                    x.name=teacher.name;
+                                    x.status = "join";
+                                    x.time=DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                                    x.picture=teacher.picture;
+                                }
+                            });
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(teacherImport, $"{school_code}", new PartitionKey("TeacherImport"));
+                            await TmdUserService.JoinSchool(client, teacher.id, teacher.picture, teacher.name, school.schoolId, school.name);
+                        }
+                            
                     }
                     Notification notification = null;
 

+ 1 - 1
TEAMModelOS/Controllers/XTest/FixDataController.cs

@@ -2264,7 +2264,7 @@ namespace TEAMModelOS.Controllers
             }
             return students;
         }
-
+     
 
         public record CorrectStu
         {

+ 29 - 0
TEAMModelOS/Controllers/XTest/TestController.cs

@@ -701,6 +701,35 @@ namespace TEAMModelOS.Controllers
             }
             return Ok(new { data });
         }
+
+
+        [HttpPost("test-blob-folder")]
+        public async Task<IActionResult> TestBlobFolder(JsonElement json)
+        {
+            var client =  _azureStorage.GetBlobContainerClient("1595321354") ;
+            List<BlobItem> blobItems = new List<BlobItem>();
+            HashSet<string> ids = new HashSet<string>();
+            string path = $"records";
+            await foreach (BlobItem item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, path)) {
+                var p=   item.Name.Split("/");
+                if (p.Length > 2) {
+                    ids.Add(p[1]);
+                }
+            }
+            List<string> lessonIds = new List<string>();
+            string sql = "select value(c.id) from c ";
+            await foreach(var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
+                .GetItemQueryIterator<string>(queryText:sql ,requestOptions:new QueryRequestOptions { PartitionKey= new PartitionKey("LessonRecord-1595321354") }))
+            {
+                lessonIds.Add(item);
+            }
+            var notdata =  ids.Except(lessonIds);
+            var notblob = lessonIds.Except(ids).ToList() ;
+            List<string> paths = notdata.Select(x => $"records/{x}").ToList() ;
+            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).DeleteItemsStreamAsync(notblob, "LessonRecord-1595321354");
+            await _azureStorage.GetBlobServiceClient().DeleteBlobs(_dingDing, "1595321354", paths);
+            return Ok(new { lessonIds , ids , notdata, notblob });
+        }
     }
 
 }

+ 3 - 3
TEAMModelOS/TEAMModelOS.csproj

@@ -32,9 +32,9 @@
     <SpaRoot>ClientApp\</SpaRoot>
     <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
     <UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-    <Version>5.2204.15</Version>
-    <AssemblyVersion>5.2204.15.1</AssemblyVersion>
-    <FileVersion>5.2204.15.1</FileVersion>
+    <Version>5.2204.18</Version>
+    <AssemblyVersion>5.2204.18.1</AssemblyVersion>
+    <FileVersion>5.2204.18.1</FileVersion>
     <Description>TEAMModelOS(IES5)</Description>
     <PackageReleaseNotes>6.0版本说明</PackageReleaseNotes>
     <PackageId>TEAMModelOS</PackageId>