Selaa lähdekoodia

Merge branch 'TPE/develop' into TPE/feat/classmgmtToHiteach

osbert 4 vuotta sitten
vanhempi
commit
ce1d25224f
85 muutettua tiedostoa jossa 2766 lisäystä ja 1073 poistoa
  1. 27 6
      TEAMModelFunction/ExamTrigger.cs
  2. 33 1
      TEAMModelFunction/MonitorServicesBus.cs
  3. 1 0
      TEAMModelFunction/Startup.cs
  4. 1 0
      TEAMModelFunction/TEAMModelFunction.csproj
  5. 1 0
      TEAMModelFunction/local.settings.json
  6. 68 1
      TEAMModelOS.SDK/DI/AzureStorage/AzureStorageBlobExtensions.cs
  7. 1 1
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Repair.cs
  8. 4 4
      TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs
  9. 72 0
      TEAMModelOS.SDK/Models/Cosmos/School/Knowledge.cs
  10. 8 0
      TEAMModelOS/ClientApp/src/api/learnActivity.js
  11. 4 0
      TEAMModelOS/ClientApp/src/api/stuAccount.js
  12. 12 2
      TEAMModelOS/ClientApp/src/api/studentWeb.js
  13. 8 7
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css
  14. 355 329
      TEAMModelOS/ClientApp/src/common/BaseCanvas.vue
  15. 24 1
      TEAMModelOS/ClientApp/src/common/BaseMyCanvas.vue
  16. 2 2
      TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.vue
  17. 0 9
      TEAMModelOS/ClientApp/src/components/selflearn/NewChooseContent.vue
  18. 216 133
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue
  19. 85 28
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReportCharts/StudentScore.vue
  20. 1 1
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperView.vue
  21. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/learnActivity.js
  22. 6 2
      TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolBaseInfo.js
  23. 14 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/studentWeb.js
  24. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/evaluation.js
  25. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/learnActivity.js
  26. 6 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/schoolBaseInfo.js
  27. 38 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/settings.js
  28. 14 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/studentWeb.js
  29. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/evaluation.js
  30. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/learnActivity.js
  31. 6 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/schoolBaseInfo.js
  32. 38 3
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/settings.js
  33. 14 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/studentWeb.js
  34. 2 0
      TEAMModelOS/ClientApp/src/static/Global.js
  35. 0 4
      TEAMModelOS/ClientApp/src/utils/blobTool.js
  36. 5 2
      TEAMModelOS/ClientApp/src/utils/evTools.js
  37. 2 2
      TEAMModelOS/ClientApp/src/utils/public.js
  38. 2 2
      TEAMModelOS/ClientApp/src/view/evaluation/bank/ExerciseList.vue
  39. 2 2
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseChild.vue
  40. 9 5
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseCreateChild.vue
  41. 9 5
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseEditExercise.vue
  42. 6 2
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseExerciseList.vue
  43. 12 26
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseImport.vue
  44. 5 8
      TEAMModelOS/ClientApp/src/view/evaluation/components/BasePointPie.vue
  45. 194 57
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseRepair.vue
  46. 8 4
      TEAMModelOS/ClientApp/src/view/evaluation/index/CreateExercises.vue
  47. 6 7
      TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue
  48. 3 3
      TEAMModelOS/ClientApp/src/view/learnactivity/CreatePrivEva.vue
  49. 15 17
      TEAMModelOS/ClientApp/src/view/learnactivity/CreateSchoolEva.vue
  50. 6 0
      TEAMModelOS/ClientApp/src/view/learnactivity/MgtPrivEva.less
  51. 66 4
      TEAMModelOS/ClientApp/src/view/learnactivity/MgtPrivEva.vue
  52. 12 16
      TEAMModelOS/ClientApp/src/view/learnactivity/MgtSchoolEva.vue
  53. 1 0
      TEAMModelOS/ClientApp/src/view/learnactivity/PaperScore.less
  54. 13 12
      TEAMModelOS/ClientApp/src/view/learnactivity/PaperScore.vue
  55. 5 0
      TEAMModelOS/ClientApp/src/view/learnactivity/Scoring.less
  56. 198 55
      TEAMModelOS/ClientApp/src/view/learnactivity/Scoring.vue
  57. 156 23
      TEAMModelOS/ClientApp/src/view/learnactivity/SimpleAnalysis.vue
  58. 88 98
      TEAMModelOS/ClientApp/src/view/learnactivity/echarts/AvgCompare.vue
  59. 5 45
      TEAMModelOS/ClientApp/src/view/learnactivity/echarts/ScoreMatrix.vue
  60. 6 0
      TEAMModelOS/ClientApp/src/view/schoolmgmt/ClassroomSetting/ClassroomSetting.less
  61. 117 35
      TEAMModelOS/ClientApp/src/view/schoolmgmt/ClassroomSetting/ClassroomSetting.vue
  62. 9 11
      TEAMModelOS/ClientApp/src/view/settings/Index.vue
  63. 31 35
      TEAMModelOS/ClientApp/src/view/settings/SchoolMgmt.vue
  64. 1 1
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/AchievementAnalysis/AchievementAnalysis.vue
  65. 1 3
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/EvaluationList/TotalIndex.vue
  66. 1 0
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/KnowledgeAnalysis/KnowledgeAnalysis.vue
  67. 1 0
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/LevelAnalysis/LevelAnalysis.vue
  68. 2 0
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/ScatterAnalysis/ScatterAnalysis.vue
  69. 1 1
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/QuestionList.css
  70. 25 11
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/QuestionList.vue
  71. 1 1
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/TestAnalysis.vue
  72. 1 6
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/index.vue
  73. 0 1
      TEAMModelOS/ClientApp/src/view/teachcontent/index.vue
  74. 220 0
      TEAMModelOS/Controllers/Analysis/AchievementController.cs
  75. 210 6
      TEAMModelOS/Controllers/Analysis/AnalysisController.cs
  76. 50 9
      TEAMModelOS/Controllers/Client/HiTeachController.cs
  77. 21 5
      TEAMModelOS/Controllers/Common/ExamController.cs
  78. 112 4
      TEAMModelOS/Controllers/Core/BlobController.cs
  79. 1 1
      TEAMModelOS/Controllers/Core/ImportController.cs
  80. 1 1
      TEAMModelOS/JsonFile/Core/LangConfigV3.json
  81. 24 0
      TEAMModelOS/Models/Dto/ExamClassResultDto.cs
  82. 33 0
      TEAMModelOS/Models/Dto/ExamDto.cs
  83. 1 2
      TEAMModelOS/TEAMModelOS.csproj
  84. 1 1
      TEAMModelOS/appsettings.Development.json
  85. 1 1
      TEAMModelOS/appsettings.json

+ 27 - 6
TEAMModelFunction/ExamTrigger.cs

@@ -20,17 +20,34 @@ namespace TEAMModelFunction
             ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
             ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
             List<ExamClassResult> examClassResults = new List<ExamClassResult>();
             List<ExamClassResult> examClassResults = new List<ExamClassResult>();
             List<ExamSubject> examSubjects = new List<ExamSubject>();
             List<ExamSubject> examSubjects = new List<ExamSubject>();
-            await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{school}") }))
+            if (info.scope.Equals("teacher", StringComparison.OrdinalIgnoreCase) || info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
             {
             {
-                using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{info.creatorId}") }))
                 {
                 {
-                    foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                     {
                     {
-                        examClassResults.Add(obj.ToObject<ExamClassResult>());
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            examClassResults.Add(obj.ToObject<ExamClassResult>());
+                        }
+                    }
+                }
+            }
+            else {
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{school}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            examClassResults.Add(obj.ToObject<ExamClassResult>());
+                        }
                     }
                     }
                 }
                 }
             }
             }
+            
 
 
             List<ChangeRecord> records = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", info.progress } });
             List<ChangeRecord> records = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", info.progress } });
             //ChangeRecord record = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ChangeRecord>(input.Id, new Azure.Cosmos.PartitionKey($"{info.progress}"));
             //ChangeRecord record = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ChangeRecord>(input.Id, new Azure.Cosmos.PartitionKey($"{info.progress}"));
@@ -207,7 +224,11 @@ namespace TEAMModelFunction
                 {
                 {
                     foreach (List<double> scores in classResult.studentScores)
                     foreach (List<double> scores in classResult.studentScores)
                     {
                     {
-                        result.studentScores.Add(scores);
+                        List<double> newScores = new List<double>();
+                        foreach (double sc in scores) {
+                            newScores.Add(sc > -1 ? sc : 0);
+                        }
+                        result.studentScores.Add(newScores);
                     }
                     }
                     //处理班级信息
                     //处理班级信息
                     ClassRange range = new ClassRange();
                     ClassRange range = new ClassRange();

+ 33 - 1
TEAMModelFunction/MonitorServicesBus.cs

@@ -6,6 +6,7 @@ using Azure.Cosmos;
 using Microsoft.Azure.WebJobs;
 using Microsoft.Azure.WebJobs;
 using Microsoft.Azure.WebJobs.Host;
 using Microsoft.Azure.WebJobs.Host;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
+using StackExchange.Redis;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models;
@@ -16,10 +17,16 @@ namespace TEAMModelFunction
     {
     {
         private readonly AzureCosmosFactory _azureCosmos;
         private readonly AzureCosmosFactory _azureCosmos;
         private readonly DingDing _dingDing;
         private readonly DingDing _dingDing;
-        public MonitorServicesBus(AzureCosmosFactory azureCosmos, DingDing dingDing)
+        private readonly AzureStorageFactory _azureStorage;
+       private readonly AzureRedisFactory _azureRedis;
+        public MonitorServicesBus(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage
+             , AzureRedisFactory azureRedis
+            )
         {
         {
             _azureCosmos = azureCosmos;
             _azureCosmos = azureCosmos;
             _dingDing = dingDing;
             _dingDing = dingDing;
+            _azureStorage = azureStorage;
+            _azureRedis = azureRedis;
         }
         }
         [FunctionName("Exam")]
         [FunctionName("Exam")]
         public async Task Exam([ServiceBusTrigger("active-task", "exam", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
         public async Task Exam([ServiceBusTrigger("active-task", "exam", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
@@ -140,5 +147,30 @@ namespace TEAMModelFunction
                 await _dingDing.SendBotMsg($"ServiceBus,VoteBus()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
                 await _dingDing.SendBotMsg($"ServiceBus,VoteBus()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
             }
             }
         }
         }
+        [FunctionName("Blob")]
+        public async Task Blob([ServiceBusTrigger("active-task", "blob", Connection = "Azure:ServiceBus:ConnectionString")] string msg) {
+            try
+            {
+               // await _dingDing.SendBotMsg($"ServiceBus,Blob(){msg}", GroupNames.醍摩豆服務運維群組);
+                var jsonMsg = JsonDocument.Parse(msg);
+                if(jsonMsg.RootElement.TryGetProperty("name", out JsonElement name)&& name.ValueKind==JsonValueKind.String)
+                {
+                    var client = _azureStorage.GetBlobContainerClient($"{name}");
+                    var size = await client.GetBlobsCatalogSize();
+                    await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", new RedisValue($"{name}"), new RedisValue($"{long.Parse($"{size.Item1}")}"));
+                    foreach (var key in size.Item2.Keys)
+                    {
+                        await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{name}", key);
+                        await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", key, size.Item2[key].HasValue ? size.Item2[key].Value : 0);
+                    }
+                    await _dingDing.SendBotMsg($"ServiceBus,Blob() 容器:{name}使用:{size.Item1},文件分类:{size.Item2.ToJsonString()}",
+                            GroupNames.醍摩豆服務運維群組);
+                }
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"ServiceBus,Blob()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
+            }
+        }
     }
     }
 }
 }

+ 1 - 0
TEAMModelFunction/Startup.cs

@@ -21,6 +21,7 @@ namespace TEAMModelFunction
             builder.Services.AddAzureServiceBus(Environment.GetEnvironmentVariable("Azure:ServiceBus:ConnectionString"));
             builder.Services.AddAzureServiceBus(Environment.GetEnvironmentVariable("Azure:ServiceBus:ConnectionString"));
             builder.Services.AddAzureStorage(Environment.GetEnvironmentVariable("Azure:Starage:ConnectionString"));
             builder.Services.AddAzureStorage(Environment.GetEnvironmentVariable("Azure:Starage:ConnectionString"));
             builder.Services.AddAzureCosmos(Environment.GetEnvironmentVariable("Azure:Cosmos:ConnectionString"));
             builder.Services.AddAzureCosmos(Environment.GetEnvironmentVariable("Azure:Cosmos:ConnectionString"));
+            builder.Services.AddAzureRedis(Environment.GetEnvironmentVariable("Azure:Redis:ConnectionString"));
         }
         }
     }
     }
 }
 }

+ 1 - 0
TEAMModelFunction/TEAMModelFunction.csproj

@@ -2,6 +2,7 @@
   <PropertyGroup>
   <PropertyGroup>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <AzureFunctionsVersion>v3</AzureFunctionsVersion>
     <AzureFunctionsVersion>v3</AzureFunctionsVersion>
+    <_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Remove="AServiceBus.cs" />
     <Compile Remove="AServiceBus.cs" />

+ 1 - 0
TEAMModelFunction/local.settings.json

@@ -5,6 +5,7 @@
     "Azure:Starage:ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelstorage;AccountKey=Yq7D4dE6cFuer2d2UZIccTA/i0c3sJ/6ITc8tNOyW+K5f+/lWw9GCos3Mxhj47PyWQgDL8YbVD63B9XcGtrMxQ==;EndpointSuffix=core.chinacloudapi.cn",
     "Azure:Starage:ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelstorage;AccountKey=Yq7D4dE6cFuer2d2UZIccTA/i0c3sJ/6ITc8tNOyW+K5f+/lWw9GCos3Mxhj47PyWQgDL8YbVD63B9XcGtrMxQ==;EndpointSuffix=core.chinacloudapi.cn",
     "Azure:ServiceBus:ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
     "Azure:ServiceBus:ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
     "Azure:Cosmos:ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;",
     "Azure:Cosmos:ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;",
+    "Azure:Redis:ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False",
     "FUNCTIONS_WORKER_RUNTIME": "dotnet",
     "FUNCTIONS_WORKER_RUNTIME": "dotnet",
     "ScanModel": "TEAMModelOS",
     "ScanModel": "TEAMModelOS",
     "Database": "TEAMModelOS"
     "Database": "TEAMModelOS"

+ 68 - 1
TEAMModelOS.SDK/DI/AzureStorage/AzureStorageBlobExtensions.cs

@@ -11,6 +11,8 @@ using System.IO;
 using Azure.Storage.Blobs.Specialized;
 using Azure.Storage.Blobs.Specialized;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
+using System.Text;
+using Azure.Core;
 
 
 namespace TEAMModelOS.SDK.DI
 namespace TEAMModelOS.SDK.DI
 {
 {
@@ -26,7 +28,8 @@ namespace TEAMModelOS.SDK.DI
             long? size = 0;
             long? size = 0;
             try
             try
             {
             {
-                await foreach (var item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, prefix))
+               
+                await foreach (BlobItem item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, prefix))
                 {
                 {
                     size += item.Properties.ContentLength;
                     size += item.Properties.ContentLength;
                 };
                 };
@@ -37,6 +40,70 @@ namespace TEAMModelOS.SDK.DI
                 return size;
                 return size;
             }
             }
         }
         }
+        /// <summary>
+        /// 取得指定前置詞的 Blob 名稱的總大小(Bytes),例如指定目錄名稱為前置詞
+        /// </summary>      
+        /// <param name="prefix">篩選開頭名稱,Null代表容器總大小</param>
+        /// <returns>總大小(Bytes),如果為Null代表查無前置詞或者發生錯誤</returns>
+        public static async Task<(long?, Dictionary<string, double?>)> GetBlobsCatalogSize(this BlobContainerClient client, string prefix = null)
+        {
+            long? size = 0;
+            Dictionary<string, double?> dict = new Dictionary<string, double?>();
+            try
+            {
+                List<KeyValuePair<string, double?>> foderSize = new List<KeyValuePair<string, double?>>();
+                await foreach (BlobItem item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, prefix))
+                {
+                    var len = item.Properties.ContentLength;
+                    foderSize.Add(new KeyValuePair<string, double?>(item.Name.Split("/")[0], len));
+                    size += item.Properties.ContentLength;
+                };
+                foderSize.Select(x => new { x.Key, x.Value }).GroupBy(y=>y.Key).ToList().ForEach(g=> {
+                    var gpsize = g.Select(m => m.Value).Sum();
+                    dict[g.Key] = gpsize;
+                });
+                return (size, dict);
+            }
+            catch
+            {
+                return (size, dict);
+            }
+        }
+
+        public class OptUrl
+        {
+            public string url { get; set; }
+            public long size { get; set; }
+        }
+        /// <summary>
+        /// 取得指定前置詞的 Blob 名稱的總大小(Bytes),例如指定目錄名稱為前置詞
+        /// </summary>      
+        /// <param name="urls">多个文件的连接/param>
+        /// <returns>總大小(Bytes),如果為Null代表查無前置詞或者發生錯誤</returns>
+        public static async Task<List<OptUrl>> GetBlobsSize(this BlobContainerClient client, List<string> urls)
+        {
+            List<OptUrl> optUrls = new List<OptUrl>();
+            try
+            {
+               
+                foreach (var url in urls) {
+                    OptUrl optUrl = new OptUrl { url = url, size =0};
+                    var eurl = System.Web.HttpUtility.UrlDecode(url, Encoding.UTF8);
+                    var blob = client.GetBlobClient(eurl);
+                    if (blob.Exists()) {
+                        var props = await blob.GetPropertiesAsync();
+                        var size= props.Value.ContentLength;
+                        optUrl.size = size;
+                    }
+                    optUrls.Add(optUrl);
+                }
+                return optUrls;
+            }
+            catch
+            {
+                return optUrls;
+            }
+        }
         /// <summary>        
         /// <summary>        
         /// 批量刪除Blobs
         /// 批量刪除Blobs
         /// </summary>      
         /// </summary>      

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Repair.cs

@@ -12,7 +12,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
         /// <summary>
         /// <summary>
         /// 文件名字
         /// 文件名字
         /// </summary>
         /// </summary>
-        //public string name { get; set; }
+        public string name { get; set; }
         /// <summary>
         /// <summary>
         /// 补救资源绝对地址
         /// 补救资源绝对地址
         /// </summary>
         /// </summary>

+ 4 - 4
TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs

@@ -97,10 +97,10 @@ namespace TEAMModelOS.SDK.Models
         public string scope { get; set; }
         public string scope { get; set; }
         public int multipleRule { get; set; }
         public int multipleRule { get; set; }
         //该试卷配分情况
         //该试卷配分情况
-        public List<double> point { get; set; }
-        public List<List<string>> answers { get; set; }
-        public List<List<string>> knowledge { get; set; }
-        public List<int> field { get; set; }
+        public List<double> point { get; set; } = new List<double>();
+        public List<List<string>> answers { get; set; } = new List<List<string>>();
+        public List<List<string>> knowledge { get; set; } = new List<List<string>>();
+        public List<int> field { get; set; } = new List<int>();
     }
     }
     /*public class Condition
     /*public class Condition
     {
     {

+ 72 - 0
TEAMModelOS.SDK/Models/Cosmos/School/Knowledge.cs

@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.School
+{
+    /// <summary>
+    ///Teaching materials 教学材料 --- 知识点,知识块
+    /// </summary>    
+    public class Knowledge : CosmosEntity
+    {
+        public Knowledge() {
+            points = new List<string>();
+            blocks = new List<CodeValue>();
+            pk = "Knowledge";
+        }
+
+        public string scope { get; set; }
+        /// <summary>
+        /// 学段id
+        /// </summary>
+        public string periodId { get; set; }
+        /// <summary>
+        /// 学科id
+        /// </summary>
+        public string subjectId { get; set; }
+        /// <summary>
+        /// 知识点
+        /// </summary>
+        public List<string> points { get; set; }
+        /// <summary>
+        /// 知识块
+        /// </summary>
+        public List<CodeValue> blocks { get; set; }
+
+    }
+    /*
+    {
+        "id": "123",
+        "code": "Knowledge-hbcn-subjectId",
+        "periodId": "uuid",
+        
+        "points": [
+            "一元一次方程","二元一次方程","一元二次方程","直线方程","三元一次方程","鸡兔同笼问题","微积分方程","函数有界性","函数单调性","函数奇偶性","函数周期性","函数连续性","函数凹凸性",
+            "常函数","一次函数","二次函数","三次函数","四次函数","五次函数","幂函数","指数函数","对数函数","三角函数","反三角函数","常数函数",
+            "正弦函数","余弦函数","正切函数","余切函数","正割函数","余割函数","正矢函数","余矢函数","半正矢函数","半余矢函数","外正割函数","外余割函数"
+        ],
+        "block":[
+            {
+                "code": "方程式" ,
+                "value":["一元一次方程","二元一次方程","一元二次方程","直线方程","三元一次方程","鸡兔同笼问题","微积分方程"]
+            },
+            {
+                "code": "函数的特性" ,
+                "value": ["函数有界性","函数单调性","函数奇偶性","函数周期性","函数连续性","函数凹凸性"]
+            },
+            {
+                "code": "多项式函数" ,
+                "value": ["常函数","一次函数","二次函数","三次函数","四次函数","五次函数"]
+            },
+            {
+                "code":  "基本初等函数" ,
+                "value": ["幂函数","指数函数","对数函数","三角函数","反三角函数","常数函数"]
+            },
+            {
+                "code": "三角函数" ,
+                "value":["正弦函数","余弦函数","正切函数","余切函数","正割函数","余割函数","正矢函数","余矢函数","半正矢函数","半余矢函数","外正割函数","外余割函数"]
+            }
+        ]
+    }
+    */
+}

+ 8 - 0
TEAMModelOS/ClientApp/src/api/learnActivity.js

@@ -283,6 +283,14 @@ export default {
      */
      */
     upsertAnswer: function (data) {
     upsertAnswer: function (data) {
         return post('/teacher/comment/upsert-answer', data)
         return post('/teacher/comment/upsert-answer', data)
+    },
+
+    /**
+     * 必须是已结束的评测,进行中的评测可能会报错
+     *获取评测简要数据分析
+     */
+    simpleAna: function (data) {
+        return post('/analysis/simple', data)
     }
     }
 
 
 }
 }

+ 4 - 0
TEAMModelOS/ClientApp/src/api/stuAccount.js

@@ -63,5 +63,9 @@ export default {
     return post('/school/init/recall-school-aclasson', {
     return post('/school/init/recall-school-aclasson', {
       school_code: data
       school_code: data
     })
     })
+  },
+  //从班级移除学生
+  removeStudent: function(data){
+    return post('/student/removeStudentFromClass', data)
   }
   }
 }
 }

+ 12 - 2
TEAMModelOS/ClientApp/src/api/studentWeb.js

@@ -6,8 +6,6 @@ import {  post } from '@/api/http'
 // ES Modules syntax
 // ES Modules syntax
 import fetch from 'node-fetch';
 import fetch from 'node-fetch';
 global.fetch = fetch;
 global.fetch = fetch;
-
-
 var Mock = require('mockjs')
 var Mock = require('mockjs')
 
 
 var mockdata = [];
 var mockdata = [];
@@ -154,6 +152,18 @@ export default {
     SaveStuExamPaper: function (data) {
     SaveStuExamPaper: function (data) {
         return post('/common/exam/upsert-record', data)
         return post('/common/exam/upsert-record', data)
     },
     },
+    //保存学生评量数据
+    getStudentAnalysis: function (data) {
+        return post('/analysis/studentAnalysis', data)
+    },
+    //查询评量Sas
+    getStudentSas: function (data) {
+        return post('/blob/sas-r', data)
+    },
+    //查询文件授权
+    getFileSas: function (data) {
+        return post('/blob/sas-url-r', data)
+    },
 
 
 }
 }
 
 

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 8 - 7
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css


+ 355 - 329
TEAMModelOS/ClientApp/src/common/BaseCanvas.vue

@@ -1,362 +1,388 @@
 <template>
 <template>
-    <canvas
-        :ref="domId"
-        class="app-sign-canvas" :id="domId"
-        @mousedown.prevent.stop="handleMousedown"
-        @mousemove.prevent.stop="handleMousemove"
-        @mouseup.prevent.stop="handleMouseup"
-        @mouseleave.prevent.stop="handleMouseleave"
-        @touchstart.prevent.stop="handleTouchstart"
-        @touchmove.prevent.stop="handleTouchmove"
-        @touchend.prevent.stop="handleTouchend">
-        您的浏览器不支持canvas技术,请升级浏览器!
-    </canvas>
+	<canvas :ref="domId" class="app-sign-canvas" :id="domId" @mousedown.prevent.stop="handleMousedown"
+	 @mousemove.prevent.stop="handleMousemove" @mouseup.prevent.stop="handleMouseup" @mouseleave.prevent.stop="handleMouseleave"
+	 @touchstart.prevent.stop="handleTouchstart" @touchmove.prevent.stop="handleTouchmove" @touchend.prevent.stop="handleTouchend">
+		您的浏览器不支持canvas技术,请升级浏览器!
+	</canvas>
 </template>
 </template>
 <script>
 <script>
-export default {
-    name: 'BaseCanvas',
-    model: {
-        value: 'image',
-        event: 'confirm'
-    },
-    props: {
-        image: {
-            required: false,
-            type: [String],
-            default: null
-        },
-
-        options: {  //配置项
-            required: false,
-            type: [Object],
-            default: () => null
-        },
+	export default {
+		name: 'BaseCanvas',
+		model: {
+			value: 'image',
+			event: 'confirm'
+		},
+		props: {
+			image: {
+				required: false,
+				type: [String],
+				default: null
+			},
 
 
-    },
-    data () {
-        return {
-            value: null, //base64
-            domId: `sign-canvas-${Math.random().toString(36).substr(2)}`,  //生成唯一dom标识
-            canvas:null,    //canvas dom对象
-            context:null,   //canvas 画布对象
-            dpr: 1,
-            config: {
-                isDpr: false,       //是否使用dpr兼容高分屏 [Boolean] 可选
-                lastWriteSpeed: 1,  //书写速度 [Number] 可选
-                lastWriteWidth: 2,  //下笔的宽度 [Number] 可选
-                lineCap: 'round',   //线条的边缘类型 [butt]平直的边缘 [round]圆形线帽 [square]	正方形线帽
-                lineJoin: 'round',  //线条交汇时边角的类型  [bevel]创建斜角 [round]创建圆角 [miter]创建尖角。
-                canvasWidth: 600, //canvas宽高 [Number] 可选
-                canvasHeight: 600,  //高度  [Number] 可选
-                isShowBorder: true, //是否显示边框 [可选]
-                bgColor: '#fcc', //背景色 [String] 可选 注:这背景色仅仅只是canvas背景,保存的图片仍然是透明的
-                borderWidth: 1, // 网格线宽度  [Number] 可选
-                borderColor: "#ff787f", //网格颜色  [String] 可选
-                writeWidth: 5, //基础轨迹宽度  [Number] 可选
-                maxWriteWidth: 30, // 写字模式最大线宽  [Number] 可选
-                minWriteWidth: 5, // 写字模式最小线宽  [Number] 可选
-                writeColor: '#101010', // 轨迹颜色  [String] 可选
-                isSign: false, //签名模式 [Boolean] 默认为非签名模式,有线框, 当设置为true的时候没有任何线框
-                imgType:'png'   //下载的图片格式  [String] 可选为 jpeg  canvas本是透明背景的
-            }
-        };
-    },
-    mounted () {
-        this.init();
-    },
+			options: { //配置项
+				required: false,
+				type: [Object],
+				default: () => null
+			},
 
 
-    watch:{
-        'options.writeWidth':{
-            handler(n){
-				this.context.lineWidth = n
-				this.config.writeWidth = n
-            },
-            deep: true
-        },
-		'options.writeColor':{
-		    handler(n){
-				this.context.strokeStyle = n
-				this.config.writeColor = n
-		    },
-		    deep: true
 		},
 		},
-		'options.canvasWidth':{
-		    handler(n){
-				this.canvas.width = n
-				this.config.canvasWidth = n
-				this.canvasInit();
-		    },
+		data() {
+			return {
+				value: null, //base64
+				domId: `sign-canvas-${Math.random().toString(36).substr(2)}`, //生成唯一dom标识
+				canvas: null, //canvas dom对象
+				context: null, //canvas 画布对象
+				dpr: 1,
+				config: {
+					isDpr: false, //是否使用dpr兼容高分屏 [Boolean] 可选
+					lastWriteSpeed: 1, //书写速度 [Number] 可选
+					lastWriteWidth: 2, //下笔的宽度 [Number] 可选
+					lineCap: 'round', //线条的边缘类型 [butt]平直的边缘 [round]圆形线帽 [square]	正方形线帽
+					lineJoin: 'round', //线条交汇时边角的类型  [bevel]创建斜角 [round]创建圆角 [miter]创建尖角。
+					canvasWidth: 600, //canvas宽高 [Number] 可选
+					canvasHeight: 600, //高度  [Number] 可选
+					isShowBorder: true, //是否显示边框 [可选]
+					bgColor: '#fcc', //背景色 [String] 可选 注:这背景色仅仅只是canvas背景,保存的图片仍然是透明的
+					borderWidth: 1, // 网格线宽度  [Number] 可选
+					borderColor: "#ff787f", //网格颜色  [String] 可选
+					writeWidth: 5, //基础轨迹宽度  [Number] 可选
+					maxWriteWidth: 30, // 写字模式最大线宽  [Number] 可选
+					minWriteWidth: 5, // 写字模式最小线宽  [Number] 可选
+					writeColor: '#101010', // 轨迹颜色  [String] 可选
+					isSign: false, //签名模式 [Boolean] 默认为非签名模式,有线框, 当设置为true的时候没有任何线框
+					imgType: 'png' //下载的图片格式  [String] 可选为 jpeg  canvas本是透明背景的
+				},
+			};
 		},
 		},
-		'options.canvasHeight':{
-		    handler(n){
-				this.canvas.height = n
-				this.config.canvasHeight = n
-				this.canvasInit();
-		    },
+		mounted() {
+			this.init();
+		},
+
+		watch: {
+			'options.writeWidth': {
+				handler(n) {
+					this.context.lineWidth = n
+					this.config.writeWidth = n
+				},
+				deep: true
+			},
+			'options.writeColor': {
+				handler(n) {
+					this.context.strokeStyle = n
+					this.config.writeColor = n
+				},
+				deep: true
+			},
+			'options.canvasWidth': {
+				handler(n) {
+					this.canvas.width = n
+					this.config.canvasWidth = n
+					this.canvasInit();
+				},
+			},
+			'options.canvasHeight': {
+				handler(n) {
+					this.canvas.height = n
+					this.config.canvasHeight = n
+					this.canvasInit();
+				},
+			},
 		},
 		},
-    },
 
 
-    methods: {
-        init () {
-            const options = this.options;
-            if (options) {
-                for (const key in options) {
-                    this.config[key] = options[key];
-                }
-            }
-            this.dpr = typeof window !== 'undefined' && this.config.isDpr ? window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1 : 1;
-			console.log(this.domId)
-			this.$nextTick(() => {
-				this.canvas = document.getElementById(this.domId);
-				console.log(this.canvas)
-				this.context = this.canvas.getContext("2d");
-				this.canvas.style.background = this.config.bgColor;
-				this.canvas.height = this.config.canvasWidth;
-				this.canvas.width = this.config.canvasHeight;
-				this.canvasInit();
-				this.canvasClear();
-			})
-            
-        },
+		methods: {
+			init() {
+				const options = this.options;
+				if (options) {
+					for (const key in options) {
+						this.config[key] = options[key];
+					}
+				}
+				this.dpr = typeof window !== 'undefined' && this.config.isDpr ? window.devicePixelRatio || window.webkitDevicePixelRatio ||
+					window.mozDevicePixelRatio || 1 : 1;
+				console.log(this.domId)
+				this.$nextTick(() => {
+					this.canvas = document.getElementById(this.domId);
+					console.log(this.canvas)
+					this.context = this.canvas.getContext("2d");
+					this.canvas.style.background = this.config.bgColor;
+					this.canvas.height = this.config.canvasWidth;
+					this.canvas.width = this.config.canvasHeight;
+					this.canvasInit();
+					this.canvasClear();
+				})
+
+			},
+			
+			/* 绘制输入的文本 */
+			doAddText(val) {
+				let context = this.context
+				context.fillStyle = "red";
+				context.textAlign = 'left';
+				context.font = '40px Helvetica';
+				context.fillText(val, 40, 40);
+			},
 
 
-        /**
-         * 轨迹宽度
-         */
-        setLineWidth () {
-            const nowTime = new Date().getTime();
-            const diffTime = nowTime - this.config.lastWriteTime;
-            this.config.lastWriteTime = nowTime;
-            let returnNum = this.config.minWriteWidth + (this.config.maxWriteWidth - this.config.minWriteWidth) * diffTime / 30;
-            if (returnNum < this.config.minWriteWidth) {
-                returnNum = this.config.minWriteWidth;
-            } else if (returnNum > this.config.maxWriteWidth) {
-                returnNum = this.config.maxWriteWidth;
-            }
-            returnNum = returnNum.toFixed(2);
-            //写字模式和签名模式
-            if (this.config.isSign) {
-                this.context.lineWidth = this.config.writeWidth * this.dpr;
-            } else {
-                const lineWidth = this.config.lastWriteWidth = this.config.lastWriteWidth / 4 * 3 + returnNum / 4
-                this.context.lineWidth = lineWidth * this.dpr;
-            }
-        },
+			/**
+			 * 轨迹宽度
+			 */
+			setLineWidth() {
+				const nowTime = new Date().getTime();
+				const diffTime = nowTime - this.config.lastWriteTime;
+				this.config.lastWriteTime = nowTime;
+				let returnNum = this.config.minWriteWidth + (this.config.maxWriteWidth - this.config.minWriteWidth) * diffTime / 30;
+				if (returnNum < this.config.minWriteWidth) {
+					returnNum = this.config.minWriteWidth;
+				} else if (returnNum > this.config.maxWriteWidth) {
+					returnNum = this.config.maxWriteWidth;
+				}
+				returnNum = returnNum.toFixed(2);
+				//写字模式和签名模式
+				if (this.config.isSign) {
+					this.context.lineWidth = this.config.writeWidth * this.dpr;
+				} else {
+					const lineWidth = this.config.lastWriteWidth = this.config.lastWriteWidth / 4 * 3 + returnNum / 4
+					this.context.lineWidth = lineWidth * this.dpr;
+				}
+			},
 
 
-        /**
-         * 写开始
-         */
-        writeBegin (point) {
-            this.config.isWrite = true;
-            this.config.lastWriteTime = new Date().getTime();
-            this.config.lastPoint = point;
-            this.writeContextStyle();
-        },
+			/**
+			 * 写开始
+			 */
+			writeBegin(point) {
+				this.config.isWrite = true;
+				this.config.lastWriteTime = new Date().getTime();
+				this.config.lastPoint = point;
+				this.writeContextStyle();
+			},
 
 
-        /**
-         * 绘制轨迹
-         */
-        writing (point) {
-            this.context.beginPath();
-            this.context.moveTo(this.config.lastPoint.x * this.dpr, this.config.lastPoint.y * this.dpr);
-            this.context.lineTo(point.x * this.dpr, point.y * this.dpr);
-            this.setLineWidth();
-            this.context.stroke();
-            this.config.lastPoint = point;
-            this.context.closePath();
-        },
+			/**
+			 * 绘制轨迹
+			 */
+			writing(point) {
+				this.context.beginPath();
+				this.context.moveTo(this.config.lastPoint.x * this.dpr, this.config.lastPoint.y * this.dpr);
+				this.context.lineTo(point.x * this.dpr, point.y * this.dpr);
+				this.setLineWidth();
+				this.context.stroke();
+				this.config.lastPoint = point;
+				this.context.closePath();
+			},
 
 
-         /**
-         * 写结束
-         */
-        writeEnd (point) {
-            this.config.isWrite = false;
-            this.config.lastPoint = point;
-        },
+			/**
+			 * 写结束
+			 */
+			writeEnd(point) {
+				this.config.isWrite = false;
+				this.config.lastPoint = point;
+			},
 
 
-        /**
-         * 轨迹样式
-         */
-        writeContextStyle () {
-            this.context.beginPath();
-            this.context.strokeStyle = this.config.writeColor;
-            this.context.lineCap = this.config.lineCap;
-            this.context.lineJoin = this.config.lineJoin;
-        },
+			/**
+			 * 轨迹样式
+			 */
+			writeContextStyle() {
+				this.context.beginPath();
+				this.context.strokeStyle = this.config.writeColor;
+				this.context.lineCap = this.config.lineCap;
+				this.context.lineJoin = this.config.lineJoin;
+			},
 
 
 
 
-        /**
-         * 清空画板
-         */
-        canvasClear () {
-            this.context.save();
-            this.context.strokeStyle = this.config.writeColor;
-            this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
-            this.context.beginPath();
-            this.context.lineWidth = this.config.borderWidth * this.dpr;
-            this.context.strokeStyle = this.config.borderColor;
-            let size = this.config.borderWidth / 2 * this.dpr;
-            if(this.config.isShowBorder){
-                //画外面的框
-                this.context.moveTo(size, size);
-                this.context.lineTo(this.canvas.width - size, size);
-                this.context.lineTo(this.canvas.width - size, this.canvas.height - size);
-                this.context.lineTo(size, this.canvas.height - size);
-                this.context.closePath();
-                this.context.stroke();
-            }
-            if (this.config.isShowBorder && !this.config.isSign) {
-                //画里面的框
-                this.context.moveTo(0, 0);
-                this.context.lineTo(this.canvas.width, this.canvas.height);
-                this.context.lineTo(this.canvas.width, this.canvas.height / 2);
-                this.context.lineTo(0, this.canvas.height / 2);
-                this.context.lineTo(0, this.canvas.height);
-                this.context.lineTo(this.canvas.width, 0);
-                this.context.lineTo(this.canvas.width / 2, 0);
-                this.context.lineTo(this.canvas.width / 2, this.canvas.height);
-                this.context.stroke();
-            }
-            this.$emit('confirm', null);
-            this.context.restore();
-        },
+			/**
+			 * 清空画板
+			 */
+			canvasClear() {
+				this.context.save();
+				this.context.strokeStyle = this.config.writeColor;
+				this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
+				this.context.beginPath();
+				this.context.lineWidth = this.config.borderWidth * this.dpr;
+				this.context.strokeStyle = this.config.borderColor;
+				let size = this.config.borderWidth / 2 * this.dpr;
+				if (this.config.isShowBorder) {
+					//画外面的框
+					this.context.moveTo(size, size);
+					this.context.lineTo(this.canvas.width - size, size);
+					this.context.lineTo(this.canvas.width - size, this.canvas.height - size);
+					this.context.lineTo(size, this.canvas.height - size);
+					this.context.closePath();
+					this.context.stroke();
+				}
+				if (this.config.isShowBorder && !this.config.isSign) {
+					//画里面的框
+					this.context.moveTo(0, 0);
+					this.context.lineTo(this.canvas.width, this.canvas.height);
+					this.context.lineTo(this.canvas.width, this.canvas.height / 2);
+					this.context.lineTo(0, this.canvas.height / 2);
+					this.context.lineTo(0, this.canvas.height);
+					this.context.lineTo(this.canvas.width, 0);
+					this.context.lineTo(this.canvas.width / 2, 0);
+					this.context.lineTo(this.canvas.width / 2, this.canvas.height);
+					this.context.stroke();
+				}
+				this.$emit('confirm', null);
+				this.context.restore();
+			},
 
 
-        /**
-         *  保存图片 格式base64
-         */
-        async saveAsImg() {
-			return new Promise(async (r,j) => {
-				const image = new Image();
-				let compressImg = await this.$editorTools.compressImg(this.canvas.toDataURL(`image/${this.config.imgType}`),this.canvas.width,this.canvas.height)
-				r({
-					base64:compressImg,
-					width:this.canvas.width,
-					height:this.canvas.height
+			/**
+			 *  保存图片 格式base64
+			 */
+			async saveAsImg() {
+				return new Promise(async (r, j) => {
+					const image = new Image();
+					let compressImg = await this.$editorTools.compressImg(this.canvas.toDataURL(`image/${this.config.imgType}`),
+						this.canvas.width, this.canvas.height)
+					r({
+						base64: compressImg,
+						width: this.canvas.width,
+						height: this.canvas.height
+					})
 				})
 				})
-			})
-            
-        },
 
 
-        /**
-         * 初始化画板
-         */
-        canvasInit () {
-            this.canvas.width = this.config.canvasWidth;
-            this.canvas.height = this.config.canvasHeight;
-            this.canvas.style.width = `${this.config.canvasWidth}px`;
-            this.canvas.style.height = `${this.config.canvasHeight}px`;
-            this.config.emptyCanvas = this.canvas.toDataURL(`image/${this.config.imgType}`);
-			console.log(this.canvas.width,this.canvas.height)
-		},
+			},
+
+			/**
+			 * 初始化画板
+			 */
+			canvasInit() {
+				this.canvas.width = this.config.canvasWidth;
+				this.canvas.height = this.config.canvasHeight;
+				this.canvas.style.width = `${this.config.canvasWidth}px`;
+				this.canvas.style.height = `${this.config.canvasHeight}px`;
+				this.config.emptyCanvas = this.canvas.toDataURL(`image/${this.config.imgType}`);
+				console.log(this.canvas.width, this.canvas.height)
+			},
 
 
-        /**
-         * 鼠标按下 => 下笔
-         */
-        handleMousedown(e){
-            this.writeBegin({ x: e.offsetX || e.clientX, y: e.offsetY || e.clientY });
-        },
+			/**
+			 * 鼠标按下 => 下笔
+			 */
+			handleMousedown(e) {
+				console.log(e)
+				this.writeBegin({
+					x: e.offsetX || e.clientX,
+					y: e.offsetY || e.clientY
+				});
+			},
 
 
-        /**
-         * 书写过程 => 下笔书写
-         */
-        handleMousemove(e){
-            this.config.isWrite && this.writing({ x: e.offsetX, y: e.offsetY });
-        },
+			/**
+			 * 书写过程 => 下笔书写
+			 */
+			handleMousemove(e) {
+				this.config.isWrite && this.writing({
+					x: e.offsetX,
+					y: e.offsetY
+				});
+			},
 
 
-        /**
-         * 鼠标松开 => 提笔
-         */
-        handleMouseup(e){
-            this.writeEnd({ x: e.offsetX, y: e.offsetY });
-        },
+			/**
+			 * 鼠标松开 => 提笔
+			 */
+			handleMouseup(e) {
+				this.writeEnd({
+					x: e.offsetX,
+					y: e.offsetY
+				});
+			},
 
 
-        /**
-         * 离开书写区域 => 提笔离开
-         */
-        handleMouseleave(e){
-            this.config.isWrite = false;
-            this.config.lastPoint = { x: e.offsetX, y: e.offsetY };
-        },
+			/**
+			 * 离开书写区域 => 提笔离开
+			 */
+			handleMouseleave(e) {
+				this.config.isWrite = false;
+				this.config.lastPoint = {
+					x: e.offsetX,
+					y: e.offsetY
+				};
+			},
 
 
-        /* ==========================移动端兼容=Start================================ */
+			/* ==========================移动端兼容=Start================================ */
 
 
-        /**
-         * 手指按下 => 下笔
-         */
-        handleTouchstart(e){
-            const touch = e.targetTouches[0];
-            const x = touch.clientX ? touch.clientX - this.getRect().left :  touch.pageX - this.offset(touch.target,'left');
-            const y = touch.clientY ? touch.clientY - this.getRect().top  : touch.pageY - this.offset(touch.target,'top');
-            this.writeBegin({ x, y});
-        },
+			/**
+			 * 手指按下 => 下笔
+			 */
+			handleTouchstart(e) {
+				const touch = e.targetTouches[0];
+				const x = touch.clientX ? touch.clientX - this.getRect().left : touch.pageX - this.offset(touch.target, 'left');
+				const y = touch.clientY ? touch.clientY - this.getRect().top : touch.pageY - this.offset(touch.target, 'top');
+				this.writeBegin({
+					x,
+					y
+				});
+			},
 
 
-        /**
-         * 手指移动 => 下笔书写
-         */
-        handleTouchmove(e){
-            const touch = e.targetTouches[0];
-            const x = touch.clientX ? touch.clientX - this.getRect().left :  touch.pageX - this.offset(touch.target,'left');
-            const y = touch.clientY ? touch.clientY - this.getRect().top  : touch.pageY - this.offset(touch.target,'top');
-            this.config.isWrite && this.writing({ x, y });
-        },
+			/**
+			 * 手指移动 => 下笔书写
+			 */
+			handleTouchmove(e) {
+				const touch = e.targetTouches[0];
+				const x = touch.clientX ? touch.clientX - this.getRect().left : touch.pageX - this.offset(touch.target, 'left');
+				const y = touch.clientY ? touch.clientY - this.getRect().top : touch.pageY - this.offset(touch.target, 'top');
+				this.config.isWrite && this.writing({
+					x,
+					y
+				});
+			},
 
 
-        /**
-         * 手指移动结束 => 提笔离开
-         */
-        handleTouchend(e){
-            const tcs = e.targetTouches;
-            const ccs = e.changedTouches;
-            const touch = tcs && tcs.length && tcs[0] || ccs && ccs.length && ccs[0];
-            const x = touch.clientX ? touch.clientX - this.getRect().left :  touch.pageX - this.offset(touch.target,'left');
-            const y = touch.clientY ? touch.clientY - this.getRect().top  : touch.pageY - this.offset(touch.target,'top');
-            this.writeEnd({ x, y });
-        },
+			/**
+			 * 手指移动结束 => 提笔离开
+			 */
+			handleTouchend(e) {
+				const tcs = e.targetTouches;
+				const ccs = e.changedTouches;
+				const touch = tcs && tcs.length && tcs[0] || ccs && ccs.length && ccs[0];
+				const x = touch.clientX ? touch.clientX - this.getRect().left : touch.pageX - this.offset(touch.target, 'left');
+				const y = touch.clientY ? touch.clientY - this.getRect().top : touch.pageY - this.offset(touch.target, 'top');
+				this.writeEnd({
+					x,
+					y
+				});
+			},
 
 
-        /* ==========================移动端兼容=End================================== */
+			/* ==========================移动端兼容=End================================== */
 
 
-        /**
-         * 下载二维码到本地
-         */
-        downloadSignImg(name) {
-            const c = document.getElementById(this.domId);
-            const dataURL = c.toDataURL('image/png');
-            this.saveFile(dataURL, name ? `${name}.${this.config.imgType}` : `${Date.parse(new Date())}.${this.config.imgType}`);
-        },
+			/**
+			 * 下载二维码到本地
+			 */
+			downloadSignImg(name) {
+				const c = document.getElementById(this.domId);
+				const dataURL = c.toDataURL('image/png');
+				this.saveFile(dataURL, name ? `${name}.${this.config.imgType}` : `${Date.parse(new Date())}.${this.config.imgType}`);
+			},
 
 
-        /**
-         * 保存文件
-         */
-        saveFile(data, filename) {
-            const saveLink = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
-            saveLink.href = data;
-            saveLink.download = filename;
-            const event = document.createEvent('MouseEvents');
-            event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-            saveLink.dispatchEvent(event);
-        },
+			/**
+			 * 保存文件
+			 */
+			saveFile(data, filename) {
+				const saveLink = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
+				saveLink.href = data;
+				saveLink.download = filename;
+				const event = document.createEvent('MouseEvents');
+				event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+				saveLink.dispatchEvent(event);
+			},
 
 
-        /**
-         * 获取画布的元素的大小及其相对于视口的位置
-         * @return {}
-         */
-        getRect() {
-            return this.$refs[this.domId].getBoundingClientRect();
-        },
+			/**
+			 * 获取画布的元素的大小及其相对于视口的位置
+			 * @return {}
+			 */
+			getRect() {
+				return this.$refs[this.domId].getBoundingClientRect();
+			},
 
 
-        /**
-         * 获取dom对象的偏移量 可以获取解决position定位的问题
-         * @returns number
-         */
-        offset(obj, direction) {
-            //将top,left首字母大写,并拼接成offsetTop,offsetLeft
-            const offsetDir = 'offset'+ direction[0].toUpperCase()+direction.substring(1);
-            let realNum = obj[offsetDir];
-            let positionParent = obj.offsetParent;  //获取上一级定位元素对象
-            while(positionParent != null){
-                realNum += positionParent[offsetDir];
-                positionParent = positionParent.offsetParent;
-            }
-            return realNum;
-        }
-    }
-};
+			/**
+			 * 获取dom对象的偏移量 可以获取解决position定位的问题
+			 * @returns number
+			 */
+			offset(obj, direction) {
+				//将top,left首字母大写,并拼接成offsetTop,offsetLeft
+				const offsetDir = 'offset' + direction[0].toUpperCase() + direction.substring(1);
+				let realNum = obj[offsetDir];
+				let positionParent = obj.offsetParent; //获取上一级定位元素对象
+				while (positionParent != null) {
+					realNum += positionParent[offsetDir];
+					positionParent = positionParent.offsetParent;
+				}
+				return realNum;
+			}
+		}
+	};
 </script>
 </script>

+ 24 - 1
TEAMModelOS/ClientApp/src/common/BaseMyCanvas.vue

@@ -1,6 +1,6 @@
 <template>
 <template>
 	<div id="baseCanvas" @mouseover="mouseOver" @mouseleave="mouseLeave">
 	<div id="baseCanvas" @mouseover="mouseOver" @mouseleave="mouseLeave">
-		<BaseCanvas class="sign-canvas" ref="SignCanvas" :options="options" v-model="value" />
+		<BaseCanvas class="sign-canvas" ref="SignCanvas" :options="options"/>
 		<div class="canvas-tools animated fadeIn" ref="canvasTools">
 		<div class="canvas-tools animated fadeIn" ref="canvasTools">
 			<span class="canvas-tools-item" style="border-radius: 15px 0 0 0;">
 			<span class="canvas-tools-item" style="border-radius: 15px 0 0 0;">
 				<Poptip trigger="hover">
 				<Poptip trigger="hover">
@@ -33,6 +33,10 @@
 					</div>
 					</div>
 				</Poptip>
 				</Poptip>
 			</span>
 			</span>
+			<span class="canvas-tools-item" @click="addText()">
+				<Icon type="md-text" />
+				<span>文本输入</span>
+			</span>
 			<span class="canvas-tools-item" @click="canvasClear()">
 			<span class="canvas-tools-item" @click="canvasClear()">
 				<Icon type="md-refresh" />
 				<Icon type="md-refresh" />
 				<span>清屏</span>
 				<span>清屏</span>
@@ -46,6 +50,14 @@
 				<span>保存</span>
 				<span>保存</span>
 			</span>
 			</span>
 		</div>
 		</div>
+		
+		<Modal v-model="addTextModal" title="添加文本" ref="pointRef" width="400px" class="related-point-modal" style="z-index:99999">
+			<span>输入文本内容</span>
+			<Input v-model="addTextVal"  style="margin:10px 0" />
+			<div slot="footer">
+				<Button type="primary" style="width: 100px;" @click="doAddText">确认</Button>
+			</div>
+		</Modal>
 	</div>
 	</div>
 </template>
 </template>
 <script>
 <script>
@@ -75,6 +87,8 @@
 		data() {
 		data() {
 			return {
 			return {
 				value: null,
 				value: null,
+				addTextModal:false,
+				addTextVal:'',
 				activeDot: 5,
 				activeDot: 5,
 				activeColor: 'black',
 				activeColor: 'black',
 				options: {
 				options: {
@@ -111,6 +125,15 @@
 			onChangeWriteColor(val) {
 			onChangeWriteColor(val) {
 				this.options.writeColor = val
 				this.options.writeColor = val
 			},
 			},
+			
+			addText(){
+				this.addTextModal = true
+			},
+			
+			doAddText(){
+				this.$refs.SignCanvas.doAddText(this.addTextVal);
+				this.addTextModal = false
+			},
 
 
 			onSelectWriteColor(val) {
 			onSelectWriteColor(val) {
 				console.log(val)
 				console.log(val)

+ 2 - 2
TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.vue

@@ -62,9 +62,9 @@
 							<div class="item-explain">
 							<div class="item-explain">
 								<span class="explain-title">【知识点】</span>
 								<span class="explain-title">【知识点】</span>
 								<div class="item-explain-details">
 								<div class="item-explain-details">
-									<span v-if="!item.points.length">暂未绑定知识点</span>
+									<span v-if="!item.knowledge || !item.knowledge.length">暂未绑定知识点</span>
 									<div v-else>
 									<div v-else>
-										<span v-for="(point, index) in item.points" class="item-point-tag" :key="index">
+										<span v-for="(point, index) in item.knowledge" class="item-point-tag" :key="index">
 											{{ point }}
 											{{ point }}
 										</span>
 										</span>
 									</div>
 									</div>

+ 0 - 9
TEAMModelOS/ClientApp/src/components/selflearn/NewChooseContent.vue

@@ -390,8 +390,6 @@ export default {
             this.queryQuestionByPage()
             this.queryQuestionByPage()
         },
         },
         selectQuestion(data) {
         selectQuestion(data) {
-            console.log('题目')
-            console.log(data)
             this.$emit('on-select-question', data)
             this.$emit('on-select-question', data)
         },
         },
         //Tab切换事件
         //Tab切换事件
@@ -413,21 +411,15 @@ export default {
         },
         },
         //处理文件选中状态
         //处理文件选中状态
         handleCheckStatus() {
         handleCheckStatus() {
-            let count = 0
             this.$nextTick(() => {
             this.$nextTick(() => {
                 let urls = this.selectedFiles.map(item => { return item.url })
                 let urls = this.selectedFiles.map(item => { return item.url })
                 for (let i in this.$refs.fileTable.$refs.tbody.objData) {
                 for (let i in this.$refs.fileTable.$refs.tbody.objData) {
                     if (this.selectedFiles.length) {
                     if (this.selectedFiles.length) {
                         if (urls.indexOf(this.$refs.fileTable.$refs.tbody.objData[i].url) > -1) {
                         if (urls.indexOf(this.$refs.fileTable.$refs.tbody.objData[i].url) > -1) {
                             this.$refs.fileTable.$refs.tbody.objData[i]._isChecked = true
                             this.$refs.fileTable.$refs.tbody.objData[i]._isChecked = true
-                            count++
                         } else {
                         } else {
                             this.$refs.fileTable.$refs.tbody.objData[i]._isChecked = false
                             this.$refs.fileTable.$refs.tbody.objData[i]._isChecked = false
                         }
                         }
-                        //如果已经设置完成,提前跳出循环
-                        if (count == this.selectedFiles.length) {
-                            break
-                        }
                     } else {
                     } else {
                         this.$refs.fileTable.$refs.tbody.objData[i]._isChecked = false
                         this.$refs.fileTable.$refs.tbody.objData[i]._isChecked = false
                     }
                     }
@@ -508,7 +500,6 @@ export default {
                         prefix: this.contentFilter.fileType
                         prefix: this.contentFilter.fileType
                     }).then(
                     }).then(
                         (res) => {
                         (res) => {
-                            console.log('/*/*/*', res)
                             this.fileList[this.contentFilter.scope][this.contentFilter.fileType] = res.blobList
                             this.fileList[this.contentFilter.scope][this.contentFilter.fileType] = res.blobList
                             this.fileListShow = this.fileList[this.contentFilter.scope][this.contentFilter.fileType]
                             this.fileListShow = this.fileList[this.contentFilter.scope][this.contentFilter.fileType]
                             this.searchBefore = [...this.fileListShow]
                             this.searchBefore = [...this.fileListShow]

+ 216 - 133
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue

@@ -5,8 +5,8 @@
                 <svg-icon icon-class="handonHint" class="warm-icon" />
                 <svg-icon icon-class="handonHint" class="warm-icon" />
                 <span class="warm-hint">{{ $t("studentWeb.exam.timeoutHint") }}</span>
                 <span class="warm-hint">{{ $t("studentWeb.exam.timeoutHint") }}</span>
             </div>
             </div>
-            <span v-show="$store.getters.getItemTitle.progress != 'finish' && testState == 1" @click="showTest" style="color: #03966a;width: 100%;cursor: pointer;font-size:18px;font-weight: 800;text-align: center">前往作答</span>
-            <h4 v-show='testState == 2'>成绩尚未结算</h4>
+            <span v-show="$store.getters.getItemTitle.progress != 'finish' && testState == 1" @click="showTest" style="color: #03966a;width: 100%;cursor: pointer;font-size:18px;font-weight: 800;text-align: center">{{$t("studentWeb.exam.report.anwser")}}</span>
+            <h4 v-show='testState == 2'>{{$t("studentWeb.exam.report.noRes")}}</h4>
             <Row :gutter="20" v-if='testState == 3'>
             <Row :gutter="20" v-if='testState == 3'>
                 <i-col :xs="24" :sm="24" :md="24" :lg="12">
                 <i-col :xs="24" :sm="24" :md="24" :lg="12">
                     <Row :gutter="20">
                     <Row :gutter="20">
@@ -39,7 +39,7 @@
                         </i-col>
                         </i-col>
                         <i-col :xs="24" :sm="24" :md="12" :lg="12">
                         <i-col :xs="24" :sm="24" :md="12" :lg="12">
                             <Card class="score-card">
                             <Card class="score-card">
-                                <p class="card-title">得分题目数</p>
+                                <p class="card-title">{{$t("studentWeb.exam.report.getScore")}}</p>
                                 <div class="card-content">
                                 <div class="card-content">
                                     <span class="myscore">{{rightAns.right}}</span> / {{rightAns.all}}
                                     <span class="myscore">{{rightAns.right}}</span> / {{rightAns.all}}
                                 </div>
                                 </div>
@@ -70,22 +70,22 @@
         <div class="QAsheet" v-if='testState != 1'>
         <div class="QAsheet" v-if='testState != 1'>
             <div class='title-rect-group '>
             <div class='title-rect-group '>
                 <div class="title-rect" />
                 <div class="title-rect" />
-                <h2 class="title-rect-name"  @click="checkedAnsFilter">评测作答回顾</h2>
+                <h2 class="title-rect-name" @click="checkedAnsFilter">{{$t("studentWeb.exam.report.answerBack")}}</h2>
             </div>
             </div>
             <div class="filterBtn">
             <div class="filterBtn">
                 <label class="checkAns">
                 <label class="checkAns">
                     <input type="checkbox" value="right" v-model="checkedAns" />
                     <input type="checkbox" value="right" v-model="checkedAns" />
-                    <span>答对: {{rightAns.right}}</span>
+                    <span>{{$t("studentWeb.exam.report.right")}}: {{rightAns.right}}</span>
                     <div class="rightBtn"></div>
                     <div class="rightBtn"></div>
                 </label>
                 </label>
                 <label class="checkAns">
                 <label class="checkAns">
                     <input type="checkbox" value="wrong" v-model="checkedAns" />
                     <input type="checkbox" value="wrong" v-model="checkedAns" />
-                    <span>答错: {{ examInfo.stuScore.length - rightAns.right - rightAns.noAns}}</span>
+                    <span>{{$t("studentWeb.exam.report.wrong")}}: {{ examInfo.stuScore.length - rightAns.right - rightAns.noAns}}</span>
                     <div class="wrongBtn"></div>
                     <div class="wrongBtn"></div>
                 </label>
                 </label>
                 <label class="checkAns" v-show=" rightAns.noAns != 0 ">
                 <label class="checkAns" v-show=" rightAns.noAns != 0 ">
                     <input type="checkbox" value="noAns" v-model="checkedAns" />
                     <input type="checkbox" value="noAns" v-model="checkedAns" />
-                    <span>未评分: {{ rightAns.noAns}}</span>
+                    <span>{{$t("studentWeb.exam.report.noScore")}}: {{ rightAns.noAns}}</span>
                     <div class="noAnsBtn"></div>
                     <div class="noAnsBtn"></div>
                 </label>
                 </label>
             </div>
             </div>
@@ -94,86 +94,156 @@
             </div>
             </div>
             <br style="clear:both" />
             <br style="clear:both" />
             <div class="qcontent" ref="qcontent" v-if="paperData.length">
             <div class="qcontent" ref="qcontent" v-if="paperData.length">
-                    <div class="qcol"
-                         v-for="(question, index) in paperData"
-                         v-show="checkedAnsFilter(index)"
-                         :key="index">
-                        <Row :gutter="10">
-                            <i-col :xs="1" :sm="1" :md="1" :lg="1">
-                                <div class="qAnsCondition">
-                                    <svg-icon class="qIcon"
-                                              v-show="examInfo.stuScore[index] == question.score"
-                                              icon-class="rightAns2" />
-                                    <svg-icon class="qIcon"
-                                              v-show="examInfo.stuScore[index] != -1 && examInfo.stuScore[index] != question.score"
-                                              icon-class="wrongAns" />
-                                    <svg-icon class="qIcon"
-                                              v-show="examInfo.stuScore[index] == -1"
-                                              icon-class="noAns" />
+                <div class="qcol"
+                     v-for="(question, index) in paperData"
+                     v-show="checkedAnsFilter(index)"
+                     :key="index">
+                    <Row :gutter="10">
+                        <i-col :xs="1" :sm="1" :md="1" :lg="1">
+                            <div class="qAnsCondition">
+                                <svg-icon class="qIcon"
+                                          v-show="examInfo.stuScore[index] == question.score"
+                                          icon-class="rightAns2" />
+                                <svg-icon class="qIcon"
+                                          v-show="examInfo.stuScore[index] != -1 && examInfo.stuScore[index] != question.score"
+                                          icon-class="wrongAns" />
+                                <svg-icon class="qIcon"
+                                          v-show="examInfo.stuScore[index] == -1"
+                                          icon-class="noAns" />
+                            </div>
+                        </i-col>
+                        <i-col :xs="2" :sm="2" :md="1" :lg="1">
+                            <div class="qtype">{{ question.parent == undefined ? getTestType(question.type) : getTestType(question.parentInfo.type) }}</div>
+                        </i-col>
+                        <i-col :xs="18" :sm="18" :md="21" :lg="21">
+                            <div class="qdesc">
+                                <div v-if="question.parent == undefined" style="display:inline-flex">
+                                    <p style="max-width:75px;font-weight:600">{{question.paperIndex}}.</p>
+                                    <div class="que-item" v-html="question.parent == undefined ? question.question :question.parentInfo.question"></div>
                                 </div>
                                 </div>
-                            </i-col>
-                            <i-col :xs="2" :sm="2" :md="1" :lg="1">
-                                <div class="qtype">{{ question.parent == undefined ? getTestType(question.type) : getTestType(question.parentInfo.type) }}</div>
-                            </i-col>
-                            <i-col :xs="18" :sm="18" :md="21" :lg="21">
-                                <div class="qdesc">
-                                    <div v-if="question.parent == undefined" style="display:inline-flex">
-                                        <p style="max-width:75px;font-weight:600">{{question.paperIndex}}.</p>
+                                <div v-if="question.parent != undefined">
+                                    <div style="display:flex">
+                                        <p style="max-width:75px;font-weight:600">{{question.parent+1}}.</p>
                                         <div class="que-item" v-html="question.parent == undefined ? question.question :question.parentInfo.question"></div>
                                         <div class="que-item" v-html="question.parent == undefined ? question.question :question.parentInfo.question"></div>
                                     </div>
                                     </div>
-                                    <div v-if="question.parent != undefined">
-                                        <div style="display:flex">
-                                            <p style="max-width:75px;font-weight:600">{{question.parent+1}}.</p>
-                                            <div class="que-item" v-html="question.parent == undefined ? question.question :question.parentInfo.question"></div>
-                                        </div>
-                                        <div style="display:flex;margin-top:10px">
-                                            <p style="max-width:75px;font-weight:600">{{question.paperIndex}}.</p>
-                                            <div class="que-item" v-html="question.question"></div>
-                                        </div>
-                                    </div>
-                                </div>
-                            </i-col>
-                            <i-col :xs="2" :sm="2" :md="1" :lg="1">
-                                <div class="qScore">
-                                    <span v-if="examInfo.stuScore[index] != -1">{{examInfo.stuScore[index]}}/{{question.score}}</span>
-                                    <span v-if="examInfo.stuScore[index] == -1">未评分</span>
-                                </div>
-                            </i-col>
-                        </Row>
-                        <div class="qAnaly" :class="{ hideqAnaly: closeAnsDetail }">
-                            <div class="rightAns">
-                                <div class="qAnserlist">
-                                    <div v-for="(item,index) in question.option" style="display:flex;margin-top:5px;">
-                                        ({{item.code}})<div style="margin-left:10px" v-html="item.value"></div>
+                                    <div style="display:flex;margin-top:10px">
+                                        <p style="max-width:75px;font-weight:600">{{question.paperIndex}}.</p>
+                                        <div class="que-item" v-html="question.question"></div>
                                     </div>
                                     </div>
-                                    <div class="TitleRec1"><span style="margin:5px;color:#1472c7">作答结果:</span></div>
-                                    <br />
-                                    <div v-if="ansData[index]" style="margin-left:10px" v-html="ansData[index].length > 0 ? ansData[index][0] : '未作答'">32131{{ansData[index][0]}}</div>
                                 </div>
                                 </div>
                             </div>
                             </div>
-                            <!--<br />-->
-                            <div class="rightAnalys">
-                                <div class="TitleRec2"><span style="margin-left:5px">参考答案:</span></div>
-                                <br />
-                                <div style="display:flex">
-                                    <div v-for="(item,iundex) in question.answer" v-html="item" style="margin-left:10px;"></div>
+                        </i-col>
+                        <i-col :xs="2" :sm="2" :md="1" :lg="1">
+                            <div class="qScore">
+                                <span v-if="examInfo.stuScore[index] != -1">{{examInfo.stuScore[index]}}/{{question.score}}</span>
+                                <span v-if="examInfo.stuScore[index] == -1">{{$t("studentWeb.exam.report.noScore")}}</span>
+                            </div>
+                        </i-col>
+                    </Row>
+                    <div class="qAnaly" :class="{ hideqAnaly: closeAnsDetail }">
+                        <div class="rightAns">
+                            <div class="qAnserlist">
+                                <div v-for="(item,index) in question.option" style="display:flex;margin-top:5px;">
+                                    ({{item.code}})<div style="margin-left:10px" v-html="item.value"></div>
                                 </div>
                                 </div>
-                                <div class="TitleRec2"><span style="margin-left:5px">解析:</span></div>
-                                <br />
-                                <div style="margin-left:10px;" v-html="question.explain != '' ?  question.explain : '暂无解析' "></div>  
-                                <div class="TitleRec2"><span style="margin-left:5px">补救资源:</span></div>
+                                <div class="TitleRec1"><span style="margin:5px;color:#1472c7">{{$t("studentWeb.exam.report.ansRes")}}:</span></div>
                                 <br />
                                 <br />
-                                <div style="margin-left:10px;" v-html="question.explain != '' ?  question.explain : '暂无解析' "></div>
+                                <div v-if="ansData[index]" style="margin-left:10px" v-html="ansData[index].length > 0 ? ansData[index][0] : '未作答'"></div>
+                            </div>
+                        </div>
+                        <!--<br />-->
+                        <div class="rightAnalys">
+                            <div class="TitleRec2"><span style="margin-left:5px">{{$t("studentWeb.exam.report.testAns")}}:</span></div>
+                            <br />
+                            <div style="display:flex">
+                                <div v-for="(item,iundex) in question.answer" v-html="item" style="margin-left:10px;"></div>
+                            </div>
+                            <div class="TitleRec2"><span style="margin-left:5px">{{$t("studentWeb.exam.report.testAnalyse")}}:</span></div>
+                            <br />
+                            <div style="margin-left:10px;" v-html="question.explain != '' ?  question.explain : $t('studentWeb.exam.report.noAnalyse') "></div>
+                            <div v-show="examInfo.stuScore[index] != -1 && examInfo.stuScore[index] != question.score" class="TitleRec2"><span style="margin-left:5px">{{$t("studentWeb.exam.report.repairSource")}}:</span></div>
+                            <br />
+                            <div style="margin-left:10px;display:flex" v-show="examInfo.stuScore[index] != -1 && examInfo.stuScore[index] != question.score">
+                                <div v-if="question.repair" class="repair-box">
+                                    <Collapse style="width:85%" accordion @on-change="getSource(question.repair,question)">
+                                        <Panel name="1">
+                                            链接资源
+                                            <p slot="content">
+                                                <List border size="small">
+                                                    <ListItem v-for="(item,normalIndex) in repairSource.normal" :key="normalIndex">
+                                                        <span style="margin-right:10px;" v-show="item.blobUrl">
+                                                            <Icon color="#0066FF" custom="iconfont icon-share_link" size="20" />
+                                                        </span><a :href="item.blobUrl" target="_blank">{{item.blobUrl}}</a>
+                                                    </ListItem>
+                                                    <ListItem v-show="repairSource.normal.length == 0">
+                                                        <span>暂无资源</span>
+                                                    </ListItem>
+                                                </List>
+                                            </p>
+                                        </Panel>
+                                        <Panel name="2">
+                                            文件资源
+                                            <p slot="content">
+                                                <List border size="small">
+                                                    <ListItem v-for="(item,fileIndex) in repairSource.file" :key="fileIndex">
+                                                        <div style="width:100%">
+                                                            <span style="margin-right:10px;">
+                                                                <Icon v-if="item.fileType == 'zip'" custom="iconfont icon-zip" size="20" />
+                                                                <Icon v-else-if="item.fileType == 'zip'" color="#8199AF" custom="iconfont icon-zip" size="20" />
+                                                                <Icon v-else-if="item.fileType == 'pdf'" color="#FF6464" custom="iconfont icon-pdf" size="20" />
+                                                                <Icon v-else-if="item.fileType == 'ppt'|| item.fileType == 'pptx'" color="#FF8976" custom="iconfont icon-ppt" size="20" />
+                                                                <Icon v-else-if="item.fileType == 'mp3'" color="#FF5562" custom="iconfont icon-mp3" size="20" />
+                                                                <Icon v-else-if="item.fileType == 'mp4'" color="#8E4C9E" custom="iconfont icon-video1" size="20" />
+                                                                <Icon v-else-if="item.fileType == 'zip'" custom="iconfont icon-video1" size="20" />
+                                                                <Icon v-else-if="item.fileType == 'doc'||item.fileType =='docx'" color="#6CCBFF" custom="iconfont icon-word" size="20" />
+                                                                <Icon v-else-if="item.fileType == 'csv'||item.fileType =='xlsx'||item.fileType =='xls'" color="#25C273" custom="iconfont icon-xlsx" size="20" />
+                                                                <Icon v-else-if="item.fileType == 'jpg'||item.fileType =='png'||item.fileType =='jpeg'" color="#30D1CA" custom="iconfont icon-jpg" size="20" />
+                                                                <Icon v-else custom="iconfont icon-V" size="20" />
+                                                            </span><a @click="getItemData(item)">{{item.name}}</a>
+                                                            <span style="display:block;float:right;cursor:pointer">
+                                                                <Icon type="md-download" size="18" @click="downloadFile(item)" />
+                                                            </span>
+                                                        </div>
+                                                       
+                                                    
+                                                    </ListItem>
+                                                    <ListItem v-show="repairSource.file.length == 0">
+                                                        <span>暂无资源</span>
+                                                    </ListItem>
+                                                </List>
+                                            </p>
+                                        </Panel>
+                                    </Collapse>
+                                </div>
                             </div>
                             </div>
                         </div>
                         </div>
                     </div>
                     </div>
+                </div>
             </div>
             </div>
         </div>
         </div>
+        <!--<div v-if="previewStatus" class="image-viewer">
+            <div style="width:fit-content;position:relative;margin:auto;">
+                <Icon type="md-close" class="close-icon" @click="closePreview" />
+                <video v-if="previewFile.type == 'video'" id="previewVideo" :src="previewFile.url" width="870" controls="controls" style="max-height: 800px;">
+                    {{$t('teachContent.tips8')}}
+                </video>
+                <audio v-else-if="previewFile.type == 'audio'" controls>
+                    <source :src="previewFile.url">
+                    您的浏览器不支持 audio 元素。
+                </audio>
+                <img v-else-if="previewFile.type == 'image'" :src="previewFile.url" style="border-radius: 5px;max-height: 800px;max-width:870px;" />
+                <embed v-else-if="previewFile.extension == 'PDF'" :src="previewFile.url" width="870" height="720" />
+                <iframe v-else :src="'https://view.officeapps.live.com/op/view.aspx?src=' + escapeBlobUrl" width='870' height='700' frameborder='1'></iframe>
+            </div>
+        </div>-->
     </div>
     </div>
 </template>
 </template>
 
 
 <script>
 <script>
-    import mockQASheet from "@/api/studentWeb";
+    import BlobTool from '@/utils/blobTool.js';
+    import FileSaver from "file-saver";
+    //import JSZip from "jszip";
+    import elementResizeDetectorMaker from "element-resize-detector"
     import LessonTestReportCharts from "./LessonTestReportCharts/LessonTestReportCharts";
     import LessonTestReportCharts from "./LessonTestReportCharts/LessonTestReportCharts";
     import { Random } from "mockjs";
     import { Random } from "mockjs";
     import Loading from "vue-loading-overlay";
     import Loading from "vue-loading-overlay";
@@ -204,11 +274,7 @@
                 isLoading: true,
                 isLoading: true,
                 opacity: 0.6,
                 opacity: 0.6,
                 //loading畫面
                 //loading畫面
-                currentReportSubject: "國文",
                 closeAnsDetail: false,
                 closeAnsDetail: false,
-                RandomComment: Random.paragraph(1, 2),
-                RandomKeypoint: Random.paragraph(1, 3),
-                mockQASheet: mockQASheet.mockQASheet,
                 checkedAns: ["right", "wrong", "noAns"],
                 checkedAns: ["right", "wrong", "noAns"],
                 testState: 0,
                 testState: 0,
                 testType: [
                 testType: [
@@ -246,7 +312,13 @@
                     },
                     },
                 ],
                 ],
                 paperData: [],
                 paperData: [],
-                ansData:[]
+                ansData: [],
+                repairSource: {
+                    normal: [],
+                    file: []
+                },
+                repairData: [],
+                previewStatus: false
             };
             };
         },
         },
         mounted() {
         mounted() {
@@ -254,6 +326,54 @@
             this.testJudge()
             this.testJudge()
         },
         },
         methods: {
         methods: {
+            getItemData(data) {
+            },
+           async downloadFile(data) {
+                let code = data.blobUrl.split('/')
+                let req = {
+                    url: data.blobUrl
+                }
+                let curFile = ""
+                await this.$api.studentWeb.getFileSas(req).then(res => {
+                    curFile = res.url
+                })
+                const downloadRes = async () => {
+                    let response = await fetch(curFile); // 内容转变成blob地址
+                    let blob = await response.blob();  // 创建隐藏的可下载链接
+                    let objectUrl = window.URL.createObjectURL(blob);
+                    let a = document.createElement('a');
+                    a.href = objectUrl;
+                    a.download = data.name;
+                    a.click()
+                    a.remove();
+                }
+                downloadRes();
+            },
+            getSource(data, info) {
+                this.repairSource = {
+                    normal: [],
+                    file: []
+                }
+                let source = {
+                    normal: [],
+                    file: []
+                }
+                for (let item of data) {
+                    if (item.type == 'normal') {
+                        source.normal.push(item)
+                    } else if (item.blobUrl) {
+                        let code = item.blobUrl.split('/')
+                        let data = code[code.length - 1].split('.')
+                        item.name = code[code.length-1]
+                        item.file = code[code.length - 2]
+                        item.fileType = data[data.length -1]
+                        source.file.push(item)
+                    }
+                }
+                this.repairSource = source
+                //let code = data.blobUrl.split('/')
+                //console.log(code)
+            },
             showTest() {
             showTest() {
                 if (this.examInfo.subject !== undefined) {
                 if (this.examInfo.subject !== undefined) {
                     this.$store.commit("ToggleLessonTestPopWithSubject", this.examInfo)
                     this.$store.commit("ToggleLessonTestPopWithSubject", this.examInfo)
@@ -298,12 +418,24 @@
                         code: key[(key.length - 1)],
                         code: key[(key.length - 1)],
                         blob: data
                         blob: data
                     }
                     }
+                    let blob = this.formUrl(code)
+                    code.blob = blob
                     datas = await this.$evTools.getComposeItem(code)
                     datas = await this.$evTools.getComposeItem(code)
                     return datas
                     return datas
                 } else {
                 } else {
                     return []
                     return []
                 }
                 }
             },
             },
+            formUrl(data) {
+                let container = data.code
+                let a = ""
+                if (data.blob.indexOf('https://teammodelstorage') > -1) {
+                    a = data.blob
+                } else {
+                    a = `${this.$GLOBAL.BLOB_URL}/${container}/exam/${data.blob}`
+                }
+                return a 
+            },
            async formPaper() {
            async formPaper() {
                 let paper = []
                 let paper = []
                 this.paperData.length = []
                 this.paperData.length = []
@@ -330,7 +462,6 @@
                     }
                     }
                 }
                 }
                this.paperData = [...paper]
                this.paperData = [...paper]
-               console.log(this.paperData)
                if (this.paperData.length) {
                if (this.paperData.length) {
                    this.ansData = await this.getItem(this.examInfo.stuAns[0])
                    this.ansData = await this.getItem(this.examInfo.stuAns[0])
                }
                }
@@ -345,13 +476,6 @@
             getCurrentLang() {
             getCurrentLang() {
                 return localStorage.getItem('lang');
                 return localStorage.getItem('lang');
             },
             },
-
-            transSubjecttoEn(type) {
-                if (type == "國文") return "Chinese";
-                else if (type == "英文") return "English";
-                else if (type == "數學") return "Math";
-                else if (type == "綜合學科") return "Comprehensive";
-            },
             RandomNum() {
             RandomNum() {
                 return Random.integer(70, 96)
                 return Random.integer(70, 96)
             },
             },
@@ -368,28 +492,6 @@
             closeDetail() {
             closeDetail() {
                 this.closeAnsDetail = !this.closeAnsDetail;
                 this.closeAnsDetail = !this.closeAnsDetail;
             },
             },
-            changeListSubject(subject) {
-                this.currentReportSubject = subject;
-                this.doAjax();
-            },
-            ansRightSum: function () {
-                var ansRightSum = [0, 0, 0];
-                for (var i = 0; i < 10; i++) {
-                    if (this.mockQASheet[i].rightAns == this.mockQASheet[i].MyAns) {
-                        ansRightSum[0]++;
-                    } else if (
-                        this.mockQASheet[i].rightAns != this.mockQASheet[i].MyAns &&
-                        this.mockQASheet[i].MyAns != ""
-                    ) {
-                        ansRightSum[1]++;
-                    } else if (this.mockQASheet[i].MyAns == "") {
-                        ansRightSum[2]++;
-                    } else {
-                        ansRightSum += 0;
-                    }
-                }
-                return ansRightSum;
-            },
             checkedAnsFilter(index) {
             checkedAnsFilter(index) {
                 if (this.checkedAns.includes("right") == true && this.examInfo.stuScore[index] == this.paperData[index].score) {
                 if (this.checkedAns.includes("right") == true && this.examInfo.stuScore[index] == this.paperData[index].score) {
                     return true;
                     return true;
@@ -402,32 +504,6 @@
                 else return false;
                 else return false;
 
 
             },
             },
-            transQtypetoEn(Qtype) {
-                if (localStorage.getItem('lang') == 'en') {
-                    if (Qtype == "單選") {
-                        return "Single"
-                    } else if (Qtype == "多選") {
-                        return "Multi";
-                    }
-                    else if (Qtype == "判斷") {
-                        return "True/False"
-                    }
-                    else if (Qtype == "填充") {
-                        return "Fill in the blank"
-                    }
-                    else return
-                }
-                else return Qtype
-            },
-            doAjax() {
-                this.isLoading = true;
-
-                // simulate AJAX
-                setTimeout(() => {
-                    this.forceRerender();
-                    this.isLoading = false;
-                }, 3000);
-            },
         },
         },
         computed: {
         computed: {
             testScore() {
             testScore() {
@@ -784,11 +860,18 @@
         top: -70%;
         top: -70%;
         right: -40%;
         right: -40%;
         font-size: 20px;
         font-size: 20px;
-        color: rgba(0, 0, 0, 0.5)
+        color: rgba(0, 0, 0, 0.5);
     }
     }
 
 
     .vld-overlay {
     .vld-overlay {
         outline: none;
         outline: none;
-        border: none
+        border: none;
     }
     }
+    .repair-box{
+        width:100%;
+    }
+        .repair-box /deep/ .ivu-list-container{
+            max-height:300px;
+            overflow:scroll;
+        }
 </style>
 </style>

+ 85 - 28
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReportCharts/StudentScore.vue

@@ -4,22 +4,22 @@
             <div class="stu-info">
             <div class="stu-info">
                 <ul>
                 <ul>
                     <li>
                     <li>
-                        <p><Icon type="ios-home" size="24" />本次考试名称:<span>成都市第三次月考</span></p>
+                        <p><Icon type="ios-home" size="24" />本次考试名称:<span>--</span></p>
                     </li>
                     </li>
                     <li>
                     <li>
-                        <p><Icon type="ios-paper" size="24" />考试类型:<span>正规考</span></p>
+                        <p><Icon type="ios-paper" size="24" />考试类型:<span>--</span></p>
                     </li>
                     </li>
                     <li>
                     <li>
-                        <p><Icon type="ios-list-box" size="24" />学习稳定系数:<span>0.8</span></p>
+                        <p><Icon type="ios-list-box" size="24" />学习稳定系数:<span>--</span></p>
                     </li>
                     </li>
                     <li>
                     <li>
-                        <p><Icon type="ios-person" size="24" />姓名:<span>SOUL</span></p>
+                        <p><Icon type="ios-person" size="24" />姓名:<span>{{$store.state.userInfo.name}}</span></p>
                     </li>
                     </li>
                     <li>
                     <li>
-                        <p style="margin-top:5px">学号:<span>12345678</span></p>
+                        <p style="margin-top:5px">学号:<span>{{$store.state.userInfo.sub}}</span></p>
                     </li>
                     </li>
                     <li>
                     <li>
-                        <p style="margin-top:5px">班级:<span>高三五班</span></p>
+                        <p style="margin-top:5px">班级:<span>{{$store.state.user.studentProfile.classinfo.name}}</span></p>
                     </li>
                     </li>
                 </ul>
                 </ul>
             </div>
             </div>
@@ -28,35 +28,36 @@
                 <ul>
                 <ul>
                     <li style="margin-right:5%;margin-top:15px;margin-left:3%">
                     <li style="margin-right:5%;margin-top:15px;margin-left:3%">
                         <h2 style="color:cornflowerblue;font-size:18px">个人总分</h2>
                         <h2 style="color:cornflowerblue;font-size:18px">个人总分</h2>
-                        <p style="color: cornflowerblue;font-size: 30px;font-weight: 800">483</p>
+                        <p style="color: cornflowerblue;font-size: 30px;font-weight: 800">{{scoreInfo.total}}</p>
                     </li>
                     </li>
                     <li class="sub-ave">
                     <li class="sub-ave">
                         <h2>班级平均分</h2>
                         <h2>班级平均分</h2>
-                        <p>472</p>
+                        <p>{{scoreInfo.classAverage}}</p>
                     </li>
                     </li>
                     <li class="sub-ave">
                     <li class="sub-ave">
                         <h2>年级平均分</h2>
                         <h2>年级平均分</h2>
-                        <p>468</p>
+                        <p>{{scoreInfo.gradeAverage}}</p>
                     </li>
                     </li>
                     <li class="sub-ave">
                     <li class="sub-ave">
                         <h2>区级平均分</h2>
                         <h2>区级平均分</h2>
-                        <p>457</p>
+                        <p>--</p>
                     </li>
                     </li>
                     <li class="sub-ave">
                     <li class="sub-ave">
                         <h2>班级排名</h2>
                         <h2>班级排名</h2>
-                        <p>05<span>/56</span></p>
+                        <p>{{scoreInfo.rankc}}<span>/{{scoreInfo.classCount}}</span></p>
                     </li>
                     </li>
                     <li class="sub-ave">
                     <li class="sub-ave">
                         <h2>年级排名</h2>
                         <h2>年级排名</h2>
-                        <p>65<span>/456</span></p>
+                        <p>{{scoreInfo.rankg}}<span>/{{scoreInfo.gradeCount}}</span></p>
                     </li>
                     </li>
                     <li class="sub-ave">
                     <li class="sub-ave">
                         <h2>区级排名</h2>
                         <h2>区级排名</h2>
-                        <p>296<span>/1456</span></p>
+                        <!--<p>-<span>/1456</span></p>-->
+                        <p>--</p>
                     </li>
                     </li>
                     <li>
                     <li>
                         <span style="font-size:16px;margin-top:20px;display:block">是否进线</span>
                         <span style="font-size:16px;margin-top:20px;display:block">是否进线</span>
-                        <p style="font-size:24px;font-weight:600;width:60px;text-align:center"></p>
+                        <p style="font-size:24px;font-weight:600;width:60px;text-align:center">--</p>
                     </li>
                     </li>
                 </ul>
                 </ul>
             </div>
             </div>
@@ -93,46 +94,46 @@
                         <span>综合难度</span>
                         <span>综合难度</span>
                     </li>
                     </li>
                 </ul>
                 </ul>
-                <ul v-for="(item,index) in data.examInfo">
+                <ul v-for="(item,index) in scoreInfo.averageMap">
                     <li class="sub-item">
                     <li class="sub-item">
-                        <div class="sub-show"><span>{{item.subject}}</span></div>
+                        <div class="sub-show"><span>{{item.name}}</span></div>
                     </li>
                     </li>
                     <li class="sub-item">
                     <li class="sub-item">
-                        <p>{{item.stuScore}}<span>/{{item.score}}</span></p>
+                        <p>{{item.score}}<span>/{{item.scoreSum}}</span></p>
                     </li>
                     </li>
                     <li class="sub-item">
                     <li class="sub-item">
-                        <p>{{item.classAve}}</p>
+                        <p>{{item.classAverage}}</p>
                     </li>
                     </li>
                     <li class="sub-item">
                     <li class="sub-item">
-                        <p>{{item.gradeAve}}</p>
+                        <p>{{item.gradeAverage}}</p>
                     </li>
                     </li>
                     <li class="sub-item">
                     <li class="sub-item">
-                        <p>{{item.areaAve}}</p>
+                        <p>--</p>
                     </li>
                     </li>
                     <li class="sub-item">
                     <li class="sub-item">
-                        <p>08<span>/56</span></p>
+                        <p>{{item.classRank}}<span>/{{item.classCount}}</span></p>
                     </li>
                     </li>
                     <li class="sub-item">
                     <li class="sub-item">
-                        <p>45<span>/456</span></p>
+                        <p>{{item.gradeRank}}<span>/{{item.gradeCount}}</span></p>
                     </li>
                     </li>
                     <li class="sub-item">
                     <li class="sub-item">
-                        <p>455<span>/1456</span></p>
+                        <p>--<span>/--</span></p>
                     </li>
                     </li>
                     <li class="sub-item">
                     <li class="sub-item">
                         <div class="ans">
                         <div class="ans">
                             <div class="obj-ans">
                             <div class="obj-ans">
                                 <h5>客观</h5>
                                 <h5>客观</h5>
-                                <p>36<span>/40</span></p>
+                                <p>{{item.sub.objIndex}}<span>/{{item.sub.objItem.length}}</span></p>
                             </div>
                             </div>
                             <div class="sub-ans">
                             <div class="sub-ans">
                                 <h5>主观</h5>
                                 <h5>主观</h5>
-                                <p>5<span>/6</span></p>
+                                <p>{{item.sub.subIndex}}<span>/{{item.sub.subItem.length}}</span></p>
                             </div>
                             </div>
                         </div>
                         </div>
 
 
                     </li>
                     </li>
                     <li class="sub-item">
                     <li class="sub-item">
-                        <span>一般</span>
+                        <span>--</span>
                     </li>
                     </li>
                 </ul>
                 </ul>
             </div>
             </div>
@@ -208,6 +209,12 @@
                 default: () => {
                 default: () => {
                     return {}
                     return {}
                 }
                 }
+            },    
+            examData: {
+                type: Array,
+                default: () => {
+                    return []
+                }
             }
             }
         },
         },
         data() {
         data() {
@@ -269,8 +276,10 @@
                     ]
                     ]
                 },
                 },
                 data10: [],
                 data10: [],
+
                 testData: [],
                 testData: [],
-                stuScore:[]
+                stuScore: [],
+                scoreInfo: {}
             }
             }
         },
         },
         methods: {
         methods: {
@@ -280,9 +289,46 @@
                     for (let i = 0; i < this.stuData.papers.length; i++) {
                     for (let i = 0; i < this.stuData.papers.length; i++) {
                         let subData = {}
                         let subData = {}
                         subData.name = this.stuData.subjects[i].name
                         subData.name = this.stuData.subjects[i].name
+                        subData.id = this.stuData.subjects[i].id
                         subData.item = await this.getStudentData(this.stuData.papers[i], this.stuData.stuScore[i], this.stuData.stuAns[i])
                         subData.item = await this.getStudentData(this.stuData.papers[i], this.stuData.stuScore[i], this.stuData.stuAns[i])
                         this.stuScore.push(subData)
                         this.stuScore.push(subData)
                     }
                     }
+                    this.getScoreInfo()
+                }
+            },
+            getScoreInfo() {
+                if (this.examData.length) {
+                    this.scoreInfo = {}
+                    let req = {
+                        "code": this.$store.state.user.schoolCode,
+                        "id": this.examData[0].id,
+                        "sId": this.$store.state.userInfo.sub,
+                        "cId": this.$store.state.user.studentProfile.classinfo.id,
+                        "gId": this.$store.state.user.studentProfile.classinfo.gradeId
+                    }
+                    this.$api.studentWeb.getStudentAnalysis(req).then(res => {
+                        if (res.gradeAverage && this.stuScore.length) {
+                            let gradeCount,classCount = 0
+                            let total = 0
+                            for (let item of res.averageMap) {
+                                total += item.score
+                                gradeCount = item.gradeCount
+                                classCount = item.classCount
+                                this.stuScore.filter((items) => {
+                                    if (item.subjectId == items.id) {
+                                        item.sub = items.item
+                                        item.name = items.name
+                                    }
+                                });
+                            }
+                            res.total = total
+                            res.gradeCount = gradeCount
+                            res.classCount = classCount
+                            this.scoreInfo = res
+                        } else {
+                            this.$Message.warning('成绩信息错误!')
+                        }
+                    })
                 }
                 }
             },
             },
             async getStudentData(data,score,ans) {
             async getStudentData(data,score,ans) {
@@ -302,15 +348,25 @@
                     let answer = await this.getItem(ans)
                     let answer = await this.getItem(ans)
                     paper = await this.formPaper(papers)
                     paper = await this.formPaper(papers)
                     this.testData = paper
                     this.testData = paper
+                    let objIndex = 0
+                    let subIndex = 0
                     for (let i = 0; i < paper.length; i++) {
                     for (let i = 0; i < paper.length; i++) {
                         paper[i].stuScore = score[i]
                         paper[i].stuScore = score[i]
                         paper[i].stuAns = answer[i]
                         paper[i].stuAns = answer[i]
                         if (paper[i].type == 'single' || paper[i].type == 'judge' || paper[i].type == 'multiple') {
                         if (paper[i].type == 'single' || paper[i].type == 'judge' || paper[i].type == 'multiple') {
+                            if (paper[i].stuScore == paper[i].score) {
+                                objIndex++
+                            }
                             item.objItem.push(paper[i])
                             item.objItem.push(paper[i])
                         } else {
                         } else {
+                            if (paper[i].stuScore >= (paper[i].score * 0.8).toFixed(2)) {
+                                subIndex++
+                            }
                             item.subItem.push(paper[i])
                             item.subItem.push(paper[i])
                         }
                         }
                     }
                     }
+                    item.subIndex = subIndex
+                    item.objIndex = objIndex
                 }
                 }
                 return item
                 return item
             },
             },
@@ -360,6 +416,7 @@
         },
         },
         mounted() {
         mounted() {
             this.getPaperData()
             this.getPaperData()
+
         },
         },
         watch: {
         watch: {
             stuData() {
             stuData() {
@@ -468,7 +525,7 @@
             }
             }
 
 
             .stu-analyse .stu-info li {
             .stu-analyse .stu-info li {
-                margin-right: 6%;
+                margin-right: 5%;
                 font-weight: 600;
                 font-weight: 600;
                 font-size: 14px;
                 font-size: 14px;
             }
             }

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

@@ -47,7 +47,7 @@
                         <h2 class="title-rect-name">{{$t("studentWeb.exam.gradeAnalyse")}}</h2>
                         <h2 class="title-rect-name">{{$t("studentWeb.exam.gradeAnalyse")}}</h2>
                     </div>
                     </div>
                     <div class="student-score">
                     <div class="student-score">
-                        <StudentScore :stuData="stuData"></StudentScore>
+                        <StudentScore :examData="paperData" :stuData="stuData"></StudentScore>
                     </div>
                     </div>
                 </TabPane>
                 </TabPane>
             </Tabs>
             </Tabs>

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

@@ -47,7 +47,7 @@ export default{
         evType:'评测类型',
         evType:'评测类型',
         examType:'考试类别',
         examType:'考试类别',
         courseType:'课程类别',
         courseType:'课程类别',
-        cusLable1:'校本课程',
+        cusLabel1:'校本课程',
         cusLabel2:'个人课程',
         cusLabel2:'个人课程',
         evTarget:'施测对象',
         evTarget:'施测对象',
         publishType:'发布方式',
         publishType:'发布方式',

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

@@ -88,6 +88,10 @@ export default {
   '3222C6D2': 'HiTeach TBL',
   '3222C6D2': 'HiTeach TBL',
   'J223IZAM': 'HiTeach PRO',
   'J223IZAM': 'HiTeach PRO',
   addStuBtn: '添加學生',
   addStuBtn: '添加學生',
-  delStuBtn: '删除學生',
-  editSeat: '修改座號'
+  delStuBtn: '移除學生',
+  editSeat: '修改座號',
+  removeTile: '移除提醒',
+  removeContent: '是否確認移除',
+  removeOk: '移除成功',
+  removeErr: '移除失敗'
 }
 }

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

@@ -263,6 +263,20 @@ export default {
             "queNo": "Title:",
             "queNo": "Title:",
             "myAns": "My answer:"
             "myAns": "My answer:"
         },
         },
+        "report": {
+            "anwser": "Go to answer",
+            "noRes": "The results have not yet been settled",
+            "getScore": "Number of score questions",
+            "answerBack": "Review of the review and answer",
+            "right": "Right",
+            "wrong": "Wrong ",
+            "noScore": "Not Review",
+            "ansRes": "Response result",
+            "testAns": "Reference Answer",
+            "testAnalyse": "Analyze",
+            "repairSource": "Repair Source",
+            "noAnalyse": "No analysis"
+        },
         "timeoutHint": "The evaluation activity time has ended. Overtime will be calculated as 0 points, or wait for the teacher to open the make-up exam.",
         "timeoutHint": "The evaluation activity time has ended. Overtime will be calculated as 0 points, or wait for the teacher to open the make-up exam.",
         "contentPage": "Review Content",
         "contentPage": "Review Content",
         "scorePage": "Score Report",
         "scorePage": "Score Report",

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

@@ -74,6 +74,7 @@ export default {
 		field:'关联认知层次', 
 		field:'关联认知层次', 
 		knowledge:'关联知识点',
 		knowledge:'关联知识点',
 		choosePoint:'选择知识点',
 		choosePoint:'选择知识点',
+		modify:'修改',
 		type:'选择题型',
 		type:'选择题型',
 		stem:'题干',
 		stem:'题干',
 		option:'选项',
 		option:'选项',

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

@@ -47,7 +47,7 @@ export default{
         evType:'评测类型',
         evType:'评测类型',
         examType:'考试类别',
         examType:'考试类别',
         courseType:'课程类别',
         courseType:'课程类别',
-        cusLable1:'校本课程',
+        cusLabel1:'校本课程',
         cusLabel2:'个人课程',
         cusLabel2:'个人课程',
         evTarget:'施测对象',
         evTarget:'施测对象',
         publishType:'发布方式',
         publishType:'发布方式',

+ 6 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/schoolBaseInfo.js

@@ -152,6 +152,10 @@ export default {
   delClass:'删除班级',
   delClass:'删除班级',
   saveClassWarning:'当前教室数据尚未保存。如果离开,修改的数据将不会保存!',
   saveClassWarning:'当前教室数据尚未保存。如果离开,修改的数据将不会保存!',
   addStuBtn:'添加学生',
   addStuBtn:'添加学生',
-  delStuBtn:'删除学生',
-  editSeat:'修改座号'
+  delStuBtn:'移除学生',
+  editSeat:'修改座号',
+  removeTile:'移除提醒',
+  removeContent:'是否确认移除',
+  removeOk:'移除成功',
+  removeErr:'移除失败'
 }
 }

+ 38 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/settings.js

@@ -1,5 +1,41 @@
 export default {
 export default {
     setting_title1: '学校管理',
     setting_title1: '学校管理',
-	setting_title2: '一般设置'
-
+	setting_title2: '一般设置',
+	schoolList:'已添加或申请学校',
+	langSetting:'网站语言设定',
+	langTips:'请选择网站要用来显示选单、互动页面以及通知信息的语言',
+	langCheck:'使用浏览器语系展示',
+	themeSetting:'网站色彩模式',
+	themeTips:'请选择网站显示的色彩模式,以便提供最佳的用户体验',
+	menuSetting:'菜单显示设置',
+	menuTips:'选择左侧Menu在网站载入时的预设显示模式',
+	menuOpen:'预设展开显示',
+	menuClose:'预设关闭显示',
+	defaultSchool:'默认学校',
+	curSchool:'当前学校',
+	courseNum:'课程数',
+	activityNum:'活动数',
+	joinStatus:'提出加入请求',
+	requestStatus:'送出添加邀请',
+	goSchool:'前往学校',
+	agreeJoin:'同意加入',
+	cancelAdd:'取消添加',
+	requestJoin:'申请加入',
+	inputSearch:'输入要搜索的学校名称',
+	modalTip1:'注意',
+	modalTip2:'此举动将使您离开当前学校的 IES5 站台,并前往',
+	modalTip3:'当前页面未保存的资料将会丢失,是否同意此操作?',
+	columnName:'学校名称',
+	columnArea:'地区',
+	columnId:'校代码',
+	columnTool:'操作',
+	modalTip4:'温馨提示',
+	modalTip5:'确认申请加入',
+	submitSucTips:'提交成功',
+	submitFailTips:'操作失败',
+	joinSucTips:'加入成功!',
+	status1:'已加入',
+	status2:'收到邀请',
+	status3:'申请中',
+	
 }
 }

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

@@ -265,6 +265,20 @@ export default {
             "queNo": "题目:",
             "queNo": "题目:",
             "myAns":"我的作答:"
             "myAns":"我的作答:"
         },
         },
+        "report": {
+            "anwser": "前往作答",
+            "noRes": "成绩尚未结算",
+            "getScore": "得分题目数",
+            "answerBack": "评测作答回顾",
+            "right": "答对",
+            "wrong": "答错",
+            "noScore": "未评分",
+            "ansRes": "作答结果",
+            "testAns": "参考答案",
+            "testAnalyse": "解析",
+            "repairSource": "补救资源",
+            "noAnalyse":"暂无解析"
+        },
         "timeoutHint": "评量活动时间已结束,逾时将以0分计算,或等待教师开放补考。",
         "timeoutHint": "评量活动时间已结束,逾时将以0分计算,或等待教师开放补考。",
         "contentPage": "评量内容",
         "contentPage": "评量内容",
         "scorePage": "成绩报告",
         "scorePage": "成绩报告",

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

@@ -74,6 +74,7 @@ export default {
 		field: '關聯認知層次',
 		field: '關聯認知層次',
 		knowledge: '關聯知識點',
 		knowledge: '關聯知識點',
 		choosePoint: '選擇知識點',
 		choosePoint: '選擇知識點',
+		modify:'修改',
 		type: '選擇題型',
 		type: '選擇題型',
 		stem: '題幹',
 		stem: '題幹',
 		option: '選項',
 		option: '選項',

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

@@ -48,7 +48,7 @@ export default {
         evType: '評測類型',
         evType: '評測類型',
         examType: '考試類別',
         examType: '考試類別',
         courseType: '課程類別',
         courseType: '課程類別',
-        cusLable1: '校本課程',
+        cusLabel1: '校本課程',
         cusLabel2: '個人課程',
         cusLabel2: '個人課程',
         evTarget: '施測對象',
         evTarget: '施測對象',
         publishType: '發佈管道',
         publishType: '發佈管道',

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

@@ -154,6 +154,10 @@ export default {
   delClass: '删除班級',
   delClass: '删除班級',
   saveClassWarning: '當前教室數據尚未保存。如果離開,修改的數據將不會保存!',
   saveClassWarning: '當前教室數據尚未保存。如果離開,修改的數據將不會保存!',
   addStuBtn: '添加學生',
   addStuBtn: '添加學生',
-  delStuBtn: '删除學生',
-  editSeat: '修改座號'
+  delStuBtn: '移除學生',
+  editSeat: '修改座號',
+  removeTile: '移除提醒',
+  removeContent: '是否確認移除',
+  removeOk: '移除成功',
+  removeErr: '移除失敗'
 }
 }

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

@@ -1,5 +1,40 @@
 export default {
 export default {
-    setting_title1: '學校管理',
-	setting_title2: '一般設置'
-
+	setting_title1: '學校管理',
+	setting_title2: '一般設定',
+	schoolList: '已添加或申請學校',
+	langSetting: '網站語言設定',
+	langTips: '請選擇網站要用來顯示選單、互動頁面以及通知資訊的語言',
+	langCheck: '使用瀏覽器語系展示',
+	themeSetting: '網站色彩模式',
+	themeTips: '請選擇網站顯示的色彩模式,以便提供最佳的用戶體驗',
+	menuSetting: '選單顯示設定',
+	menuTips: '選擇左側Menu在網站載入時的預設顯示模式',
+	menuOpen: '預設展開顯示',
+	menuClose: '預設關閉顯示',
+	defaultSchool: '默認學校',
+	curSchool: '當前學校',
+	courseNum: '課程數',
+	activityNum: '活動數',
+	joinStatus: '提出加入請求',
+	requestStatus: '送出添加邀請',
+	goSchool: '前往學校',
+	agreeJoin: '同意加入',
+	cancelAdd: '取消添加',
+	requestJoin: '申請加入',
+	inputSearch: '輸入要蒐索的學校名稱',
+	modalTip1: '注意',
+	modalTip2: '此舉動將使您離開當前學校的IES5站臺,並前往',
+	modalTip3: '當前頁面未保存的資料將會遺失,是否同意此操作?',
+	columnName: '學校名稱',
+	columnArea: '地區',
+	columnId: '校程式碼',
+	columnTool: '操作',
+	modalTip4: '溫馨提示',
+	modalTip5: '確認申請加入',
+	submitSucTips: '提交成功',
+	submitFailTips: '操作失敗',
+	joinSucTips: '加入成功!',
+	status1: '已加入',
+	status2: '收到邀請',
+	status3: '申請中',
 }
 }

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

@@ -263,6 +263,20 @@ export default {
             "queNo": "題目:",
             "queNo": "題目:",
             "myAns": "我的作答:"
             "myAns": "我的作答:"
         },
         },
+        "report": {
+            "anwser": "前往作答",
+            "noRes": "成績尚未結算",
+            "getScore": "得分題目數",
+            "answerBack": "評測作答回顧",
+            "right": "答對",
+            "wrong": "答錯",
+            "noScore": "未評分",
+            "ansRes": "作答結果",
+            "testAns": "參考答案",
+            "testAnalyse": "解析",
+            "repairSource": "補救資源",
+            "noAnalyse": "暫無解析"
+        },
         "timeoutHint": "評量活動時間已結束,逾時將以0分計算,或等待教師開放補考。",
         "timeoutHint": "評量活動時間已結束,逾時將以0分計算,或等待教師開放補考。",
         "contentPage": "評量內容",
         "contentPage": "評量內容",
         "scorePage": "成績報告",
         "scorePage": "成績報告",

+ 2 - 0
TEAMModelOS/ClientApp/src/static/Global.js

@@ -5,6 +5,7 @@ import VueI18n from 'vue-i18n'
 const PRIVATE_SPACE = 1024 * 1024 * 1024 * 1 //教师Blob个人空间
 const PRIVATE_SPACE = 1024 * 1024 * 1024 * 1 //教师Blob个人空间
 const SCHOOL_SPACE = 1024 * 1024 * 1024 * 10 //学校Blob空间
 const SCHOOL_SPACE = 1024 * 1024 * 1024 * 10 //学校Blob空间
 const DEFAULT_SCHOOL_CODE = 'SYSTEM_NO_SCHOOL' //尚未归属学校的默认学校编码
 const DEFAULT_SCHOOL_CODE = 'SYSTEM_NO_SCHOOL' //尚未归属学校的默认学校编码
+const BLOB_URL = 'https://teammodelstorage.blob.core.chinacloudapi.cn' //尚未归属学校的默认学校编码
 
 
 //文件类型,对应内容模块Blob目录
 //文件类型,对应内容模块Blob目录
 const CONTENT_TYPES = {
 const CONTENT_TYPES = {
@@ -121,6 +122,7 @@ const GLOBAL = {
 	PRIVATE_SPACE,
 	PRIVATE_SPACE,
 	SCHOOL_SPACE,
 	SCHOOL_SPACE,
 	DEFAULT_SCHOOL_CODE,
 	DEFAULT_SCHOOL_CODE,
+	BLOB_URL,
 	EXAM_TYPE,
 	EXAM_TYPE,
 	EXERCISE_TYPES,
 	EXERCISE_TYPES,
 	EXERCISE_DIFFS,
 	EXERCISE_DIFFS,

+ 0 - 4
TEAMModelOS/ClientApp/src/utils/blobTool.js

@@ -1,6 +1,5 @@
 import { GLOBAL } from '@/static/Global.js';
 import { GLOBAL } from '@/static/Global.js';
 import JsFn from '@/utils/js-fn.js';
 import JsFn from '@/utils/js-fn.js';
-console.log(GLOBAL)
 const { BlobServiceClient, BlobClient } = require("@azure/storage-blob")
 const { BlobServiceClient, BlobClient } = require("@azure/storage-blob")
 //const s = "?sv=2019-12-12&ss=b&srt=sco&st=2020-12-22T10%3A09%3A08Z&se=2020-12-23T10%3A09%3A08Z&sp=rwdxftlacup&sig=EHyNiA5uoBPHQAHfISLei%2BWdWnldHzOYYR7ZYdtFtRo%3D"
 //const s = "?sv=2019-12-12&ss=b&srt=sco&st=2020-12-22T10%3A09%3A08Z&se=2020-12-23T10%3A09%3A08Z&sp=rwdxftlacup&sig=EHyNiA5uoBPHQAHfISLei%2BWdWnldHzOYYR7ZYdtFtRo%3D"
 //获取文件后缀和类型
 //获取文件后缀和类型
@@ -69,12 +68,10 @@ export default class BlobTool {
             this.containerClient.getProperties(options).then(
             this.containerClient.getProperties(options).then(
                 res => {
                 res => {
                     console.log('获取信息成功')
                     console.log('获取信息成功')
-                    console.log(res)
                     r(res)
                     r(res)
                 },
                 },
                 err => {
                 err => {
                     console.log('获取信息失败')
                     console.log('获取信息失败')
-                    console.log(err)
                     j(err)
                     j(err)
                 }
                 }
             )
             )
@@ -203,7 +200,6 @@ export default class BlobTool {
                 if (hendleHTEX) {
                 if (hendleHTEX) {
                     blobList = this.handleHTEXFile(blobList)
                     blobList = this.handleHTEXFile(blobList)
                 }
                 }
-                console.log('----', blobList)
                 r({
                 r({
                     blobList,
                     blobList,
                     continuationToken: 'end'
                     continuationToken: 'end'

+ 5 - 2
TEAMModelOS/ClientApp/src/utils/evTools.js

@@ -28,7 +28,7 @@ export default {
 					explain:item.explain,
 					explain:item.explain,
 					type:item.type,
 					type:item.type,
 					opts:item.option.length,
 					opts:item.option.length,
-					points:item.points,
+					knowledge:item.knowledge,
 					field:item.field,
 					field:item.field,
 					level:item.level,
 					level:item.level,
 					periodId:item.periodId,
 					periodId:item.periodId,
@@ -60,7 +60,7 @@ export default {
 				score:0,
 				score:0,
 				type:item.type,
 				type:item.type,
 				question:this.getSimpleText(item.question),
 				question:this.getSimpleText(item.question),
-				points:item.points,
+				knowledge:item.knowledge,
 				field:item.field,
 				field:item.field,
 				level:item.level,
 				level:item.level,
 				periodId:item.periodId,
 				periodId:item.periodId,
@@ -155,6 +155,9 @@ export default {
 			Promise.all(promiseArr).then(result => {
 			Promise.all(promiseArr).then(result => {
 				console.log('从Blob获取来的试题',result)
 				console.log('从Blob获取来的试题',result)
 				resolve(result)
 				resolve(result)
+			}).catch(err => {
+				Message.error('有试题文件读取失败')
+				reject(err)
 			})
 			})
 		})
 		})
 	},
 	},

+ 2 - 2
TEAMModelOS/ClientApp/src/utils/public.js

@@ -618,7 +618,7 @@ export default {
 		let result = []
 		let result = []
 		val.students.forEach(stu => {
 		val.students.forEach(stu => {
 			result.push([
 			result.push([
-				stu.id,
+				stu.name,
 				stu.className,
 				stu.className,
 				stu.no || '-',
 				stu.no || '-',
 				val.fScores[subjectIndex].Value[index],
 				val.fScores[subjectIndex].Value[index],
@@ -660,7 +660,7 @@ export default {
 		let result = []
 		let result = []
 		val.students.forEach(stu => {
 		val.students.forEach(stu => {
 			result.push([
 			result.push([
-				stu.id,
+				stu.name,
 				stu.className,
 				stu.className,
 				stu.no || '-',
 				stu.no || '-',
 				val.kScores[subjectIndex].Value[index],
 				val.kScores[subjectIndex].Value[index],

+ 2 - 2
TEAMModelOS/ClientApp/src/view/evaluation/bank/ExerciseList.vue

@@ -143,9 +143,9 @@
 							<div class="item-explain">
 							<div class="item-explain">
 								<span class="explain-title">【{{$t('evaluation.knowledgePoints')}}】</span>
 								<span class="explain-title">【{{$t('evaluation.knowledgePoints')}}】</span>
 								<div class="item-explain-details">
 								<div class="item-explain-details">
-									<span v-if="!item.points.length">{{$t('evaluation.noPoints')}}</span>
+									<span v-if="!item.knowledge || !item.knowledge.length">{{$t('evaluation.noPoints')}}</span>
 									<div v-else>
 									<div v-else>
-										<span v-for="(point, index) in item.points" class="item-point-tag" :key="index">
+										<span v-for="(point, index) in item.knowledge" class="item-point-tag" :key="index">
 											{{ point }}
 											{{ point }}
 										</span>
 										</span>
 									</div>
 									</div>

+ 2 - 2
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseChild.vue

@@ -48,9 +48,9 @@
 			<div class="item-explain">
 			<div class="item-explain">
 				<span class="explain-title">【{{$t('evaluation.knowledgePoints')}}】</span>
 				<span class="explain-title">【{{$t('evaluation.knowledgePoints')}}】</span>
 				<div class="item-explain-details">
 				<div class="item-explain-details">
-					<span v-if="!item.points || !item.points.length">{{$t('evaluation.noPoints')}}</span>
+					<span v-if="!item.knowledge || !item.knowledge.length">{{$t('evaluation.noPoints')}}</span>
 					<div v-else>
 					<div v-else>
-						<span v-for="(point,index) in item.points" :key="index" class="item-point-tag">
+						<span v-for="(point,index) in item.knowledge" :key="index" class="item-point-tag">
 							<span>{{ point }}</span>
 							<span>{{ point }}</span>
 						</span>
 						</span>
 					</div>
 					</div>

+ 9 - 5
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseCreateChild.vue

@@ -65,7 +65,7 @@
 		<!-- 补救的富文本部分 -->
 		<!-- 补救的富文本部分 -->
 		<div class="exersices-analysis" v-show="exersicesType !== 'compose'">
 		<div class="exersices-analysis" v-show="exersicesType !== 'compose'">
 			<IconText :text="$t('evaluation.newExercise.repair')" :color="'#2892DD'" :icon="'md-link'" style="margin-bottom: 10px"></IconText>
 			<IconText :text="$t('evaluation.newExercise.repair')" :color="'#2892DD'" :icon="'md-link'" style="margin-bottom: 10px"></IconText>
-			<BaseRepair ref="repairRef" :datas="editInfo.repair"></BaseRepair>
+			<BaseRepair ref="repairRef" :repairs="editInfo.repair"></BaseRepair>
 		</div>
 		</div>
 
 
 		<div class="save-wrap display-flex">
 		<div class="save-wrap display-flex">
@@ -279,7 +279,7 @@
 					this.$refs.repairRef.datas
 					this.$refs.repairRef.datas
 				);
 				);
 				exerciseItem.field = this.exerciseField + 1;
 				exerciseItem.field = this.exerciseField + 1;
-				exerciseItem.points = this.exercisePoints;
+				exerciseItem.knowledge = this.exercisePoints;
 				exerciseItem.code =
 				exerciseItem.code =
 					this.$parent.$parent.exerciseScope === 0 ?
 					this.$parent.$parent.exerciseScope === 0 ?
 					this.$store.state.userInfo.TEAMModelId :
 					this.$store.state.userInfo.TEAMModelId :
@@ -341,9 +341,13 @@
 				if (list.length) {
 				if (list.length) {
 					let arr = [];
 					let arr = [];
 					list.forEach((i, index) => {
 					list.forEach((i, index) => {
-						if (this.$tools.isURL(i.blobUrl)) {
-							arr.push(i);
-						}
+						i.blobUrl.forEach(j => {
+							arr.push({
+								blobUrl:j.url,
+								name:i.name,
+								type:i.type
+							})
+						})
 					});
 					});
 					return arr;
 					return arr;
 				} else {
 				} else {

+ 9 - 5
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseEditExercise.vue

@@ -93,7 +93,7 @@
 		<!-- 补救的富文本部分 -->
 		<!-- 补救的富文本部分 -->
 		<div class="exersices-analysis" v-show="exersicesType !== 'compose'">
 		<div class="exersices-analysis" v-show="exersicesType !== 'compose'">
 			<IconText :text="$t('evaluation.newExercise.repair')" :color="'#2892DD'" :icon="'md-link'" style="margin-bottom: 10px"></IconText>
 			<IconText :text="$t('evaluation.newExercise.repair')" :color="'#2892DD'" :icon="'md-link'" style="margin-bottom: 10px"></IconText>
-			<BaseRepair ref="repairRef" :datas="repairResource || []"></BaseRepair>
+			<BaseRepair ref="repairRef" :rapairs="repairResource || []"></BaseRepair>
 		</div>
 		</div>
 
 
 		<!-- 小题展示区域 -->
 		<!-- 小题展示区域 -->
@@ -320,7 +320,7 @@
 					this.$refs.repairRef.datas
 					this.$refs.repairRef.datas
 				);
 				);
 				exerciseItem.field = this.exerciseField + 1;
 				exerciseItem.field = this.exerciseField + 1;
-				exerciseItem.points = this.exercisePoints;
+				exerciseItem.knowledge = this.exercisePoints;
 				exerciseItem.periodId = this.isSchool ?
 				exerciseItem.periodId = this.isSchool ?
 					this.schoolInfo.period[this.exercisePeriod].id :
 					this.schoolInfo.period[this.exercisePeriod].id :
 					null;
 					null;
@@ -568,9 +568,13 @@
 				if (list.length) {
 				if (list.length) {
 					let arr = [];
 					let arr = [];
 					list.forEach((i, index) => {
 					list.forEach((i, index) => {
-						if (this.$tools.isURL(i.blobUrl)) {
-							arr.push(i);
-						}
+						i.blobUrl.forEach(j => {
+							arr.push({
+								blobUrl:j.url,
+								name:i.name,
+								type:i.type
+							})
+						})
 					});
 					});
 					return arr;
 					return arr;
 				} else {
 				} else {

+ 6 - 2
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseExerciseList.vue

@@ -111,9 +111,9 @@
 								<div class="item-explain" v-show="isShowAnswer">
 								<div class="item-explain" v-show="isShowAnswer">
 									<span class="explain-title">【{{$t('evaluation.knowledgePoints')}}】</span>
 									<span class="explain-title">【{{$t('evaluation.knowledgePoints')}}】</span>
 									<div class="item-explain-details">
 									<div class="item-explain-details">
-										<span v-if="! (_.compact(item.points).length)">{{$t('evaluation.noPoints')}}</span>
+										<span v-if="!item.knowledge || !(_.compact(item.knowledge).length)">{{$t('evaluation.noPoints')}}</span>
 										<div v-else>
 										<div v-else>
-											<span v-for="(point,index) in item.points" :key="index" class="item-point-tag">
+											<span v-for="(point,index) in item.knowledge" :key="index" class="item-point-tag">
 												{{ point }}
 												{{ point }}
 											</span>
 											</span>
 										</div>
 										</div>
@@ -672,6 +672,10 @@
 						if (newPaper.item.length) {
 						if (newPaper.item.length) {
 							newPaper.item.forEach(i => {
 							newPaper.item.forEach(i => {
 								if (!i.score) i.score = 0
 								if (!i.score) i.score = 0
+								// 如果有综合题 则将小题的分数进行累加作为综合题的分数
+								if(i.type === 'compose' && i.children.length){
+									i.score = i.children.reduce((a,b) => a + b.score , 0)
+								}
 							})
 							})
 							this.orderList.push({
 							this.orderList.push({
 								list: newPaper.item
 								list: newPaper.item

+ 12 - 26
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseImport.vue

@@ -71,7 +71,7 @@
             }
             }
         },
         },
         created() {
         created() {
-            this.uploadUrl = window.location.origin  + '/import/upload-word'
+            this.uploadUrl = window.location.origin  + '/import/parse-word '
 			this.curLang = localStorage.getItem('local')
 			this.curLang = localStorage.getItem('local')
 			this.hostName = this.$store.state.privateSas ? this.$store.state.privateSas.url : 'https://teammodelstorage.blob.core.chinacloudapi.cn'
 			this.hostName = this.$store.state.privateSas ? this.$store.state.privateSas.url : 'https://teammodelstorage.blob.core.chinacloudapi.cn'
         },
         },
@@ -103,12 +103,12 @@
 			/* 下载模板制作详情说明文件 */
 			/* 下载模板制作详情说明文件 */
 			onDownloadDetails(){
 			onDownloadDetails(){
 				const downloadRes = async () => {
 				const downloadRes = async () => {
-				      let response = await fetch(this.hostName + '/download/%E6%A8%A1%E6%9D%BF%E5%88%B6%E4%BD%9C%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9.txt'); // 内容转变成blob地址
+				      let response = await fetch(this.hostName + '/download/IES5%E8%AF%95%E5%8D%B7%E6%A8%A1%E6%9D%BF%E5%88%B6%E4%BD%9C%E8%AF%B4%E6%98%8E%EF%BC%88%E7%BB%88%EF%BC%89.pdf'); // 内容转变成blob地址
 				      let blob = await response.blob();  // 创建隐藏的可下载链接
 				      let blob = await response.blob();  // 创建隐藏的可下载链接
 				      let objectUrl = window.URL.createObjectURL(blob);
 				      let objectUrl = window.URL.createObjectURL(blob);
 				      let a = document.createElement('a');
 				      let a = document.createElement('a');
 				      a.href = objectUrl;
 				      a.href = objectUrl;
-				      a.download = '模板制作注意事项.txt';
+				      a.download = 'IES5试卷导入模板制作说明.pdf';
 				      a.click()
 				      a.click()
 				      a.remove(); 
 				      a.remove(); 
 				   }
 				   }
@@ -163,30 +163,16 @@
              * @param response
              * @param response
              */
              */
             uploadSuccess(response) {
             uploadSuccess(response) {
-                if (response.htmlString) {
-                    let requestData = { lang:localStorage.getItem('local'), htmlString: response.htmlString }
-                    this.$api.SaveAnalyzeHtml(requestData).then(res => {
-                        if (!res.error) {
-							if(res.length){
-								this.$Message.success(this.$t('evaluation.importFile.warningTips3'))
-								this.$emit('importFinish',res)
-								this.isImportFinish = false
-								this.isBtnLoading = false
-								this.exerciseList = []
-							}else{
-								this.$Message.error(this.$t('evaluation.importFile.warningTips4'))
-								this.isBtnLoading = false
-							}
-                                
-                        }else{
-							this.$Message.error(this.$t('evaluation.importFile.warningTips5'))
-							this.isBtnLoading = false
-						}
-                    })
-                } else {
-                    this.$Message.error(this.$t('evaluation.importFile.warningTips5'))
+				if(Array.isArray(response) && response.length){
+					this.$Message.success(this.$t('evaluation.importFile.warningTips3'))
+					this.$emit('importFinish',response)
+					this.isImportFinish = false
 					this.isBtnLoading = false
 					this.isBtnLoading = false
-                }
+					this.exerciseList = []
+				}else{
+					this.$Message.error(this.$t('evaluation.importFile.warningTips4'))
+					this.isBtnLoading = false
+				}
 				this.isSelectFinish = false
 				this.isSelectFinish = false
             },
             },
         },
         },

+ 5 - 8
TEAMModelOS/ClientApp/src/view/evaluation/components/BasePointPie.vue

@@ -78,15 +78,12 @@
 					tempArr.push(i)
 					tempArr.push(i)
 				}
 				}
 			})
 			})
-			let typeList = this._.groupBy(tempArr, 'points')
-			console.log(typeList)
+			let typeList = this._.groupBy(tempArr, 'knowledge')
 			for (let key in typeList) {
 			for (let key in typeList) {
-				if (key !== ''){
-					arr.push({
-						value: typeList[key].length,
-						name: key
-					})
-				}
+				arr.push({
+					value: typeList[key].length,
+					name: key === 'undefined' || !key ?  '未绑定知识点' : key
+				})
 			}
 			}
 			this.drawLine(arr)
 			this.drawLine(arr)
 		},
 		},

+ 194 - 57
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseRepair.vue

@@ -1,39 +1,48 @@
 <template>
 <template>
 	<div class="repair-wrap">
 	<div class="repair-wrap">
-		<Tabs :animated="false" name="repairTab">
-			<TabPane :label="$t('evaluation.newExercise.outRepair')" tab="repairTab">
-				<Button type="info" @click="onAddLink('normal')" v-show="datas.filter(i => i.type !== 'file').length === 0">{{$t('evaluation.newExercise.addLink')}}</Button>
+		<Tabs :animated="false" name="repairTab" v-model="curTab">
+			<TabPane :label="$t('evaluation.newExercise.innerRepair')" tab="repairTab" name="site">
+				<Button type="info" @click="onAddLink('site')">{{$t('evaluation.newExercise.chooseContent')}}</Button>
+				<div class="repair-link-wrap-item" v-for="(item,index) in datas.filter(i => i.type === 'file')" :key="index">
+						<div class="repair-link-wrap-item-box">
+							<p>资源描述:{{ item.name }}</p>
+							<div style="display: flex;">
+								<span>资源链接:</span>
+								<div>
+									<p v-for="(url,urlIndex) in item.blobUrl" :key="urlIndex">
+										<span>{{ url.url }}</span>
+									</p>
+								</div>
+							</div>
+							<div class="repair-link-tools">
+								<span @click="onEditRepair(item,index)">编辑</span>
+								<span @click="onDeleteRepair(item)">删除</span>
+							</div>
+						</div>
+				</div>
+			</TabPane>
+			<TabPane :label="$t('evaluation.newExercise.outRepair')" tab="repairTab" name="outer">
+				<Button type="info" @click="onAddLink('normal')">{{$t('evaluation.newExercise.addLink')}}</Button>
 				<div class="repair-link-wrap">
 				<div class="repair-link-wrap">
 					<div class="repair-link-wrap-item" v-for="(item,index) in datas.filter(i => i.type !== 'file')" :key="index">
 					<div class="repair-link-wrap-item" v-for="(item,index) in datas.filter(i => i.type !== 'file')" :key="index">
 							<div class="repair-link-wrap-item-box">
 							<div class="repair-link-wrap-item-box">
-								<Input v-model="item.blobUrl" @on-change="onInputChange">
-								<Select v-model="item.type" slot="prepend" style="width: 120px">
-									<Option value="normal"><Icon type="ios-link" size="18"/>{{$t('evaluation.newExercise.normalResource')}}</Option>
-									<Option value="video"><Icon type="ios-videocam" size="18"/>{{$t('evaluation.newExercise.mediaResource')}}</Option>
-								</Select>
-								</Input>
-								<span class="flex-row-center" style="margin-left: 10px;">
-									<Icon type="md-add" color="#00aa3c" v-if="index === 0" @click="onAddLink('normal')"/>
-									<Icon type="md-close" color="#ff0000" size="24" @click="onDeleteLink(item)"/>
-								</span>
+								<p>资源描述:{{ item.name }}</p>
+								<div style="display: flex;">
+									<span>资源链接:</span>
+									<div>
+										<p v-for="(url,urlIndex) in item.blobUrl" :key="urlIndex">
+											<span>{{ url.url }}</span>
+										</p>
+									</div>
+								</div>
+								<div class="repair-link-tools">
+									<span @click="onEditRepair(item,index)">编辑</span>
+									<span @click="onDeleteRepair(item)">删除</span>
+								</div>
 							</div>
 							</div>
-							<p class="error-tip" v-show="!isURL(item.blobUrl)">{{$t('evaluation.newExercise.linkTip')}}</p>
 					</div>
 					</div>
 				</div>
 				</div>
 			</TabPane>
 			</TabPane>
-			<TabPane :label="$t('evaluation.newExercise.innerRepair')" tab="repairTab">
-				<Button type="info" @click="isRelatedContent = true">{{$t('evaluation.newExercise.chooseContent')}}</Button>
-				<div class="repair-link-wrap-item" v-for="(item,index) in datas.filter(i => i.type === 'file')" :key="index">
-						<div class="repair-link-wrap-item-box">
-							<Input v-model="item.blobUrl" @on-change="onInputChange"/>
-							<span class="flex-row-center" style="margin-left: 10px;">
-								<!-- <Icon type="md-add" color="#00aa3c" v-if="index === 0" @click="onAddLink('normal')"/> -->
-								<Icon type="md-close" color="#ff0000" size="24" @click="onDeleteLink(item)"/>
-							</span>
-						</div>
-						<p class="error-tip" v-show="!isURL(item.blobUrl)">{{$t('evaluation.newExercise.linkTip')}}</p>
-				</div>
-			</TabPane>
 		</Tabs>
 		</Tabs>
 		
 		
 		<!-- 关联内容弹窗 -->
 		<!-- 关联内容弹窗 -->
@@ -42,12 +51,40 @@
 		    <NewChooseContent :showSyllabus="isFalse"
 		    <NewChooseContent :showSyllabus="isFalse"
 		                   :showOther="isFalse"
 		                   :showOther="isFalse"
 		                   :showQuestion="isFalse"
 		                   :showQuestion="isFalse"
-						   :defaultFiles="relateFileList"
+						   :defaultFiles="curRepair.blobUrl"
 						   ref="chooseContentRef"
 						   ref="chooseContentRef"
 		                   @on-file-change="onSelectFile"></NewChooseContent>
 		                   @on-file-change="onSelectFile"></NewChooseContent>
 		
 		
 		    <Button class="modal-btn" :loading="isLoading" @click="onConfirmRelate">{{$t('evaluation.confirm')}}</Button>
 		    <Button class="modal-btn" :loading="isLoading" @click="onConfirmRelate">{{$t('evaluation.confirm')}}</Button>
 		</Modal>
 		</Modal>
+		
+		<!-- 添加补救资源弹窗 -->
+		<Modal v-model="isAddRepair" width="600" footer-hide>
+		    <div class="modal-header" slot="header">添加补救资源</div>
+			<p style="margin: 15px 2px;">资源类型</p>
+			<Select v-model="curRepair.type" :disabled="isSiteLink">
+				<Option value="normal">{{$t('evaluation.newExercise.normalResource')}}</Option>
+				<Option value="file">{{$t('evaluation.newExercise.mediaResource')}}</Option>
+			</Select>
+			<p style="margin: 15px 2px;">资源描述</p>
+		    <Input v-model="curRepair.name" placeholder="请输入资源描述..."/>
+			<p style="margin: 15px 2px;">资源链接地址</p>
+			
+			<!-- 选择内容 -->
+			<Button type="info" @click="isRelatedContent = true" v-if="isSiteLink">{{$t('evaluation.newExercise.chooseContent')}}</Button>
+			<!-- 手动输入 -->
+			<Input v-model="curOutLink" v-if="!isSiteLink" placeholder="请输入资源地址,回车即可添加" @on-enter="onAddOutLink"/>
+			<!-- 链接link列表 -->
+			<div>
+				<p v-for="(item,index) in curRepair.blobUrl" class="repair-link-item">
+					<span>{{ item.url }}</span>
+					<Icon type="md-close" size="18" @click="onDeleteRelateLink(item)"/>
+				</p>
+			</div>
+			<!-- 确认 -->
+			<Button type="success" @click="onAddRepair" style="margin-top: 20px;width: 100%;height: 38px;">确认</Button>
+			
+		</Modal>
 	</div>
 	</div>
 </template>
 </template>
 <script>
 <script>
@@ -56,7 +93,7 @@
 		name:'BaseRepair',
 		name:'BaseRepair',
 		components: { NewChooseContent },
 		components: { NewChooseContent },
 		props: {
 		props: {
-			datas: {
+			rapairs: {
 				type: Array,
 				type: Array,
 				default: function() {
 				default: function() {
 					return []
 					return []
@@ -65,54 +102,97 @@
 		},
 		},
 		data() {
 		data() {
 			return {
 			return {
+				datas:[],
+				curTab:'site',
+				curEditIndex:null,
+				curOutLink:'',
+				isAddRepair:false,
 				isLoading:false,
 				isLoading:false,
+				isSiteLink:true,
 				isRelatedContent:false,
 				isRelatedContent:false,
 				isFalse:false,
 				isFalse:false,
-				relateFileList:[]
+				relateFileList:[],
+				defaultFiles:[],
+				curRepair:{
+					type:'file',
+					name:'',
+					blobUrl:[]
+				}
 			}
 			}
 		},
 		},
 		created() {
 		created() {
 			
 			
 		},
 		},
 		methods: {
 		methods: {
+			/* 点击添加外部或者内部资源 */
 			onAddLink(type){
 			onAddLink(type){
-				let addObj = {
-					blobUrl:'',
-					type:type
+				this.isSiteLink = type === 'site'
+				this.curEditIndex = null
+				this.curRepair.name = ''
+				this.curRepair.type = type === 'site' ? 'file' : 'normal'
+				this.curRepair.blobUrl = []
+				this.isAddRepair = true
+				this.defaultFiles = []
+			},
+			
+			/* 回车添加外部资源链接 */
+			onAddOutLink(){
+				if(this.isURL(this.curOutLink)){
+					if(this.curRepair.blobUrl.map(i => i.url).indexOf(this.curOutLink) > -1){
+						this.$Message.warning('已存在相同链接!')
+					}else{
+						this.curRepair.blobUrl.push({
+							url:this.curOutLink
+						})
+						this.curOutLink = ''
+					}
+				}else{
+					this.$Message.warning('请输入正确格式的网址地址!')
 				}
 				}
-				this.datas.push(addObj)
+				
 			},
 			},
 			
 			
-			onDeleteLink(item){
-				let index = this.datas.indexOf(item)
-				this.datas.splice(index,1)
-				if(item.type === 'file'){
-					let urlArr = this.relateFileList.map(i => i.url)
-					this.relateFileList.splice(urlArr.indexOf(item.blobUrl),1)
+			/* 点击添加资源 */
+			onAddRepair(){
+				if(this.curRepair.name.trim() === '' || this.curRepair.blobUrl.length === 0){
+					this.$Message.warning('请填写完整!')
+				}else{
+					if(this.curEditIndex || this.curEditIndex === 0){
+						this.datas[this.curEditIndex] = JSON.parse(JSON.stringify(this.curRepair))
+					}else{
+						this.datas.push(JSON.parse(JSON.stringify(this.curRepair)))
+					}
+					this.isAddRepair = false
 				}
 				}
-				console.log(this.relateFileList.map(i => i.url))
 			},
 			},
 			
 			
-			onInputChange(val){
-				// console.log(val)
+			/* 编辑当前补救资源 */
+			onEditRepair(item,index){
+				this.isSiteLink = this.curTab === 'site'
+				this.curRepair = JSON.parse(JSON.stringify(item))
+				this.isAddRepair = true
+				this.curEditIndex = this.datas.indexOf(item)
+				this.defaultFiles = this.curTab === 'site' ? this.curRepair.blobUrl : []
+			},
+			
+			/* 删除当前补救资源 */
+			onDeleteRepair(item){
+				this.datas.splice(this.datas.indexOf(item),1)
 			},
 			},
 			
 			
+			/* 删除某个链接地址LINK */
+			onDeleteRelateLink(item){
+				this.curRepair.blobUrl.splice(this.curRepair.blobUrl.indexOf(item),1)
+				this.defaultFiles = this.curRepair.blobUrl
+			},
+			
+			/* 选择内容联动 */
 			onSelectFile(val) {
 			onSelectFile(val) {
 			    this.relateFileList = val.files
 			    this.relateFileList = val.files
+				this.curRepair.blobUrl = val.files
 			},
 			},
 			
 			
 			onConfirmRelate() {
 			onConfirmRelate() {
-				this.relateFileList.forEach(i => {
-					if(this.datas.length && this.datas.map(i => i.blobUrl).includes(i.url)){
-						return
-					}else{
-						this.datas.push({
-							blobUrl:i.url,
-							type:'file'
-						})
-					}
-					
-				})
 			    this.isRelatedContent = false
 			    this.isRelatedContent = false
 			},
 			},
 			
 			
@@ -142,7 +222,33 @@
 			if(this.$refs.chooseContentRef){
 			if(this.$refs.chooseContentRef){
 				this.$refs.chooseContentRef.clickTab('content')
 				this.$refs.chooseContentRef.clickTab('content')
 			}
 			}
+
 		},
 		},
+		watch:{
+			rapairs:{
+				handler(val){
+					/* 转换补救资源格式 根据描述 汇总分组 */
+					let namesArr = [...new Set(val.map(i => i.name))]
+					let result = []
+					namesArr.forEach(name => {
+						let urls = []
+						let type = ''
+						val.forEach(i => {
+							if(i.name === name){
+								urls.push({ url:i.blobUrl })
+								type = i.type
+							}
+						})
+						result.push({
+							name:name,
+							blobUrl:urls,
+							type:type
+						})
+					})
+					this.datas = result
+				}
+			}
+		}
 	}
 	}
 </script>
 </script>
 
 
@@ -159,6 +265,23 @@
 </style>
 </style>
 
 
 <style lang="less" scoped>
 <style lang="less" scoped>
+	
+	.repair-link-item{
+		margin: 10px 0;
+		padding: 4px 5px;
+		background: #a7a7a7;
+		color: #fff;
+		border-radius: 4px;
+		word-break: break-all;
+		
+		.ivu-icon{
+			margin: 5px 10px;
+			vertical-align: sub;
+			color: red;
+			font-weight: bold;
+		}
+	}
+	
 	.repair-wrap {
 	.repair-wrap {
 		min-height: 300px;
 		min-height: 300px;
 		
 		
@@ -168,10 +291,24 @@
 			&-item{
 			&-item{
 				margin: 20px 0;
 				margin: 20px 0;
 				
 				
-				
 				&-box{
 				&-box{
-					display: flex;
-					align-items: center;
+					position: relative;
+					border: 2px dashed #aaaaaa;
+					background-color: #ebf9ff;
+					border-radius: 5px;
+					padding: 10px;
+					font-size: 16px;
+					
+					.repair-link-tools{
+						position: absolute;
+						right: 20px;
+						top: 40%;
+						
+						span{
+							margin-right: 20px;
+							cursor: pointer;
+						}
+					}
 				}
 				}
 				
 				
 				.ivu-icon{
 				.ivu-icon{

+ 8 - 4
TEAMModelOS/ClientApp/src/view/evaluation/index/CreateExercises.vue

@@ -327,7 +327,7 @@
 				}
 				}
 				exerciseItem.repair = this.formatRepairResource(this.$refs.repairRef.datas);
 				exerciseItem.repair = this.formatRepairResource(this.$refs.repairRef.datas);
 				exerciseItem.field = this.exerciseField + 1;
 				exerciseItem.field = this.exerciseField + 1;
-				exerciseItem.points = this.exercisePoints;
+				exerciseItem.knowledge = this.exercisePoints; //新知识点
 				exerciseItem.periodId = this.isSchool ? this.schoolInfo.period[this.exercisePeriod].id : null;
 				exerciseItem.periodId = this.isSchool ? this.schoolInfo.period[this.exercisePeriod].id : null;
 				exerciseItem.gradeIds = this.isSchool ?
 				exerciseItem.gradeIds = this.isSchool ?
 					this.exerciseGrade.length ?
 					this.exerciseGrade.length ?
@@ -506,9 +506,13 @@
 				if (list.length) {
 				if (list.length) {
 					let arr = [];
 					let arr = [];
 					list.forEach((i, index) => {
 					list.forEach((i, index) => {
-						if (this.$tools.isURL(i.blobUrl)) {
-							arr.push(i);
-						}
+						i.blobUrl.forEach(j => {
+							arr.push({
+								blobUrl:j.url,
+								name:i.name,
+								type:i.type
+							})
+						})
 					});
 					});
 					return arr;
 					return arr;
 				} else {
 				} else {

+ 6 - 7
TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue

@@ -274,7 +274,7 @@
 							})
 							})
 						}
 						}
 						// 如果导入的是客观题 则需要检测答案与选项是否为空
 						// 如果导入的是客观题 则需要检测答案与选项是否为空
-						if (objectiveTypes.includes(i.type) && (!i.question.replace(/\s*/g, "") || !i.option.length || !i.answer.length)) {
+						if (objectiveTypes.includes(i.type) && (!i.question.replace(/\s*/g, "") || !i.option.length || !i.answer.length || !i.option || !i.answer)) {
 							this.errorList.push(i)
 							this.errorList.push(i)
 						}
 						}
 					}
 					}
@@ -478,7 +478,7 @@
 								type: item.type,
 								type: item.type,
 								scoring: {
 								scoring: {
 									score: item.score,
 									score: item.score,
-									knowledge: item.points || [],
+									knowledge: item.knowledge || [],
 									field: item.field || 1,
 									field: item.field || 1,
 									ans: nullType.includes(item.type) ? [] : item.answer
 									ans: nullType.includes(item.type) ? [] : item.answer
 								}
 								}
@@ -774,11 +774,10 @@
 
 
 								let item = res.files[i]
 								let item = res.files[i]
 								if (item.scope == 'school') {
 								if (item.scope == 'school') {
-									containerClient.copyFolder('paper/' + paperItem.name + '/', 'item/' + item.id, schoolBlob)
+									containerClient.copyFolder('paper/' + paperItem.name + '/', 'item/' + item.id, schoolBlob).then(res => { r(200) })
 								} else {
 								} else {
-									containerClient.copyFolder('paper/' + paperItem.name + '/', 'item/' + item.id, privateBlob)
+									containerClient.copyFolder('paper/' + paperItem.name + '/', 'item/' + item.id, privateBlob).then(res => { r(200) })
 								}
 								}
-								r(200)
 							}))
 							}))
 
 
 
 
@@ -857,8 +856,8 @@
 			getPaperPoints(items) {
 			getPaperPoints(items) {
 				let arr = []
 				let arr = []
 				items.forEach((i, index) => {
 				items.forEach((i, index) => {
-					if (i.points) {
-						arr = arr.concat(i.points)
+					if (i.knowledge) {
+						arr = arr.concat(i.knowledge)
 					}
 					}
 				})
 				})
 				return arr
 				return arr

+ 3 - 3
TEAMModelOS/ClientApp/src/view/learnactivity/CreatePrivEva.vue

@@ -30,8 +30,8 @@
                             </FormItem>
                             </FormItem>
                             <FormItem :label="$t('learnActivity.createEv.courseType')" prop="course">
                             <FormItem :label="$t('learnActivity.createEv.courseType')" prop="course">
                                 <Select v-model="evaluationInfo.scope" @on-change="resetCourse">
                                 <Select v-model="evaluationInfo.scope" @on-change="resetCourse">
-                                    <Option value="teacher">{{$t('learnActivity.createEv.cusLable1')}}</Option>
-                                    <Option value="private">{{$t('learnActivity.createEv.cusLable2')}}</Option>
+                                    <Option value="teacher">{{$t('learnActivity.createEv.cusLabel1')}}</Option>
+                                    <Option value="private">{{$t('learnActivity.createEv.cusLabel2')}}</Option>
                                 </Select>
                                 </Select>
                             </FormItem>
                             </FormItem>
                             <!-- 使用级联选择 课程--》班级 -->
                             <!-- 使用级联选择 课程--》班级 -->
@@ -333,7 +333,7 @@ export default {
             let simplePaper = data
             let simplePaper = data
             this.$Modal.confirm({
             this.$Modal.confirm({
                 title: this.$t('learnActivity.createEv.stPaperTitle'),
                 title: this.$t('learnActivity.createEv.stPaperTitle'),
-                content: `${$t('learnActivity.createEv.stPaperContent')}${data.name}?`,
+                content: `${this.$t('learnActivity.createEv.stPaperContent')}${data.name}?`,
                 onOk: async () => {
                 onOk: async () => {
                     let fullPaper = await this.$evTools.getFullPaper(simplePaper)
                     let fullPaper = await this.$evTools.getFullPaper(simplePaper)
                     this.comfirmSelectPaper(simplePaper, fullPaper)
                     this.comfirmSelectPaper(simplePaper, fullPaper)

+ 15 - 17
TEAMModelOS/ClientApp/src/view/learnactivity/CreateSchoolEva.vue

@@ -23,8 +23,8 @@
                                     <Option v-for="(item,index) in $store.state.user.schoolProfile.periods" :value="item.id" :key="index">{{ item.name }}</Option>
                                     <Option v-for="(item,index) in $store.state.user.schoolProfile.periods" :value="item.id" :key="index">{{ item.name }}</Option>
                                 </Select>
                                 </Select>
                             </FormItem>
                             </FormItem>
-                            <FormItem :label="$t('learnActivity.createEv.evMode')" prop="evaType">
-                                <Select v-model="evaluationInfo.evaType">
+                            <FormItem :label="$t('learnActivity.createEv.evMode')" prop="source">
+                                <Select v-model="evaluationInfo.source">
                                     <Option v-for="(item,index) in $GLOBAL.EV_MODE()" :value="item.value" :key="index">{{ item.label }}</Option>
                                     <Option v-for="(item,index) in $GLOBAL.EV_MODE()" :value="item.value" :key="index">{{ item.label }}</Option>
                                 </Select>
                                 </Select>
                             </FormItem>
                             </FormItem>
@@ -192,7 +192,7 @@ export default {
                 'type.id': [
                 'type.id': [
                     { required: true, message: this.$t('learnActivity.createEv.errTips2'), trigger: 'change' }
                     { required: true, message: this.$t('learnActivity.createEv.errTips2'), trigger: 'change' }
                 ],
                 ],
-                evaType: [
+                source: [
                     { required: true, message: this.$t('learnActivity.createEv.errTips3'), trigger: 'change' }
                     { required: true, message: this.$t('learnActivity.createEv.errTips3'), trigger: 'change' }
                 ],
                 ],
                 'period.id': [
                 'period.id': [
@@ -228,7 +228,7 @@ export default {
                 targetClassIds: [],
                 targetClassIds: [],
                 grades: [],
                 grades: [],
                 type: '',  //测试类别
                 type: '',  //测试类别
-                evaType: '',
+                source: '',
                 publish: '0',
                 publish: '0',
                 subjects: [],
                 subjects: [],
                 subjectIds: [],
                 subjectIds: [],
@@ -579,7 +579,7 @@ export default {
                 examType: this.evaluationInfo.examType,
                 examType: this.evaluationInfo.examType,
                 year: new Date().getFullYear(),
                 year: new Date().getFullYear(),
                 range: this.mode,
                 range: this.mode,
-                source: this.evaluationInfo.evaType,
+                source: this.evaluationInfo.source,
                 targetClassIds: this.evaluationInfo.targetClassIds,
                 targetClassIds: this.evaluationInfo.targetClassIds,
                 publish: this.evaluationInfo.publish,
                 publish: this.evaluationInfo.publish,
                 startTime: this.evaluationInfo.publish == 0 ? Math.round(new Date()) : this.evaluationInfo.startTime,
                 startTime: this.evaluationInfo.publish == 0 ? Math.round(new Date()) : this.evaluationInfo.startTime,
@@ -701,23 +701,21 @@ export default {
         if (this.$route.name == 'createSchoolEva') {
         if (this.$route.name == 'createSchoolEva') {
             this.mode = 'school'
             this.mode = 'school'
         }
         }
-        //创建个人和校本已经分开,个人相关逻辑代码可是删除
-        // else {
-        //     this.mode = 'private'
-        //     this.findPrivClass() 
-        // }
 
 
         //编辑评测逻辑(暂时注释)
         //编辑评测逻辑(暂时注释)
-        //let routerData = this.$route.params.evaluationInfo
-        //if (routerData !== undefined) {
-        //    this.evaluationInfo.startTime = new Date(routerData.startTime)
-        //    this.evaluationInfo.endTime = new Date(routerData.endTime)
+        let routerData = this.$route.params.evaluationInfo
+        console.log(routerData)
+        if (routerData !== undefined) {
+           routerData.startTime = new Date(routerData.startTime)
+           routerData.endTime = new Date(routerData.endTime)
+           routerData.paperInfo = []
         //    for (let i = 0; i < routerData.paperInfo.length; i++) {
         //    for (let i = 0; i < routerData.paperInfo.length; i++) {
         //        routerData.paperInfo[i].createType = 'manualPaper'
         //        routerData.paperInfo[i].createType = 'manualPaper'
         //    }
         //    }
-        //    this.evaluationInfo = routerData
-        //    this.activeTab = 'preview'
-        //}
+           this.evaluationInfo = routerData
+           this.activeTab = 'preview'
+           this.$Message.warning('编辑评测功能尚未完善')
+        }
     },
     },
     mounted() {
     mounted() {
         this.startTime = new Date()
         this.startTime = new Date()

+ 6 - 0
TEAMModelOS/ClientApp/src/view/learnactivity/MgtPrivEva.less

@@ -258,3 +258,9 @@
     color: white;
     color: white;
     border-radius: 2px;
     border-radius: 2px;
 }
 }
+.mock-stu-answer{
+    margin-right: 20px;
+}
+.mock-tea-scoring{
+    margin-right: 40px;
+}

+ 66 - 4
TEAMModelOS/ClientApp/src/view/learnactivity/MgtPrivEva.vue

@@ -54,6 +54,15 @@
                     <span :class="curBarIndex == 1 ? 'evalustion-bar-item line-bottom-active line-bottom':'evalustion-bar-item line-bottom'" @click="selectBar(1)">
                     <span :class="curBarIndex == 1 ? 'evalustion-bar-item line-bottom-active line-bottom':'evalustion-bar-item line-bottom'" @click="selectBar(1)">
                         {{$t('learnActivity.mgtScEv.tab2')}}
                         {{$t('learnActivity.mgtScEv.tab2')}}
                     </span>
                     </span>
+                    <!-- <div style="float:right;" v-show="evaListShow[curEvaIndex] && evaListShow[curEvaIndex].progress == 'going'"> -->
+                    <div style="float:right;">
+                        <Tooltip :content="$t('learnActivity.mgtScEv.autoTips1')" :max-width="240">
+                            <Button type="success" size="small" :loading="answerLoading" class="mock-stu-answer" @click="mockAnswer">{{$t('learnActivity.mgtScEv.autoAnswer')}}</Button>
+                        </Tooltip>
+                        <Tooltip :content="$t('learnActivity.mgtScEv.autoTips2')" :max-width="240">
+                            <Button type="warning" size="small" :loading="scoreLoading" class="mock-tea-scoring" @click="mockScoring">{{$t('learnActivity.mgtScEv.autoScore')}}</Button>
+                        </Tooltip>
+                    </div>
                 </div>
                 </div>
                 <!--试卷信息-->
                 <!--试卷信息-->
                 <div :class="curBarIndex == 1 ? 'animated fadeIn evaluation-base-info':'evaluation-base-info animated fadeOutRight'" v-show="curBarIndex == 1">
                 <div :class="curBarIndex == 1 ? 'animated fadeIn evaluation-base-info':'evaluation-base-info animated fadeOutRight'" v-show="curBarIndex == 1">
@@ -86,6 +95,7 @@ export default {
         TestPaper,
         TestPaper,
         Scoring
         Scoring
     },
     },
+    inject: ['reload'],
     data() {
     data() {
         return {
         return {
             split1: 0.2,
             split1: 0.2,
@@ -102,10 +112,56 @@ export default {
             filterPeriod: undefined,
             filterPeriod: undefined,
             schoolBase: {
             schoolBase: {
                 period: []
                 period: []
-            }
+            },
+            scoreLoading: false,
+            answerLoading: false
         }
         }
     },
     },
     methods: {
     methods: {
+        // 模拟教师评分数据
+        mockScoring() {
+            this.scoreLoading = true
+            this.$api.learnActivity.mockScoring({
+                id: this.evaListShow[this.curEvaIndex].id,
+                code: this.evaListShow[this.curEvaIndex].code.replace('Exam-', '')
+            }).then(
+                res => {
+                    setTimeout(() => {
+                        this.$Message.success(this.$t('learnActivity.mgtScEv.mockOk'))
+                    }, 500)
+                },
+                err => {
+                    this.$Message.error(this.$t('learnActivity.mgtScEv.mockErr'))
+                }
+            ).finally(() => {
+                setTimeout(() => {
+                    this.scoreLoading = false
+                    this.reload()
+                }, 500)
+            })
+        },
+        // 模拟学生作答数据
+        mockAnswer() {
+            this.answerLoading = true
+            this.$api.learnActivity.mockAnswer({
+                id: this.evaListShow[this.curEvaIndex].id,
+                code: this.evaListShow[this.curEvaIndex].code.replace('Exam-', '')
+            }).then(
+                res => {
+                    setTimeout(() => {
+                        this.$Message.success(this.$t('learnActivity.mgtScEv.mockOk'))
+                    }, 500)
+                },
+                err => {
+                    this.$Message.error(this.$t('learnActivity.mgtScEv.mockErr'))
+                }
+            ).finally(() => {
+                setTimeout(() => {
+                    this.answerLoading = false
+                    this.reload()
+                }, 500)
+            })
+        },
         handleEnd(index) {
         handleEnd(index) {
             this.$Modal.confirm({
             this.$Modal.confirm({
                 title: this.$t('learnActivity.mgtScEv.stopTitle'),
                 title: this.$t('learnActivity.mgtScEv.stopTitle'),
@@ -297,10 +353,16 @@ export default {
                 async res => {
                 async res => {
                     if (!res.error) {
                     if (!res.error) {
                         let resData = res.examInfo[0]
                         let resData = res.examInfo[0]
+                        resData.score = 0
                         for (let index in resData.papers) {
                         for (let index in resData.papers) {
-                            resData.papers[index].scope = resData.scope
-                            resData.papers[index].examId = resData.id
-                            resData.papers[index] = await this.$evTools.getFullPaper(resData.papers[index])
+                            resData.score += resData.papers[index].point.reduce((total, item) => {
+                                return total + parseInt(item)
+                            }, 0)
+                            if (resData.papers[index].blob) {
+                                resData.papers[index].scope = resData.scope
+                                resData.papers[index].examId = resData.id
+                                resData.papers[index] = await this.$evTools.getFullPaper(resData.papers[index])
+                            }
                         }
                         }
                         this.evaListShow.splice(this.curEvaIndex, 1, resData)
                         this.evaListShow.splice(this.curEvaIndex, 1, resData)
                         this.examDetaiInfo = resData
                         this.examDetaiInfo = resData

+ 12 - 16
TEAMModelOS/ClientApp/src/view/learnactivity/MgtSchoolEva.vue

@@ -17,7 +17,7 @@
                     </Dropdown>
                     </Dropdown>
                     <Icon type="md-add" class=" to-create-icon" @click="goToCreate" :title="$t('learnActivity.mgtScEv.create')" />
                     <Icon type="md-add" class=" to-create-icon" @click="goToCreate" :title="$t('learnActivity.mgtScEv.create')" />
                     <Icon type="md-trash" v-show="evaListShow.length" class="to-create-icon" :title="$t('learnActivity.mgtScEv.delete')" @click="deleteEvaluation" />
                     <Icon type="md-trash" v-show="evaListShow.length" class="to-create-icon" :title="$t('learnActivity.mgtScEv.delete')" @click="deleteEvaluation" />
-                    <Icon type="md-create" v-show="evaListShow.length" class="to-create-icon" @click="editEvaluation" :title="$t('learnActivity.mgtScEv.edit')" />
+                    <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')" />
                 </div>
                 </div>
                 <div class="evaluation-list-main">
                 <div class="evaluation-list-main">
                     <vuescroll>
                     <vuescroll>
@@ -63,7 +63,7 @@
                     <span :class="curBarIndex == 1 ? 'evalustion-bar-item line-bottom-active line-bottom':'evalustion-bar-item line-bottom'" @click="selectBar(1)">
                     <span :class="curBarIndex == 1 ? 'evalustion-bar-item line-bottom-active line-bottom':'evalustion-bar-item line-bottom'" @click="selectBar(1)">
                         {{$t('learnActivity.mgtScEv.tab2')}}
                         {{$t('learnActivity.mgtScEv.tab2')}}
                     </span>
                     </span>
-                    <div style="float:right;" v-if="$access.ability('admin','mock-eva').validateAll">
+                    <div style="float:right;" v-if="$access.ability('admin','mock-eva').validateAll" v-show="evaListShow[curEvaIndex] && evaListShow[curEvaIndex].progress == 'going'">
                         <Tooltip :content="$t('learnActivity.mgtScEv.autoTips1')" :max-width="240">
                         <Tooltip :content="$t('learnActivity.mgtScEv.autoTips1')" :max-width="240">
                             <Button type="success" size="small" :loading="answerLoading" class="mock-stu-answer" @click="mockAnswer">{{$t('learnActivity.mgtScEv.autoAnswer')}}</Button>
                             <Button type="success" size="small" :loading="answerLoading" class="mock-stu-answer" @click="mockAnswer">{{$t('learnActivity.mgtScEv.autoAnswer')}}</Button>
                         </Tooltip>
                         </Tooltip>
@@ -99,9 +99,6 @@
                 </div>
                 </div>
             </div>
             </div>
         </Split>
         </Split>
-        <!-- <Modal v-model="editEvaluationStatus" title="编辑" @on-ok="confirmEdit">
-            <p>即将跳转到评测编辑页面?</p>
-        </Modal> -->
     </div>
     </div>
 </template>
 </template>
 <script>
 <script>
@@ -120,7 +117,6 @@ export default {
             split1: 0.2,
             split1: 0.2,
             scope: '',//school 校本 private 个人
             scope: '',//school 校本 private 个人
             showBack: false,
             showBack: false,
-            editEvaluationStatus: false,
             curSubIndex: 0,
             curSubIndex: 0,
             curBarIndex: 0,
             curBarIndex: 0,
             curEvaIndex: 0,
             curEvaIndex: 0,
@@ -193,6 +189,7 @@ export default {
                             if (!res.error) {
                             if (!res.error) {
                                 this.$Message.success(this.$t('learnActivity.mgtScEv.stopOk'))
                                 this.$Message.success(this.$t('learnActivity.mgtScEv.stopOk'))
                                 this.evaListShow[index].progress = 'finish'
                                 this.evaListShow[index].progress = 'finish'
+                                this.reload()
                             } else {
                             } else {
                                 this.$Message.error('API ERROR!')
                                 this.$Message.error('API ERROR!')
                             }
                             }
@@ -308,19 +305,15 @@ export default {
                 this.$Message.warning(this.$t('learnActivity.mgtScEv.noJoin'))
                 this.$Message.warning(this.$t('learnActivity.mgtScEv.noJoin'))
             }
             }
         },
         },
-        confirmEdit() {
-            let evaluationInfo = this.evaluationList[this.curEvaIndex]
-            evaluationInfo.testPaper = this.examDetaiInfo
+        editEvaluation() {
+            // this.$Message.warning('暂未处理编辑评测功能!')
             this.$router.push({
             this.$router.push({
-                name: 'createEvaluation',
-                params: {
-                    evaluationInfo
+                name:'createSchoolEva',
+                params:{
+                    evaluationInfo: this.examDetaiInfo
                 }
                 }
             })
             })
         },
         },
-        editEvaluation() {
-            this.$Message.warning('暂未处理编辑评测功能!')
-        },
         selectSubject(index) {
         selectSubject(index) {
             this.curSubIndex = index
             this.curSubIndex = index
         },
         },
@@ -391,7 +384,7 @@ export default {
                 this.examDetaiInfo = this.evaListShow[this.curEvaIndex]
                 this.examDetaiInfo = this.evaListShow[this.curEvaIndex]
             }
             }
         },
         },
-        //查询当前评测的试卷信息
+        //查询当前评测的详细信息
         findExamPaper() {
         findExamPaper() {
             let requestData = {
             let requestData = {
                 id: this.evaListShow[this.curEvaIndex].id,
                 id: this.evaListShow[this.curEvaIndex].id,
@@ -402,10 +395,13 @@ export default {
                 async res => {
                 async res => {
                     if (!res.error) {
                     if (!res.error) {
                         let resData = res.examInfo[0]
                         let resData = res.examInfo[0]
+                        resData.score = 0
                         for (let index in resData.papers) {
                         for (let index in resData.papers) {
                             resData.papers[index].scope = resData.scope
                             resData.papers[index].scope = resData.scope
                             resData.papers[index].examId = resData.id
                             resData.papers[index].examId = resData.id
                             resData.papers[index] = await this.$evTools.getFullPaper(resData.papers[index])
                             resData.papers[index] = await this.$evTools.getFullPaper(resData.papers[index])
+                            console.log('试卷',resData.papers[index])
+                            resData.score += resData.papers[index].score
                         }
                         }
                         this.evaListShow.splice(this.curEvaIndex, 1, resData)
                         this.evaListShow.splice(this.curEvaIndex, 1, resData)
                         this.examDetaiInfo = resData
                         this.examDetaiInfo = resData

+ 1 - 0
TEAMModelOS/ClientApp/src/view/learnactivity/PaperScore.less

@@ -314,6 +314,7 @@
         font-size: 12px;
         font-size: 12px;
         display: none; 
         display: none; 
         line-height: 18px;
         line-height: 18px;
+        cursor: pointer;
     }
     }
     .stu-status-tag{
     .stu-status-tag{
         background: #ed4014;
         background: #ed4014;

+ 13 - 12
TEAMModelOS/ClientApp/src/view/learnactivity/PaperScore.vue

@@ -161,9 +161,9 @@
                                         <div class="item-explain">
                                         <div class="item-explain">
                                             <span class="explain-title">{{$t('learnActivity.score.kdLabel')}}</span>
                                             <span class="explain-title">{{$t('learnActivity.score.kdLabel')}}</span>
                                             <div class="item-explain-details">
                                             <div class="item-explain-details">
-                                                <span v-if="! (_.compact(item.points).length)">{{$t('learnActivity.score.noKd')}}</span>
+                                                <span v-if="!item.knowledge || (_.compact(item.knowledge).length)">{{$t('learnActivity.score.noKd')}}</span>
                                                 <div v-else>
                                                 <div v-else>
-                                                    <span v-for="(point,index) in item.points" :key="index" class="item-point-tag">
+                                                    <span v-for="(point,index) in item.knowledge" :key="index" class="item-point-tag">
                                                         {{ point }}
                                                         {{ point }}
                                                     </span>
                                                     </span>
                                                 </div>
                                                 </div>
@@ -279,9 +279,9 @@
                                 <div class="item-explain" v-show="showAnswer">
                                 <div class="item-explain" v-show="showAnswer">
                                     <span class="explain-title">{{$t('learnActivity.score.kdLabel')}}</span>
                                     <span class="explain-title">{{$t('learnActivity.score.kdLabel')}}</span>
                                     <div class="item-explain-details">
                                     <div class="item-explain-details">
-                                        <span v-if="!childItem.points.length">{{$t('learnActivity.score.noKd')}}</span>
+                                        <span v-if="!childItem.knowledge || !childItem.knowledge.length">{{$t('learnActivity.score.noKd')}}</span>
                                         <div v-else>
                                         <div v-else>
-                                            <span v-for="(point,index) in childItem.points" :key="index" class="item-point-tag">
+                                            <span v-for="(point,index) in childItem.knowledge" :key="index" class="item-point-tag">
                                                 <span>{{ point }}</span>
                                                 <span>{{ point }}</span>
                                             </span>
                                             </span>
                                         </div>
                                         </div>
@@ -395,9 +395,7 @@ export default {
             this.curAnIndex = index
             this.curAnIndex = index
             let answerIframe = document.getElementById('answerIframe')
             let answerIframe = document.getElementById('answerIframe')
             let markBody = answerIframe.contentWindow.document.body
             let markBody = answerIframe.contentWindow.document.body
-            console.log('body', answerIframe.contentWindow.document.body)
             answerIframe.onload = () => {
             answerIframe.onload = () => {
-                console.log(markBody)
                 answerIframe.style.width = '850px'
                 answerIframe.style.width = '850px'
                 answerIframe.contentWindow.document.body.style.margin = '0px 20px'
                 answerIframe.contentWindow.document.body.style.margin = '0px 20px'
                 answerIframe.contentWindow.document.body.style.padding = '10px'
                 answerIframe.contentWindow.document.body.style.padding = '10px'
@@ -576,7 +574,6 @@ export default {
     watch: {
     watch: {
         paper: {
         paper: {
             handler(newValue, oldValue) {
             handler(newValue, oldValue) {
-                console.log('newValue', newValue)
                 this.paperInfo = newValue
                 this.paperInfo = newValue
             },
             },
             deep: true
             deep: true
@@ -619,15 +616,21 @@ export default {
                 if (!this.studentAnswer.status) {
                 if (!this.studentAnswer.status) {
                     if (newValue.answers.length) {
                     if (newValue.answers.length) {
                         try {
                         try {
-                            console.log(this.scope)
                             let sas = this.scope == 'school' ? this.$store.state.user.schoolProfile.blob_sas : this.$store.state.user.userProfile.blob_sas
                             let sas = this.scope == 'school' ? this.$store.state.user.schoolProfile.blob_sas : this.$store.state.user.userProfile.blob_sas
-                            let a = await this.$tools.getFile(newValue.answers[0] + '?' + sas)
+                            let container = this.scope == 'school' ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId
+                            //为了兼容原来完整的路径,这里做判断
+                            let a = null
+                            if (newValue.answers[0].indexOf('https://teammodelstorage') > -1) {
+                                a = await this.$tools.getFile(`${newValue.answers[0]}?${sas}`)
+                            }else{
+                                a = await this.$tools.getFile(`${this.$GLOBAL.BLOB_URL}/${container}/exam/${newValue.answers[0]}?${sas}`)
+                            }
+
                             if (a) {
                             if (a) {
                                 let ans = JSON.parse(a)
                                 let ans = JSON.parse(a)
                                 ans.forEach((item, index) => {
                                 ans.forEach((item, index) => {
                                     if (!item.length) ans[index] = [this.$t('learnActivity.score.noStuAns')]
                                     if (!item.length) ans[index] = [this.$t('learnActivity.score.noStuAns')]
                                 })
                                 })
-                                console.log('a', ans)
                                 this.$set(this.studentAnswer, 'answers', ans)
                                 this.$set(this.studentAnswer, 'answers', ans)
                             } else {
                             } else {
                                 this.$set(this.studentAnswer, 'answers', [])
                                 this.$set(this.studentAnswer, 'answers', [])
@@ -640,7 +643,6 @@ export default {
                         let a = newValue.scores.map(item => {
                         let a = newValue.scores.map(item => {
                             return [this.$t('learnActivity.score.noStuAns1')]
                             return [this.$t('learnActivity.score.noStuAns1')]
                         })
                         })
-                        console.log('a', a)
                         this.$set(this.studentAnswer, 'answers', a)
                         this.$set(this.studentAnswer, 'answers', a)
                     }
                     }
                     this.studentAnswer.status = true
                     this.studentAnswer.status = true
@@ -665,7 +667,6 @@ export default {
         }
         }
     },
     },
     created() {
     created() {
-        console.log('router', this.$route)
         if (this.$route.name == 'privateEvaluation') {
         if (this.$route.name == 'privateEvaluation') {
             this.scope = 'private'
             this.scope = 'private'
         } else {
         } else {

+ 5 - 0
TEAMModelOS/ClientApp/src/view/learnactivity/Scoring.less

@@ -89,4 +89,9 @@
     width: 100%;
     width: 100%;
     height: 200px;
     height: 200px;
     // background: white;
     // background: white;
+}
+.page-wrap{
+    float: right;
+    margin-top: 15px;
+    color: white;
 }
 }

+ 198 - 55
TEAMModelOS/ClientApp/src/view/learnactivity/Scoring.vue

@@ -1,12 +1,8 @@
 <template>
 <template>
     <div class="ev-scoring dark-iview-table">
     <div class="ev-scoring dark-iview-table">
         <vuescroll ref="score-main-warp">
         <vuescroll ref="score-main-warp">
-            <SimpleAnalysis :examInfo="examInfo" v-show="!showTest"></SimpleAnalysis>
+            <SimpleAnalysis :examInfo="examInfo" v-show="!showTest" :overviewInfo="overviewInfo"></SimpleAnalysis>
             <div class="ev-target-box dark-iview-select">
             <div class="ev-target-box dark-iview-select">
-                <span class="filter-label" v-show="examInfo.scope == 'school'">{{$t('learnActivity.score.subjectLabel')}}</span>
-                <Select filterable v-model="chooseSubject" class="filter-select" size="small" @on-change="getCurPaper" v-show="examInfo.scope == 'school'" transfer>
-                    <Option v-for="(item,index) in examInfo.subjects" :value="item.id" :key="index">{{ item.name }}</Option>
-                </Select>
                 <span class="filter-label" v-show="examInfo.scope == 'school'">{{$t('learnActivity.score.gradeLabel')}}</span>
                 <span class="filter-label" v-show="examInfo.scope == 'school'">{{$t('learnActivity.score.gradeLabel')}}</span>
                 <Select filterable v-model="chooseGrade" class="filter-select" size="small" v-show="examInfo.scope == 'school'" style="margin-right:5px" transfer>
                 <Select filterable v-model="chooseGrade" class="filter-select" size="small" v-show="examInfo.scope == 'school'" style="margin-right:5px" transfer>
                     <Option v-for="(item,index) in examInfo.grades" :value="item.id" :key="index">{{ item.name }}</Option>
                     <Option v-for="(item,index) in examInfo.grades" :value="item.id" :key="index">{{ item.name }}</Option>
@@ -15,6 +11,10 @@
                 <Select filterable v-model="chooseClass" class="filter-select" style="width:140px;" @on-change="getClassStudent" size="small" transfer>
                 <Select filterable v-model="chooseClass" class="filter-select" style="width:140px;" @on-change="getClassStudent" size="small" transfer>
                     <Option v-for="(item,index) in classList" :value="item.id" :key="index">{{ item.name }}</Option>
                     <Option v-for="(item,index) in classList" :value="item.id" :key="index">{{ item.name }}</Option>
                 </Select>
                 </Select>
+                <span class="filter-label" v-show="examInfo.scope == 'school'">{{$t('learnActivity.score.subjectLabel')}}</span>
+                <Select filterable v-model="chooseSubject" class="filter-select" size="small" @on-change="getCurPaper" v-show="examInfo.scope == 'school'" transfer>
+                    <Option v-for="(item,index) in examInfo.subjects" :value="item.id" :key="index">{{ item.name }}</Option>
+                </Select>
                 <span style="margin-left:5px" v-show="showTest">{{$t('learnActivity.score.stuLabel')}}</span>
                 <span style="margin-left:5px" v-show="showTest">{{$t('learnActivity.score.stuLabel')}}</span>
                 <Select filterable v-model="chooseStudent.id" label-in-value class="filter-select" style="width:140px;" size="small" clearable @on-change="setStuInfo" v-show="showTest" transfer>
                 <Select filterable v-model="chooseStudent.id" label-in-value class="filter-select" style="width:140px;" size="small" clearable @on-change="setStuInfo" v-show="showTest" transfer>
                     <Option v-for="(item,index) in students" :value="item.id" :key="index">
                     <Option v-for="(item,index) in students" :value="item.id" :key="index">
@@ -28,7 +28,7 @@
                 </span>
                 </span>
             </div>
             </div>
             <div class="scoring-main-wrap">
             <div class="scoring-main-wrap">
-                <Table v-show="!showTest" class="score-box" border :columns="tableColumn" :data="studentScore" :loading="tableLoading" :max-height="700" :no-data-text="$t('learnActivity.score.classNoStu')">
+                <Table v-show="!showTest" class="score-box" border :columns="tableColumn" :data="tableData" :loading="tableLoading" @on-sort-change="onSortChange" :no-data-text="$t('learnActivity.score.classNoStu')">
                     <template slot-scope="{ row,index }" :slot="'qu'+qIndex" v-for="(item,qIndex) in quCount">
                     <template slot-scope="{ row,index }" :slot="'qu'+qIndex" v-for="(item,qIndex) in quCount">
                         <div :key="'qu'+qIndex" @click="getStuScore(row,qIndex)" style="cursor:pointer;">
                         <div :key="'qu'+qIndex" @click="getStuScore(row,qIndex)" style="cursor:pointer;">
                             <span @click="noAnswer" v-if="row.data[qIndex] == -1 && row.status == 1">- -</span>
                             <span @click="noAnswer" v-if="row.data[qIndex] == -1 && row.status == 1">- -</span>
@@ -36,9 +36,9 @@
                             <span style="color:#2db7f5;" v-else>{{row.data[qIndex]}}</span>
                             <span style="color:#2db7f5;" v-else>{{row.data[qIndex]}}</span>
                         </div>
                         </div>
                     </template>
                     </template>
-                    <template slot-scope="{ row,index }" slot="total">
+                    <!-- <template slot-scope="{ row,index }" slot="total">
                         <strong>{{getcount(studentScore[row._index].data)}}</strong>
                         <strong>{{getcount(studentScore[row._index].data)}}</strong>
-                    </template>
+                    </template> -->
                     <!-- 1: 未作答 2:未评分 3:已评分 -->
                     <!-- 1: 未作答 2:未评分 3:已评分 -->
                     <template slot-scope="{ row,index }" slot="status">
                     <template slot-scope="{ row,index }" slot="status">
                         <span class="stu-status-tag" @click="getStuScore(row,0)" :style="{'background':row.status == 1 ? '#c5c8ce' : row.status == 2 ? '#ff9900' : '#19be6b', 'cursor':row.status == 1 ? 'text':'pointer'}">
                         <span class="stu-status-tag" @click="getStuScore(row,0)" :style="{'background':row.status == 1 ? '#c5c8ce' : row.status == 2 ? '#ff9900' : '#19be6b', 'cursor':row.status == 1 ? 'text':'pointer'}">
@@ -47,6 +47,10 @@
                     </template>
                     </template>
                     <Loading slot="loading" :top="-50"></Loading>
                     <Loading slot="loading" :top="-50"></Loading>
                 </Table>
                 </Table>
+                <!-- 分页 -->
+                <div class="page-wrap dark-ivew-select">
+                    <Page show-total size="small" :current="currentPage" :total="studentScore.length" :page-size="pageSize" :page-size-opts="pageSizeOpts" @on-change="pageChange" @on-page-size-change="pageSizeChange" show-sizer />
+                </div>
                 <div class="dark-iview-table scoring-handle-box" v-show="showTest">
                 <div class="dark-iview-table scoring-handle-box" v-show="showTest">
                     <PaperScore ref="paperScore" :defaultIndex="defaultIndex" :examId="examInfo.id" :paper="paperInfo" :studentAnswer="chooseStudent" :subjectId="chooseSubject" @nextStu="getNextStu" style="color:#515a6e;"></PaperScore>
                     <PaperScore ref="paperScore" :defaultIndex="defaultIndex" :examId="examInfo.id" :paper="paperInfo" :studentAnswer="chooseStudent" :subjectId="chooseSubject" @nextStu="getNextStu" style="color:#515a6e;"></PaperScore>
                     <Loading :top="200" type="1" style="text-align:center" v-show="dataLoading"></Loading>
                     <Loading :top="200" type="1" style="text-align:center" v-show="dataLoading"></Loading>
@@ -63,18 +67,30 @@ export default {
         examInfo: {
         examInfo: {
             type: Object,
             type: Object,
             default: () => {
             default: () => {
-                return {};
-            },
-        },
+                return {}
+            }
+        }
     },
     },
     components: {
     components: {
         PaperScore, SimpleAnalysis
         PaperScore, SimpleAnalysis
     },
     },
     data() {
     data() {
         return {
         return {
+            originData: [],
+            studentScore: [],
+            tableData: [],
+            currentPage: 1,
+            pageSize: 10,
+            pageSizeOpts: [5, 10, 20, 30, 40],
+            overviewInfo: {
+                total: 0,
+                answered: 0,
+                noAnswer: 0,
+                scored: 0,
+                noScore: 0
+            },
             defaultIndex: 0,
             defaultIndex: 0,
             tableLoading: false,
             tableLoading: false,
-            tableHeight: 750,
             showTest: false, //是否评分
             showTest: false, //是否评分
             studentData: [],
             studentData: [],
             dataLoading: false,
             dataLoading: false,
@@ -97,10 +113,11 @@ export default {
                 },
                 },
                 {
                 {
                     title: this.$t('learnActivity.score.column2'),
                     title: this.$t('learnActivity.score.column2'),
-                    slot: "total",
+                    key: "total",
                     align: "center",
                     align: "center",
+                    sortable: true,
                     fixed: "right",
                     fixed: "right",
-                    width: 100,
+                    width: 100
                 },
                 },
                 {
                 {
                     title: this.$t('learnActivity.score.column3'),
                     title: this.$t('learnActivity.score.column3'),
@@ -111,16 +128,49 @@ export default {
                 }
                 }
             ],
             ],
             tableColumn: [],
             tableColumn: [],
-            studentScore: [],
+
             quCount: [],
             quCount: [],
             paperInfo: {},
             paperInfo: {},
             students: [],
             students: [],
             privClassList: undefined,
             privClassList: undefined,
             routerScope: ''
             routerScope: ''
 
 
-        };
+        }
     },
     },
     methods: {
     methods: {
+        // 排序操作
+        onSortChange(data) {
+            let order = data.order // 当前排序方式 升序、降序、正常
+            let key = data.key // 当前排序依据
+            switch (order) {
+                case 'asc':
+                    this.studentScore = this.originData.sort((a, b) => { return Number(a[key]) - Number(b[key]) })
+                    break
+                case 'desc':
+                    this.studentScore = this.originData.sort((a, b) => { return Number(b[key]) - Number(a[key]) })
+                    break
+                case 'normal':
+                    this.studentScore = this.students
+                    break
+                default:
+                    break
+            }
+            console.log('1', this.studentScore[0].name)
+            console.log(2, this.originData[0].name)
+            this.pageChange(1)
+        },
+        // 页面size变化
+        pageSizeChange(val) {
+            this.pageSize = val
+            this.pageChange(1)
+        },
+        // 分页页面变化
+        pageChange(page) {
+            let start = this.pageSize * (page - 1)
+            let end = this.pageSize * page
+            this.currentPage = page
+            this.tableData = this.studentScore.slice(start, end)
+        },
         toggleScoreStatus() {
         toggleScoreStatus() {
             this.$refs['paperScore'].isComplete = false
             this.$refs['paperScore'].isComplete = false
             this.showTest = !this.showTest
             this.showTest = !this.showTest
@@ -209,22 +259,48 @@ export default {
             if (!this.chooseClass) return;
             if (!this.chooseClass) return;
             let requestData = {
             let requestData = {
                 id: this.chooseClass,
                 id: this.chooseClass,
-                scope: this.routerScope,
-                school_code: this.routerScope == 'school' ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId,
+                scope: this.examInfo.scope == 'private' ? 'private' : 'school',
+                school_code: this.examInfo.scope == 'private' ? this.$store.state.userInfo.TEAMModelId : this.$store.state.userInfo.schoolCode,
             };
             };
             this.$api.schoolSetting.getClassroomStudent(requestData).then((res) => {
             this.$api.schoolSetting.getClassroomStudent(requestData).then((res) => {
                 if (!res.error) {
                 if (!res.error) {
                     if (!this.paperInfo[this.chooseClass]) {
                     if (!this.paperInfo[this.chooseClass]) {
                         this.paperInfo[this.chooseClass] = {}
                         this.paperInfo[this.chooseClass] = {}
                     }
                     }
-                    this.$set(this.paperInfo[this.chooseClass], "students", res.classrooms[0]);
+                    this.$set(this.paperInfo[this.chooseClass], "students", res.classrooms[0])
+                    this.students = []
+                    this.tableData = []
+                    this.studentScore = []
                     this.getStudentAnswer();
                     this.getStudentAnswer();
                 } else {
                 } else {
                     this.$Message.error("API ERROR!");
                     this.$Message.error("API ERROR!");
                 }
                 }
             })
             })
         },
         },
-
+        //计算总览数据
+        calcOverView(data) {
+            //计算已作答未作答
+            this.overviewInfo.noAnswer = 0
+            data.studentAnswers.forEach(item => {
+                if (item.length == 0) {
+                    this.overviewInfo.noAnswer++
+                }
+            })
+            this.overviewInfo.answered = data.studentAnswers.length - this.overviewInfo.noAnswer
+            // 计算已评分未评分
+            this.overviewInfo.noScore = 0
+            data.studentScores.forEach(item => {
+                let flag = item.find(item => {
+                    return item == -1
+                })
+                if (flag) {
+                    this.overviewInfo.noScore++
+                }
+            })
+            this.overviewInfo.scored = data.studentScores.length - this.overviewInfo.noScore
+            // 班级总人数
+            this.overviewInfo.total = data.studentIds.length
+        },
         getStudentAnswer() {
         getStudentAnswer() {
             this.dataLoading = true
             this.dataLoading = true
             let requestData = {
             let requestData = {
@@ -238,6 +314,10 @@ export default {
                     if (res.examClassResults) {
                     if (res.examClassResults) {
                         this.paperInfo[this.chooseClass]["studentAns"] = res.examClassResults[0];
                         this.paperInfo[this.chooseClass]["studentAns"] = res.examClassResults[0];
                         this.setTableData();
                         this.setTableData();
+                        if (res.examClassResults[0]) {
+                            this.calcOverView(res.examClassResults[0])
+                        }
+
                     }
                     }
                 },
                 },
                 (err) => {
                 (err) => {
@@ -245,18 +325,6 @@ export default {
                 }
                 }
             ).finally(() => {
             ).finally(() => {
                 setTimeout(() => {
                 setTimeout(() => {
-                    this.$nextTick(() => {
-                        let tableBody = document.getElementsByClassName('ivu-table-tbody')
-                        console.log('tableBody', tableBody)
-                        let fixed = document.getElementsByClassName('ivu-table-fixed-body')
-                        console.log(fixed)
-                        for (let iterator of fixed) {
-                            console.log(iterator)
-                            let max = 653 > (48 * this.studentScore.length) ? (48 * this.studentScore.length) : 653
-                            // iterator.style.maxHeight =  (this.tableHeight - 40) + 'px'
-                            iterator.style.maxHeight = max + 'px'
-                        }
-                    })
                     this.dataLoading = false
                     this.dataLoading = false
                     this.tableLoading = false
                     this.tableLoading = false
                 }, 500);
                 }, 500);
@@ -264,29 +332,30 @@ export default {
         },
         },
         //初始化表单数据
         //初始化表单数据
         setTableData() {
         setTableData() {
-            if (this.paperInfo[this.chooseClass]) {
-                let studentData = this.paperInfo[this.chooseClass]["students"];
-                let studentAns = this.paperInfo[this.chooseClass]["studentAns"];
-                this.studentScore = [];
-                this.tableColumn = [...this.scoreList];
-                this.quCount = studentAns.studentScores[0] ? studentAns.studentScores[0].length : 0;
+            if (this.paperInfo[this.chooseClass] && this.paperInfo[this.chooseClass]["students"] && this.paperInfo[this.chooseClass]["studentAns"]) {
+                let studentData = this.paperInfo[this.chooseClass]["students"]
+                let studentAns = this.paperInfo[this.chooseClass]["studentAns"]
+                this.studentScore = []
+                this.tableColumn = [...this.scoreList]
+                this.quCount = studentAns.studentScores[0] ? studentAns.studentScores[0].length : 0
                 for (let i = 0; i < this.quCount; i++) {
                 for (let i = 0; i < this.quCount; i++) {
                     let data = {
                     let data = {
                         title: "Q" + (i + 1),
                         title: "Q" + (i + 1),
                         slot: "qu" + i,
                         slot: "qu" + i,
                         align: "center",
                         align: "center",
-                        minWidth: 70,
-                    };
+                        minWidth: 65,
+                    }
                     this.tableColumn.push(data);
                     this.tableColumn.push(data);
                 }
                 }
-                let ans = [];
+                let ans = []
                 for (let i = 0; i < studentAns.studentIds.length; i++) {
                 for (let i = 0; i < studentAns.studentIds.length; i++) {
                     for (let k = 0; k < studentData.students.length; k++) {
                     for (let k = 0; k < studentData.students.length; k++) {
-                        let score = {};
+                        let score = {}
                         if (studentAns.studentIds[i] == studentData.students[k].id) {
                         if (studentAns.studentIds[i] == studentData.students[k].id) {
-                            score.name = studentData.students[k].name;
-                            score.id = studentAns.studentIds[i];
-                            score.data = studentAns.studentScores[i];
+                            score.name = studentData.students[k].name
+                            score.id = studentAns.studentIds[i]
+                            score.data = studentAns.studentScores[i]
+                            score.total = this.getcount(score.data)
                             if (studentAns.studentAnswers[i].length == 0) {//学生未作答
                             if (studentAns.studentAnswers[i].length == 0) {//学生未作答
                                 score.status = 1
                                 score.status = 1
                             } else if (studentAns.studentScores[i].indexOf(-1) >= 0) {//已作答,未评分
                             } else if (studentAns.studentScores[i].indexOf(-1) >= 0) {//已作答,未评分
@@ -294,17 +363,15 @@ export default {
                             } else {//已批改
                             } else {//已批改
                                 score.status = 3
                                 score.status = 3
                             }
                             }
-                            this.studentScore.push(score);
+                            this.studentScore.push(score)
                         }
                         }
                     }
                     }
                 }
                 }
+                this.originData = this._.cloneDeep(this.studentScore)
                 this.students = this._.cloneDeep(this.studentScore)
                 this.students = this._.cloneDeep(this.studentScore)
+                this.pageChange(1)
                 if (ans.length) {
                 if (ans.length) {
-                    for (
-                        let k = 0;
-                        k < this.paperInfo.papers.item.length;
-                        k++
-                    ) {
+                    for (let k = 0; k < this.paperInfo.papers.item.length; k++) {
                         this.$set(
                         this.$set(
                             this.paperInfo.papers.item[k],
                             this.paperInfo.papers.item[k],
                             "answerData",
                             "answerData",
@@ -382,7 +449,6 @@ export default {
                 if (n.grades && n.grades.length) {
                 if (n.grades && n.grades.length) {
                     this.chooseGrade = n.grades[0].id;
                     this.chooseGrade = n.grades[0].id;
                 }
                 }
-
                 if (n.papers && n.papers.length) {
                 if (n.papers && n.papers.length) {
                     if (n.scope == 'school') {
                     if (n.scope == 'school') {
                         let res = n.papers.find((item) => {
                         let res = n.papers.find((item) => {
@@ -408,6 +474,26 @@ export default {
                 }
                 }
             },
             },
             deep: true,
             deep: true,
+        },
+        chooseStudent: {
+            handler(n, o) {
+                if (n.id) {
+                    let curStu = this.studentScore.find(item => {
+                        return item.id == n.id
+                    })
+                    if (curStu.status == 2) {
+                        let flag = n.scores.find(item => {
+                            return item == -1
+                        })
+                        if (!flag) {
+                            curStu.status = 3
+                            this.overviewInfo.noScore--
+                            this.overviewInfo.scored++
+                        }
+                    }
+                }
+            },
+            deep: true
         }
         }
     },
     },
     computed: {
     computed: {
@@ -437,7 +523,6 @@ export default {
                             ids: this.examInfo.targetClassIds
                             ids: this.examInfo.targetClassIds
                         }).then(
                         }).then(
                             res => {
                             res => {
-                                console.log('list', res)
                                 if (res.className && res.className.length) this.chooseClass = res.className[0].id
                                 if (res.className && res.className.length) this.chooseClass = res.className[0].id
                                 this.privClassList = res.className
                                 this.privClassList = res.className
                             },
                             },
@@ -454,8 +539,6 @@ export default {
         },
         },
     },
     },
     mounted() {
     mounted() {
-        let tableWrap = document.getElementsByClassName('scoring-main-wrap')
-        this.tableHeight = tableWrap[0].offsetHeight - 27
     },
     },
     created() {
     created() {
         if (this.$route.name == 'privateEvaluation') {
         if (this.$route.name == 'privateEvaluation') {
@@ -500,4 +583,64 @@ export default {
         background: rgba(53, 53, 53, 0.5);
         background: rgba(53, 53, 53, 0.5);
     }
     }
 }
 }
+.page-wrap .ivu-page-item {
+    background: rgba(40, 40, 40, 0.5);
+}
+
+.page-wrap .ivu-page-item:hover {
+    border-color: #e4eadb;
+}
+
+.page-wrap .ivu-page-item-active {
+    background: #bfbfb9;
+}
+
+.page-wrap .ivu-page-item a {
+    color: #f1f1f1;
+}
+
+.page-wrap .ivu-page-next,
+.page-wrap .ivu-page-prev {
+    background: rgba(0, 0, 0, 0);
+}
+
+.page-wrap .ivu-page-next a,
+.page-wrap .ivu-page-prev a {
+    color: #e4eadb;
+}
+
+.page-wrap .ivu-page-next:hover,
+.page-wrap .ivu-page-prev:hover {
+    border-color: #e4eadb;
+}
+
+.page-wrap .ivu-page-item-active,
+.page-wrap .ivu-page-item:hover a {
+    border-color: #e4eadb;
+}
+
+.page-wrap .ivu-page-item-active a {
+    color: #595959;
+}
+.page-wrap
+    .ivu-select-small.ivu-select-single
+    .ivu-select-selection
+    .ivu-select-selected-value {
+    height: 27px;
+    line-height: 27px;
+    font-size: 12px;
+}
+.page-wrap .ivu-select-single .ivu-select-selection {
+    height: 30px;
+    background: transparent;
+    border: 1px solid #595959;
+    box-shadow: none;
+    color: #cecece;
+}
+
+.page-wrap .ivu-select-single .ivu-select-placeholder {
+    height: 30px;
+    line-height: 30px;
+    font-size: 16px;
+}
 </style>
 </style>

+ 156 - 23
TEAMModelOS/ClientApp/src/view/learnactivity/SimpleAnalysis.vue

@@ -1,6 +1,6 @@
 <template>
 <template>
     <div>
     <div>
-        <div class="overview-box"  v-if="examInfo.progress == 'finish'">
+        <div class="overview-box" v-if="examInfo.progress == 'finish'">
             <div class="count-box">
             <div class="count-box">
                 <span class="count-subject-num">{{examInfo.stuCount}}</span>
                 <span class="count-subject-num">{{examInfo.stuCount}}</span>
                 <span class="count-subject-text">
                 <span class="count-subject-text">
@@ -9,7 +9,7 @@
                 </span>
                 </span>
             </div>
             </div>
             <div class="count-box">
             <div class="count-box">
-                <span class="count-subject-num">1</span>
+                <span class="count-subject-num">--</span>
                 <span class="count-subject-text">
                 <span class="count-subject-text">
                     <Icon type="ios-paper" class="count-icon" />
                     <Icon type="ios-paper" class="count-icon" />
                     缺考数
                     缺考数
@@ -30,7 +30,7 @@
                 </span>
                 </span>
             </div>
             </div>
             <div class="count-box">
             <div class="count-box">
-                <span class="count-subject-num">273</span>
+                <span class="count-subject-num">{{avgScore}}</span>
                 <span class="count-subject-text">
                 <span class="count-subject-text">
                     <Icon custom="iconfont icon-class-self" class="count-icon" />
                     <Icon custom="iconfont icon-class-self" class="count-icon" />
                     平均分
                     平均分
@@ -38,46 +38,54 @@
             </div>
             </div>
         </div>
         </div>
         <div class="overview-box" style="justify-content: space-around;padding-top:40px" v-if="examInfo.progress == 'finish'">
         <div class="overview-box" style="justify-content: space-around;padding-top:40px" v-if="examInfo.progress == 'finish'">
-            <ScoreMatrix></ScoreMatrix>
-            <AvgCompare></AvgCompare>
+            <ScoreMatrix :pieData="scoreSegment"></ScoreMatrix>
+            <AvgCompare :pieData="simpleData.averageMap"></AvgCompare>
         </div>
         </div>
         <div class="overview-box" v-if="examInfo.progress == 'going'" style="margin-bottom:30px;">
         <div class="overview-box" v-if="examInfo.progress == 'going'" style="margin-bottom:30px;">
             <div class="count-box">
             <div class="count-box">
-                <span class="count-subject-num">{{examInfo.stuCount}}</span>
+                <span class="count-subject-num">{{overviewInfo.total}}</span>
                 <span class="count-subject-text">
                 <span class="count-subject-text">
                     <Icon type="ios-people" class="count-icon" />
                     <Icon type="ios-people" class="count-icon" />
-                    人数
+                    班级人数
                 </span>
                 </span>
             </div>
             </div>
             <div class="count-box" style="color:#2db7f5">
             <div class="count-box" style="color:#2db7f5">
-                <span class="count-subject-num">352</span>
+                <span class="count-subject-num">{{overviewInfo.answered}}</span>
                 <span class="count-subject-text">
                 <span class="count-subject-text">
                     <Icon type="md-checkmark-circle" class="count-icon" />
                     <Icon type="md-checkmark-circle" class="count-icon" />
                     已作答
                     已作答
                 </span>
                 </span>
             </div>
             </div>
             <div class="count-box" style="color:#ed4014">
             <div class="count-box" style="color:#ed4014">
-                <span class="count-subject-num">400</span>
+                <span class="count-subject-num">{{overviewInfo.noAnswer}}</span>
                 <span class="count-subject-text">
                 <span class="count-subject-text">
                     <Icon type="md-remove-circle" class="count-icon" />
                     <Icon type="md-remove-circle" class="count-icon" />
                     未作答
                     未作答
                 </span>
                 </span>
             </div>
             </div>
             <div class="count-box" style="color:#19be6b">
             <div class="count-box" style="color:#19be6b">
-                <span class="count-subject-num">158</span>
+                <span class="count-subject-num">{{overviewInfo.scored}}</span>
                 <span class="count-subject-text">
                 <span class="count-subject-text">
                     <Icon type="md-star" class="count-icon" />
                     <Icon type="md-star" class="count-icon" />
                     已评分
                     已评分
                 </span>
                 </span>
             </div>
             </div>
-            <div class="count-box"  style="color:#ff9900">
-                <span class="count-subject-num">58</span>
+            <div class="count-box" style="color:#ff9900">
+                <span class="count-subject-num">{{overviewInfo.noScore}}</span>
                 <span class="count-subject-text">
                 <span class="count-subject-text">
                     <Icon type="ios-star-outline" class="count-icon" />
                     <Icon type="ios-star-outline" class="count-icon" />
                     未评分
                     未评分
                 </span>
                 </span>
             </div>
             </div>
         </div>
         </div>
+        <div v-show="calculating">
+            <p style="text-align: center;color: white;margin: 20px 0px;">
+                成绩数据结算中,
+                <span style="text-decoration: underline;color: #1cc0f3;cursor: pointer;" @click="reload()">
+                    点此刷新
+                </span>
+            </p>
+        </div>
     </div>
     </div>
 </template>
 </template>
 <script>
 <script>
@@ -88,27 +96,152 @@ export default {
         AvgCompare,
         AvgCompare,
         ScoreMatrix
         ScoreMatrix
     },
     },
+    inject: ['reload'],
     props: {
     props: {
         examInfo: {
         examInfo: {
-            default: ()=>{
+            default: () => {
                 return {
                 return {
-                    subjects:[],
-                    targetClassIds:[]
+                    subjects: [],
+                    targetClassIds: []
                 }
                 }
             },
             },
             type: Object
             type: Object
         },
         },
-        overviewInfo:{
-            type:Object,
-            default:()=>{
+        overviewInfo: {
+            type: Object,
+            default: () => {
                 return {
                 return {
-                    total:0,
-                    answered:0,
-                    noAnswer:0,
-                    scored:0,
-                    noScore:0
+                    total: 0,
+                    answered: 0,
+                    noAnswer: 0,
+                    scored: 0,
+                    noScore: 0
+                }
+            }
+        }
+    },
+    data() {
+        return {
+            simpleData: {},
+            allData: {},
+            calculating: false
+        }
+    },
+    methods: {
+        //获取已结束评测简要数据分析
+        findSimpleAna() {
+            let requestData = {
+                id: this.examInfo.id,
+                code: this.examInfo.code.replace('Exam-', '')
+            }
+            this.$api.learnActivity.simpleAna(requestData).then(
+                res => {
+                    if (!res.error) {
+                        if (res.averageMap.length && res.averageMap.length) {
+                            this.calculating = false
+                            for (let i in res.averageMap) {
+                                for (let j in res.averageMap[i].ClassAverage) {
+                                    res.averageMap[i].ClassAverage[j] = parseFloat(res.averageMap[i].ClassAverage[j].toFixed(2))
+                                }
+                                let subject = this.examInfo.papers.find(item => {
+                                    return item.subjectId == res.averageMap[i].subjectId
+                                })
+                                if (subject) {
+                                    res.averageMap[i].subjectId = subject.subjectName
+                                }
+                            }
+                            this.allData[this.examInfo.id] = res
+                            this.simpleData = res
+                        } else {
+                            this.calculating = true
+                            this.$Message.error('数据结算中,请稍后查看')
+                        }
+
+                    } else {
+                        this.$Message.error('API ERROR!')
+                    }
+                },
+                err => {
+                    this.$Message.error('API ERROR!')
+                }
+            ).finally(() => {
+                this.isLoading = false;
+            })
+        },
+    },
+    watch: {
+        examInfo: {
+            handler() {
+                console.log('评测信息:', this.examInfo)
+                if (this.examInfo.progress == 'finish') {
+                    if (this.allData[this.examInfo.id]) {
+                        this.simpleData = this.allData[this.examInfo.id]
+                    } else {
+                        this.findSimpleAna()
+                    }
+                }
+            },
+            deep: true
+        }
+    },
+    computed: {
+        examScore() {
+            if (this.examInfo && this.examInfo.score) {
+                return this.examInfo.score
+            } else {
+                return 0
+            }
+        },
+        avgScore() {
+            if (this.simpleData && this.simpleData.averageMap) {
+                let avg = 0
+                this.simpleData.averageMap.forEach(item => {
+                    let total = item.ClassAverage.reduce((total, num) => {
+                        return total + num
+                    }, 0)
+                    let sAvg = total / item.ClassAverage.length
+                    avg += sAvg
+                })
+                return avg.toFixed(2)
+            } else {
+                return '--'
+            }
+        },
+        stuTotalScores() {
+            if (this.simpleData && this.simpleData.averageTotal) {
+                let total = []
+                this.simpleData.averageTotal.forEach((subItem, i) => {
+                    subItem.total.forEach((sItem, j) => {
+                        if (!total[j]) total[j] = 0
+                        total[j] += sItem
+                    })
+                })
+                return total
+            } else {
+                return []
+            }
+        },
+        scoreSegment() {
+            if (this.stuTotalScores.length) {
+                let segment = []
+                let unit = this.examScore / 10
+                console.log('unit', unit)
+                for (let i = 0; i < 10; i++) {
+                    let startScore = unit * i
+                    let endScore = unit * (i + 1)
+                    let s = this.stuTotalScores.filter(item => {
+                        return item >= startScore && item < endScore
+                    })
+                    segment.push({
+                        name: `${startScore}-${endScore}`,
+                        value: s.length
+                    })
                 }
                 }
+                return segment
+            } else {
+                return []
             }
             }
+
         }
         }
     }
     }
 }
 }

+ 88 - 98
TEAMModelOS/ClientApp/src/view/learnactivity/echarts/AvgCompare.vue

@@ -8,17 +8,41 @@ export default {
         pieData: {
         pieData: {
             type: Array,
             type: Array,
             default: () => {
             default: () => {
-                return [10, 0, 0, 0, 36, 0, 11, 12, 15, 88]
+                return []
             }
             }
         }
         }
     },
     },
     data() {
     data() {
         return {
         return {
             progressPie: undefined,
             progressPie: undefined,
-            option: {
+            defaultSeries: {
+                name: '总分',
+                type: 'line',
+                itemStyle: {
+                    color: '#11C2EE',
+                    width: 2
+                },
+                symbol: 'none',
+                lineStyle: {
+                    type: 'dashed',
+                    width: 0
+                },
+                markLine: {
+                    data: [
+                        { type: 'average' }
+                    ],
+                    lineStyle: {
+                        color: '#11C2EE',
+                        type: 'dashed',
+                        width: 2
+                    }
+                },
+                data: []
+            },
+            defOption: {
                 color: [
                 color: [
-                    "#F72459",
                     "#4ECDC4",
                     "#4ECDC4",
+                    "#F72459",
                     "#F99406",
                     "#F99406",
                     "#075CD0",
                     "#075CD0",
                     "#03C9A8",
                     "#03C9A8",
@@ -31,29 +55,11 @@ export default {
                     "#9A1294",
                     "#9A1294",
                 ],
                 ],
                 legend: {
                 legend: {
-                    // data: ['语文', '数学', '英语']
                     right: 5,
                     right: 5,
-                    data: [
-                        {
-                            name: '语文',
-                            textStyle: {
-                                color: '#FFF'
-                            }
-                        }, {
-                            name: '数学',
-                            textStyle: {
-                                color: '#FFF'
-                            }
-                        }, {
-                            name: '英语',
-                            textStyle: {
-                                color: '#FFF'
-                            }
-                        }
-                    ]
+                    data: []
                 },
                 },
                 title: {
                 title: {
-                    "text": "平均分对比",
+                    "text": "均分统计",
                     "left": 0,
                     "left": 0,
                     "top": 0,
                     "top": 0,
                     "textStyle": {
                     "textStyle": {
@@ -70,14 +76,9 @@ export default {
                     bottom: '0%',
                     bottom: '0%',
                     containLabel: true
                     containLabel: true
                 },
                 },
-                // toolbox: {
-                //     feature: {
-                //         saveAsImage: {}
-                //     }
-                // },
                 xAxis: {
                 xAxis: {
                     type: 'category',
                     type: 'category',
-                    data: ['六年级一班', '六年级二班', '六年级三班', '六年级四班', '六年级五班'],
+                    data: [],
                     axisLine: {
                     axisLine: {
                         lineStyle: {
                         lineStyle: {
                             color: "#FFF"
                             color: "#FFF"
@@ -100,61 +101,14 @@ export default {
                         }
                         }
                     }
                     }
                 },
                 },
-                series: [
-                    {
-                        name: '语文',
-                        type: 'bar',
-                        stack: '总量',
-                        barMaxWidth: 30,
-                        data: [89, 92, 90, 95, 87],
-
-                    },
-                    {
-                        name: '数学',
-                        type: 'bar',
-                        stack: '总量',
-                        barMaxWidth: 30,
-                        data: [98, 90, 95, 92, 87]
-                    },
-                    {
-                        name: '英语',
-                        type: 'bar',
-                        stack: '总量',
-                        barMaxWidth: 30,
-                        data: [85, 89, 88, 92, 99]
-                    },
-                    {
-                        name: '总分',
-                        type: 'line',
-                        itemStyle: {
-                            color: '#11C2EE',
-                            width: 2
-                        },
-                        symbol: 'none',
-                        lineStyle: {
-                            type: 'dashed',
-                            width: 0
-                        },
-                        markLine: {
-                            data: [
-                                { type: 'average' }
-                            ],
-                            lineStyle: {
-                                color: '#11C2EE',
-                                type: 'dashed',
-                                width: 2
-                            }
-                        },
-                        data: [272, 271, 273, 279, 273]
-                    }
-                ]
-            }
+                series: []
+            },
+            newOption:{}
         }
         }
     },
     },
     mounted() {
     mounted() {
         this.progressPie = this.$echarts.init(document.getElementById('ev-avg-compare'))
         this.progressPie = this.$echarts.init(document.getElementById('ev-avg-compare'))
-        this.progressPie.setOption(this.option)
-        let _this = this
+        // this.progressPie.setOption(this.newOption,true)
         let erd11 = elementResizeDetectorMaker()
         let erd11 = elementResizeDetectorMaker()
         erd11.listenTo(document.getElementById("ev-avg-compare"), () => {
         erd11.listenTo(document.getElementById("ev-avg-compare"), () => {
             this.$nextTick(() => {
             this.$nextTick(() => {
@@ -162,41 +116,77 @@ export default {
                 this.progressPie.resize()
                 this.progressPie.resize()
             })
             })
         })
         })
-        this.progressPie.on('legendselectchanged', (params) =>{
-            console.log(params)
-            let active = this.option.series.filter(item=>{
-                if(params.selected[item.name]){
+        this.progressPie.on('legendselectchanged', (params) => {
+            let active = this.newOption.series.filter(item => {
+                if (params.selected[item.name]) {
                     return true
                     return true
-                }else{
+                } else {
                     return false
                     return false
                 }
                 }
             })
             })
             let score = []
             let score = []
-            active.forEach((item)=>{
-                item.data.forEach((scoreItem,index)=>{
-                    if(!score[index]) score[index] = 0
+            active.forEach((item) => {
+                item.data.forEach((scoreItem, index) => {
+                    if (!score[index]) score[index] = 0
                     score[index] += scoreItem
                     score[index] += scoreItem
                 })
                 })
             })
             })
-            console.log('active',active)
-            console.log('score',score)
-            let len = this.option.series.length
-            this.option.series[len-1].data = score
-            this.progressPie.setOption(this.option)
-
+            let len = this.newOption.series.length
+            this.newOption.series[len - 1].data = score
+            this.progressPie.setOption(this.newOption)
         });
         });
     },
     },
     watch: {
     watch: {
         pieData: {
         pieData: {
             handler(n, o) {
             handler(n, o) {
                 this.$nextTick(() => {
                 this.$nextTick(() => {
+                    this.newOption = this._.cloneDeep(this.defOption)
                     if (!this.progressPie) {
                     if (!this.progressPie) {
                         this.progressPie = this.$echarts.init(document.getElementById('ev-avg-compare'))
                         this.progressPie = this.$echarts.init(document.getElementById('ev-avg-compare'))
                     }
                     }
-                    // this.option.series[0].data.forEach((item, index) => {
-                    //     item.value = this.pieData[index]
-                    // })
-                    this.progressPie.setOption(this.option)
+                    //处理
+                    this.pieData.forEach(item => {
+                        this.newOption.legend.data.push({
+                            name: item.subjectId,
+                            textStyle: {
+                                color: '#FFF'
+                            }
+                        })
+                    })
+                    if (this.pieData.length) {
+                        this.newOption.xAxis.data = this.pieData[0].className.map(item => {
+                            return item.name
+                        })
+                    }
+
+                    // this.option.series = []
+                    this.defaultSeries.data = []
+
+                    if (this.pieData.length) {
+                        let subCount = this.pieData.length
+                        let classCount = this.pieData[0].ClassAverage.length
+                        for (let i = 0; i < classCount; i++) {
+                            for (let j = 0; j < subCount; j++) {
+                                if (!this.defaultSeries.data[i]) this.defaultSeries.data[i] = 0
+                                this.defaultSeries.data[i] += this.pieData[j].ClassAverage[i]
+                            }
+                        }
+
+                    }
+                    this.pieData.forEach(item => {
+                        this.newOption.series.push(
+                            {
+                                name: item.subjectId,
+                                type: 'bar',
+                                stack: '总量',
+                                barMaxWidth: 30,
+                                data: item.ClassAverage
+                            }
+                        )
+                    })
+                    this.newOption.series.push(this.defaultSeries)
+                    console.log('option哈哈',this.newOption)
+                    this.progressPie.setOption(this.newOption, true)
                 })
                 })
             },
             },
             deep: true,
             deep: true,

+ 5 - 45
TEAMModelOS/ClientApp/src/view/learnactivity/echarts/ScoreMatrix.vue

@@ -8,7 +8,7 @@ export default {
         pieData: {
         pieData: {
             type: Array,
             type: Array,
             default: () => {
             default: () => {
-                return [10, 0, 0, 0, 36, 0, 11, 12, 15, 88]
+                return []
             }
             }
         }
         }
     },
     },
@@ -71,48 +71,7 @@ export default {
                                 }
                                 }
                             }
                             }
                         },
                         },
-                        data: [
-                            {
-                                value: 0,
-                                name: '0-10'
-                            },
-                            {
-                                value: 0,
-                                name: '11-20'
-                            },
-                            {
-                                value: 0,
-                                name: '21-30'
-                            },
-                            {
-                                value: 0,
-                                name: '31-40'
-                            },
-                            {
-                                value: 0,
-                                name: '41-50'
-                            },
-                            {
-                                value: 0,
-                                name: '51-60'
-                            },
-                            {
-                                value: 0,
-                                name: '61-70'
-                            },
-                            {
-                                value: 0,
-                                name: '71-80'
-                            },
-                            {
-                                value: 0,
-                                name: '81-90'
-                            },
-                            {
-                                value: 0,
-                                name: '91-100'
-                            }
-                        ]
+                        data: []
                     }
                     }
                 ]
                 ]
             }
             }
@@ -133,12 +92,13 @@ export default {
     watch: {
     watch: {
         pieData: {
         pieData: {
             handler(n, o) {
             handler(n, o) {
+                console.log('新的',this.pieData)
                 this.$nextTick(() => {
                 this.$nextTick(() => {
                     if (!this.progressPie) {
                     if (!this.progressPie) {
                         this.progressPie = this.$echarts.init(document.getElementById('ev-score-matrix'))
                         this.progressPie = this.$echarts.init(document.getElementById('ev-score-matrix'))
                     }
                     }
-                    this.option.series[0].data.forEach((item, index) => {
-                        item.value = this.pieData[index]
+                    this.option.series[0].data = this.pieData.filter(item=>{
+                        return item.value > 0
                     })
                     })
                     this.progressPie.setOption(this.option)
                     this.progressPie.setOption(this.option)
                 })
                 })

+ 6 - 0
TEAMModelOS/ClientApp/src/view/schoolmgmt/ClassroomSetting/ClassroomSetting.less

@@ -452,4 +452,10 @@
 }
 }
 .item-tools{
 .item-tools{
     display:none;
     display:none;
+}
+
+.reset-no-btn{
+    display: inline-block;
+    margin-left: 10px;
+    cursor: pointer;
 }
 }

+ 117 - 35
TEAMModelOS/ClientApp/src/view/schoolmgmt/ClassroomSetting/ClassroomSetting.vue

@@ -75,8 +75,6 @@
                                 <span class="primary-text-color">{{$t('schoolBaseInfo.dClass')}}</span>
                                 <span class="primary-text-color">{{$t('schoolBaseInfo.dClass')}}</span>
                             </p>
                             </p>
                         </div>
                         </div>
-                        <!-- 刪除教室 -->
-                        <!--<Icon class="action-btn-icon" :class="curClassIndex == index ? '' : 'hide-icon'" size="19" type="md-trash"/>-->
                     </div>
                     </div>
                     <EmptyData v-if="classroomListShow.length == 0" style="padding-top:120px;"></EmptyData>
                     <EmptyData v-if="classroomListShow.length == 0" style="padding-top:120px;"></EmptyData>
                 </vuescroll>
                 </vuescroll>
@@ -104,8 +102,8 @@
                 <Button v-if="$access.can('admin.*|student-upd')" class="save-btn" :loading="isSaveLoading" icon="md-add" @click="addStuStatus = true" v-show="currentTabIndex == 2">
                 <Button v-if="$access.can('admin.*|student-upd')" class="save-btn" :loading="isSaveLoading" icon="md-add" @click="addStuStatus = true" v-show="currentTabIndex == 2">
                     {{$t('schoolBaseInfo.addStuBtn')}}
                     {{$t('schoolBaseInfo.addStuBtn')}}
                 </Button>
                 </Button>
-                <!-- 除学生 -->
-                <Button v-if="$access.can('admin.*|student-upd')" class="save-btn" style="margin-right:10px;" :loading="isSaveLoading" icon="md-trash" @click="delStudent()" v-show="currentTabIndex == 2">
+                <!-- 除学生 -->
+                <Button v-if="$access.can('admin.*|student-upd')" class="save-btn" style="margin-right:10px;" :loading="isSaveLoading" icon="md-remove-circle" @click="removeStudent(-1)" v-show="currentTabIndex == 2">
                     {{$t('schoolBaseInfo.delStuBtn')}}
                     {{$t('schoolBaseInfo.delStuBtn')}}
                 </Button>
                 </Button>
             </div>
             </div>
@@ -291,6 +289,53 @@
                     </div>
                     </div>
                 </div>
                 </div>
 
 
+                <!--平面位置-->
+                <div class="school-plan-wrap" v-show="currentTabIndex == 1">
+                    <Upload action="" :on-success="uploadSchoolPlan" :before-upload="getFileData">
+                        <Button icon="ios-cloud-upload-outline">{{$t('schoolBaseInfo.uploadPlan')}}</Button>
+                    </Upload>
+                    <div class="school-plan-zoom">
+                        <span @click="defaultSize()">1:1</span>
+                        <Icon type="ios-add-circle-outline" color="white" size="24" @click="bigger()" />
+                        <Icon type="ios-remove-circle-outline" color="white" size="24" @click="smaller()" />
+                    </div>
+                    <div class="school-plan-box" id="school-plan-box">
+                        <canvas id="school-plan" style="cursor:move;" @mousedown="canvasMouseDown" @mousemove="canvasMouseMove" @mouseup="canvasMouseUp" @mouseout="canvasMouseOut">
+                            {{$t('schoolBaseInfo.suportCanvas')}}
+                        </canvas>
+                    </div>
+                </div>
+
+                <!--学生名单-->
+                <div id="sut-list-box" class="dark-iview-table dark-iview-input" style="width:100%;height:100%;" v-show="currentTabIndex == 2">
+                    <vuescroll style="height:100%;" v-if="classroomListShow[curClassIndex] && classroomListShow[curClassIndex].openType == '1'">
+                        <Table :columns="studentColumn" :data="students" @on-selection-change="(selections)=>{delSelections = selections}" :height="tableHeight" class="system-classroom-table" :loading="stuLoading" no-data-text="暂无学生">
+                            <Loading slot="loading" :top="0" bgColor="rgba(103, 103, 103, 0.27)"></Loading>
+                            <template slot-scope="{ row }" slot="picture">
+                                <PersonalPhoto :name="row.name" :picture="row.picture" />
+                            </template>
+                            <template slot-scope="{ row,index }" slot="no">
+                                <span v-show="editIndex !== index">{{row.no}}</span>
+                                <Input v-model="students[index].no" v-show="editIndex == index" style="width: 60px;" type="number" />
+                                <Icon type="md-checkmark" v-show="editIndex == index" @click="confirmSetNo()" class="reset-no-btn" />
+                                <Icon type="md-close" v-show="editIndex == index" @click="cancelSetNo()" class="reset-no-btn" />
+                            </template>
+                            <template slot-scope="{ row ,index}" slot="action">
+                                <div class="item-tools" v-if="$access.can('admin.*|student-upd')">
+                                    <Icon type="md-create" size="18" color="white" @click="resetNo(index)" :title="$t('schoolBaseInfo.editSeat')" />
+                                    <Icon type="md-remove-circle" size="18" color="white" style="margin-left:10px" @click="removeStudent(index)" :title="$t('schoolBaseInfo.delStuBtn')" />
+                                </div>
+                            </template>
+                            <!-- <template slot-scope="{ row, index }" slot="groupId">
+                                <span>{{row.groupId ? row.groupId : '- -'}}</span>
+                            </template>
+                            <template slot-scope="{ row, index }" slot="groupName">
+                                <span>{{row.groupName ? row.groupName : '未分组'}}</span>
+                            </template> -->
+                        </Table>
+                    </vuescroll>
+                    <h2 v-else style="text-align:center;color:#cccccc;width:100%;padding-top:80px;">{{$t('schoolBaseInfo.onClassStu')}}</h2>
+                </div>
             </div>
             </div>
         </div>
         </div>
         <!-- 原来可以创建序号,如果现在调整序列号部分后不需要添加可以删除相关代码 -->
         <!-- 原来可以创建序号,如果现在调整序列号部分后不需要添加可以删除相关代码 -->
@@ -324,7 +369,7 @@ import PersonalPhoto from "@/components/public/personalPhoto/Index.vue"
 import StudentList from '@/components/coursemgt/StudentList.vue'
 import StudentList from '@/components/coursemgt/StudentList.vue'
 export default {
 export default {
     components: {
     components: {
-        PersonalPhoto,StudentList
+        PersonalPhoto, StudentList
     },
     },
     data() {
     data() {
         // 验证只能是字母和数字
         // 验证只能是字母和数字
@@ -341,12 +386,12 @@ export default {
         }
         }
         return {
         return {
             studentColumn: [
             studentColumn: [
-                // {
-                //     title: ' ',
-                //     type: 'selection',
-                //     width: 60,
-                //     align: 'center'
-                // },
+                {
+                    title: ' ',
+                    type: 'selection',
+                    width: 60,
+                    align: 'center'
+                },
                 {
                 {
                     title: ' ',
                     title: ' ',
                     slot: 'picture',
                     slot: 'picture',
@@ -366,7 +411,7 @@ export default {
                 },
                 },
                 {
                 {
                     title: this.$t('courseManage.classroom.studentTableC1'),
                     title: this.$t('courseManage.classroom.studentTableC1'),
-                    key: 'no',
+                    slot: 'no',
                     align: 'center',
                     align: 'center',
                     sortable: true
                     sortable: true
                 },
                 },
@@ -389,14 +434,17 @@ export default {
                     width: '150'
                     width: '150'
                 },
                 },
             ],
             ],
+            editIndex: -1,
+            resetNoBef: 0,
             updHiteachLink: [],
             updHiteachLink: [],
             orgHiteachData: [],
             orgHiteachData: [],
             hiteachData: [],
             hiteachData: [],
             schoolBase: {
             schoolBase: {
                 period: []
                 period: []
             },
             },
-            selections:[],
-            addStuStatus:false,
+            delSelections: [],//需要移除的学生
+            selections: [],//添加的学生
+            addStuStatus: false,
             stuLoading: false,
             stuLoading: false,
             orderBy: 'id',
             orderBy: 'id',
             filterHiteachVer: 'ALL',
             filterHiteachVer: 'ALL',
@@ -588,6 +636,7 @@ export default {
                         'id': this.classroomListShow[this.curClassIndex].id,
                         'id': this.classroomListShow[this.curClassIndex].id,
                         'scope': 'school'
                         'scope': 'school'
                     }
                     }
+                    this.stuLoading = true
                     this.$api.schoolSetting.getClassroomStudent(params).then(
                     this.$api.schoolSetting.getClassroomStudent(params).then(
                         res => {
                         res => {
                             if (res.classrooms.length > 0) {
                             if (res.classrooms.length > 0) {
@@ -597,7 +646,9 @@ export default {
                         err => {
                         err => {
                             this.$Message.error(this.$t('schoolBaseInfo.findStuErr'))
                             this.$Message.error(this.$t('schoolBaseInfo.findStuErr'))
                         }
                         }
-                    )
+                    ).finally(()=>{
+                        this.stuLoading = false
+                    })
                 }
                 }
             } else {
             } else {
                 return []
                 return []
@@ -605,10 +656,55 @@ export default {
         }
         }
     },
     },
     methods: {
     methods: {
+        resetNo(index) {
+            this.editIndex = index
+            this.resetNoBef = this.students[index].no
+        },
+        confirmSetNo() {
+            this.$Message.warning('暂未对接API')
+            this.editIndex = -1
+        },
+        cancelSetNo() {
+            this.students[this.editIndex].no = this.resetNoBef
+            this.editIndex = -1
+        },
+        //移除班级里面的学生
+        removeStudent(index) {
+            let requestParams = {
+                schoolId: this.$store.state.userInfo.schoolCode,
+                students: []
+            }
+            if (index > -1) {
+                requestParams.students.push(this.students[index])
+            } else if (this.delSelections.length > 0) {
+                requestParams.students = this.delSelections
+            }
+            if (requestParams.students.length) {
+                let names = requestParams.students.map(item => {
+                    return item.name
+                })
+                this.$Modal.confirm({
+                    title: this.$t('schoolBaseInfo.removeTile'),
+                    content: `${this.$t('schoolBaseInfo.removeContent')}${names.join(', ')}?`,
+                    onOk: () => {
+                        this.$Message.warning('暂未对接API')
+                        // this.$api.stuAccount.removeStudent(requestParams).then(
+                        //     res => {
+                        //         this.$Message.success(this.$t('schoolBaseInfo.removeOk'))
+                        //     },
+                        //     err => {
+                        //         this.$Message.error(this.$t('schoolBaseInfo.removeErr'))
+                        //     }
+                        // )
+                    }
+                })
+            }
+        },
         //确认添加学生
         //确认添加学生
         confirmAddStu() {
         confirmAddStu() {
             if (this.selections.length > 0) {
             if (this.selections.length > 0) {
                 console.log(this.selections)
                 console.log(this.selections)
+                this.$Message.warning('暂未对接API')
                 //保存操作
                 //保存操作
                 // this.listLoading = true
                 // this.listLoading = true
                 // this.courseListP[this.curCusIndex].code = this.$store.state.userInfo.TEAMModelId
                 // this.courseListP[this.curCusIndex].code = this.$store.state.userInfo.TEAMModelId
@@ -634,6 +730,7 @@ export default {
                 // })
                 // })
             }
             }
         },
         },
+
         dropdownStates(flag) {
         dropdownStates(flag) {
             if (!flag) this.filterByPeriod()
             if (!flag) this.filterByPeriod()
         },
         },
@@ -919,7 +1016,6 @@ export default {
                 let image = new Image()
                 let image = new Image()
                 image.crossOrigin = 'anonymous'
                 image.crossOrigin = 'anonymous'
                 image.src = require('../../../assets/image/school_plan.jpg');
                 image.src = require('../../../assets/image/school_plan.jpg');
-                //image.src = 'https://teammodelstorage.blob.core.chinacloudapi.cn/teammodelos/test/school_plan.jpg'
                 image.onload = function () {
                 image.onload = function () {
                     _this.schoolPlan.width = image.width
                     _this.schoolPlan.width = image.width
                     _this.schoolPlan.height = image.height
                     _this.schoolPlan.height = image.height
@@ -1002,7 +1098,6 @@ export default {
                                         this.$store.dispatch('user/addSchoolClasses', this.classroomListShow[this.curClassIndex]);
                                         this.$store.dispatch('user/addSchoolClasses', this.classroomListShow[this.curClassIndex]);
                                     }
                                     }
                                 }
                                 }
-
                             } else {
                             } else {
                                 this.$Message.error('API error!')
                                 this.$Message.error('API error!')
                             }
                             }
@@ -1030,7 +1125,6 @@ export default {
                             this.updateBefore = JSON.stringify(this.classroomList[0])
                             this.updateBefore = JSON.stringify(this.classroomList[0])
                         }
                         }
                         this.filterClassname()
                         this.filterClassname()
-
                         // 預設搜尋給第一個
                         // 預設搜尋給第一個
                         // this.filterPeriod = res.school_base.period[0].id
                         // this.filterPeriod = res.school_base.period[0].id
                         if (this.periods) this.filterPeriod = this.periods[0].id
                         if (this.periods) this.filterPeriod = this.periods[0].id
@@ -1038,7 +1132,6 @@ export default {
                     }
                     }
                 },
                 },
                 (err) => {
                 (err) => {
-                    console.log(err)
                     this.$Message.error('API error!')
                     this.$Message.error('API error!')
                 }
                 }
             ).finally(() => {
             ).finally(() => {
@@ -1082,17 +1175,14 @@ export default {
                                     break
                                     break
                                 }
                                 }
                             }
                             }
-
                             this.$api.schoolSetting.hiteachUnlinkByClassId({
                             this.$api.schoolSetting.hiteachUnlinkByClassId({
                                 classId: this.classroomListShow[index].id,
                                 classId: this.classroomListShow[index].id,
                                 school_code: this.$store.state.userInfo.schoolCode
                                 school_code: this.$store.state.userInfo.schoolCode
                             })
                             })
                             // this.unlinkHiteach(this.classroomListShow[index].id) // 刪掉指定的classId                                
                             // this.unlinkHiteach(this.classroomListShow[index].id) // 刪掉指定的classId                                
                             this.$store.dispatch('user/delSchoolClasses', this.classroomListShow[index].id);
                             this.$store.dispatch('user/delSchoolClasses', this.classroomListShow[index].id);
-
                             this.classroomList.splice(originIndex, 1)
                             this.classroomList.splice(originIndex, 1)
                             this.classroomListShow.splice(index, 1)
                             this.classroomListShow.splice(index, 1)
-
                             this.$Message.success(this.$t('schoolBaseInfo.csTips7'))
                             this.$Message.success(this.$t('schoolBaseInfo.csTips7'))
                             this.updated = false
                             this.updated = false
                             this.updHiteachLink = []
                             this.updHiteachLink = []
@@ -1151,13 +1241,8 @@ export default {
                 }
                 }
             }
             }
         },
         },
-        isEmpty(obj) {
-            if (typeof obj === 'undefined' || obj == null || obj == '') {
-                return true
-            } else {
-                return false
-            }
-        },
+
+        // 这段代码应该是原来的hiteach序号相关代码,调整之后没用就可以删掉了, 我看没有调用这个方法了
         chooseHiTeach(index) {
         chooseHiTeach(index) {
             if (this.editStatus) {
             if (this.editStatus) {
                 this.$Message.warning('当前为不可编辑状态')
                 this.$Message.warning('当前为不可编辑状态')
@@ -1167,7 +1252,7 @@ export default {
                     if (this.hiTeachs[i].using > 0) {
                     if (this.hiTeachs[i].using > 0) {
                         this.$Message.warning(this.$t('schoolBaseInfo.csTips6'))
                         this.$Message.warning(this.$t('schoolBaseInfo.csTips6'))
                     } else {
                     } else {
-                        if (!this.isEmpty(this.classroomListShow[this.curClassIndex].sn)) {
+                        if (this.classroomListShow[this.curClassIndex].sn) {
                             let showIndex = -1
                             let showIndex = -1
                             let allIndex = -1
                             let allIndex = -1
                             this.hiTeachsShow.forEach((v, i) => {
                             this.hiTeachsShow.forEach((v, i) => {
@@ -1437,7 +1522,6 @@ export default {
     },
     },
     mounted() {
     mounted() {
         this.filterClassname()
         this.filterClassname()
-        // this.filterCode()
         this.initData()
         this.initData()
         this.initHiteachData()
         this.initHiteachData()
         this.tableHeight = document.getElementById('class-list').clientHeight + 45
         this.tableHeight = document.getElementById('class-list').clientHeight + 45
@@ -1460,8 +1544,6 @@ export default {
             next()
             next()
         }
         }
     },
     },
-    watch: {
-    },
     created() {
     created() {
         this.initData()
         this.initData()
         if (this.$access.can('admin.*|classroom-upd')) this.editStatus = this.noStatus
         if (this.$access.can('admin.*|classroom-upd')) this.editStatus = this.noStatus
@@ -1474,8 +1556,8 @@ export default {
 @import "./ClassroomSetting.less";
 @import "./ClassroomSetting.less";
 </style>
 </style>
 <style>
 <style>
-.class-mgt-container .ivu-table-row-hover .item-tools{
-    display:inline-block ;
+.class-mgt-container .ivu-table-row-hover .item-tools {
+    display: inline-block;
     cursor: pointer;
     cursor: pointer;
 }
 }
 .class-info-content
 .class-info-content

+ 9 - 11
TEAMModelOS/ClientApp/src/view/settings/Index.vue

@@ -8,32 +8,32 @@
         <div class="settings-body">
         <div class="settings-body">
             <div class="normal-settings" v-if="activeTab === '0'">
             <div class="normal-settings" v-if="activeTab === '0'">
                 <div class="normal-settings-item">
                 <div class="normal-settings-item">
-                    <span class="item-title">网站语言设定</span>
-                    <span class="item-description">请选择网站要用来显示选单、互动页面以及通知信息的语言</span>
+                    <span class="item-title">{{ $t('settings.langSetting')}}</span>
+                    <span class="item-description">{{ $t('settings.langTips')}}</span>
                     <span class="item-content">
                     <span class="item-content">
                         <Select v-model="cloudSetting.curLang" style="width:200px" @on-change="onSelectLang">
                         <Select v-model="cloudSetting.curLang" style="width:200px" @on-change="onSelectLang">
                             <Option value="zh-cn">中文(简体)</Option>
                             <Option value="zh-cn">中文(简体)</Option>
                             <Option value="zh-tw">中文(繁体)</Option>
                             <Option value="zh-tw">中文(繁体)</Option>
                             <Option value="en-us">English</Option>
                             <Option value="en-us">English</Option>
                         </Select>
                         </Select>
-                        <Checkbox v-model="cloudSetting.isSystemLang" @on-change="onMenuStatusChange">使用您作业系统的语系来展示</Checkbox>
+                        <Checkbox v-model="cloudSetting.isSystemLang" @on-change="onMenuStatusChange">{{ $t('settings.langCheck')}}</Checkbox>
                     </span>
                     </span>
                 </div>
                 </div>
                 <div class="normal-settings-item">
                 <div class="normal-settings-item">
-                    <span class="item-title">网站色彩模式</span>
-                    <span class="item-description">请选择网站显示的色彩模式,以便提供最佳的用户体验</span>
+                    <span class="item-title">{{ $t('settings.themeSetting')}}</span>
+                    <span class="item-description">{{ $t('settings.themeTips')}}</span>
                     <span class="item-content">
                     <span class="item-content">
                         <span :class="['color-item',cloudSetting.curTheme === 'dark' ?  'color-item-active' : '']" @click="onTips('dark')"></span>
                         <span :class="['color-item',cloudSetting.curTheme === 'dark' ?  'color-item-active' : '']" @click="onTips('dark')"></span>
                         <span :class="['color-item',cloudSetting.curTheme === 'light' ?  'color-item-active' : '']" @click="onTips('light')"></span>
                         <span :class="['color-item',cloudSetting.curTheme === 'light' ?  'color-item-active' : '']" @click="onTips('light')"></span>
                     </span>
                     </span>
                 </div>
                 </div>
                 <div class="normal-settings-item">
                 <div class="normal-settings-item">
-                    <span class="item-title">菜单显示设置</span>
-                    <span class="item-description">选择左侧Menu在网站载入时的预设显示模式</span>
+                    <span class="item-title">{{ $t('settings.menuSetting')}}</span>
+                    <span class="item-description">{{ $t('settings.menuTips')}}</span>
                     <span class="item-content">
                     <span class="item-content">
                         <RadioGroup v-model="cloudSetting.menuStatus" @on-change="onMenuStatusChange">
                         <RadioGroup v-model="cloudSetting.menuStatus" @on-change="onMenuStatusChange">
-                            <Radio label="open">预设展开显示</Radio>
-                            <Radio label="close">预设关闭显示</Radio>
+                            <Radio label="open">{{ $t('settings.menuOpen')}}</Radio>
+                            <Radio label="close">{{ $t('settings.menuClose')}}</Radio>
                         </RadioGroup>
                         </RadioGroup>
                     </span>
                     </span>
                 </div>
                 </div>
@@ -139,8 +139,6 @@
                 this.$Modal.confirm({
                 this.$Modal.confirm({
                     title: '提示',
                     title: '提示',
                     content: '设置保存成功,刷新后即可生效,是否前往?',
                     content: '设置保存成功,刷新后即可生效,是否前往?',
-                    okText: '确认',
-                    cancelText: '取消',
                     onOk: () => {
                     onOk: () => {
                         localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
                         localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
                         location.reload()
                         location.reload()

+ 31 - 35
TEAMModelOS/ClientApp/src/view/settings/SchoolMgmt.vue

@@ -3,7 +3,7 @@
 		<Loading v-show="isLoading"></Loading>
 		<Loading v-show="isLoading"></Loading>
 		<div class="school-container-left">
 		<div class="school-container-left">
 			<div class="school-container-header">
 			<div class="school-container-header">
-				<span>已添加或申请学校</span>
+				<span>{{ $t('settings.schoolList')}}</span>
 			</div>
 			</div>
 			<vuescroll>
 			<vuescroll>
 				<div class="school-list-wrap">
 				<div class="school-list-wrap">
@@ -16,33 +16,33 @@
 							<span class="school-item-name">
 							<span class="school-item-name">
 								<span>{{ item.name }}</span>
 								<span>{{ item.name }}</span>
 								<span class="school-item-status" :style='{ background:bgFilter(item.status) }'>{{ statusFilter(item.status) }}</span>
 								<span class="school-item-status" :style='{ background:bgFilter(item.status) }'>{{ statusFilter(item.status) }}</span>
-								<span class="school-item-status" style="background-color: #008352;" v-show="item.schoolId === teacherInfo.defaultschool">默认学校</span>
-								<span class="school-item-status" style="background-color: #f59a2a;" v-show="item.schoolId === curSchool">当前学校</span>
+								<span class="school-item-status" style="background-color: #008352;" v-show="item.schoolId === teacherInfo.defaultschool">{{ $t('settings.defaultSchool')}}</span>
+								<span class="school-item-status" style="background-color: #f59a2a;" v-show="item.schoolId === curSchool">{{ $t('settings.curSchool')}}</span>
 							</span>
 							</span>
 							<span class="school-item-code">{{ item.schoolId  }}</span>
 							<span class="school-item-code">{{ item.schoolId  }}</span>
 							<span class="school-item-nums" v-if="item.status === 'join'">
 							<span class="school-item-nums" v-if="item.status === 'join'">
 								<span>
 								<span>
 									<Icon type="md-bookmarks" />
 									<Icon type="md-bookmarks" />
-									<span>课程数</span>
+									<span>{{ $t('settings.courseNum')}}</span>
 									<span style="margin-left: 10px;">{{ item.course }}</span>
 									<span style="margin-left: 10px;">{{ item.course }}</span>
 								</span>
 								</span>
 								<span style="margin-left: 20px;">
 								<span style="margin-left: 20px;">
 									<Icon type="md-star" />
 									<Icon type="md-star" />
-									<span>活动数</span>
+									<span>{{ $t('settings.activityNum')}}</span>
 									<span style="margin-left: 10px;">{{ item.activity }}</span>
 									<span style="margin-left: 10px;">{{ item.activity }}</span>
 								</span>
 								</span>
 							</span>
 							</span>
 							<span class="school-item-nums" v-if="item.status === 'request'">
 							<span class="school-item-nums" v-if="item.status === 'request'">
-								于 2020-08-02 提出加入请求
+								于 2020-08-02 {{ $t('settings.joinStatus')}}
 							</span>
 							</span>
 							<span class="school-item-nums" v-if="item.status === 'invite'">
 							<span class="school-item-nums" v-if="item.status === 'invite'">
-								于 2020-08-02 送出添加邀请
+								于 2020-08-02 {{ $t('settings.requestStatus')}}
 							</span>
 							</span>
 							<span class="school-item-role">{{ item.role }}</span>
 							<span class="school-item-role">{{ item.role }}</span>
 							<span class="school-item-btn" v-if="item.status === 'join' && item.schoolId !== curSchool" @click="onGoSchool(item)">
 							<span class="school-item-btn" v-if="item.status === 'join' && item.schoolId !== curSchool" @click="onGoSchool(item)">
 								<span>
 								<span>
 									<Icon type="md-swap" style="transform: rotate(90deg);" />
 									<Icon type="md-swap" style="transform: rotate(90deg);" />
-									<span>前往学校</span>
+									<span>{{ $t('settings.goSchool')}}</span>
 								</span>
 								</span>
 							</span>
 							</span>
 <!-- 							<span class="school-item-btn" style="background: rgb(202,54,54);" v-if="item.status === 'request'">
 <!-- 							<span class="school-item-btn" style="background: rgb(202,54,54);" v-if="item.status === 'request'">
@@ -54,13 +54,13 @@
 							<span class="school-item-btn" style="background: #1CC0F3;right: 140px;" v-if="item.status === 'invite'" @click="onConfirmJoin(item)">
 							<span class="school-item-btn" style="background: #1CC0F3;right: 140px;" v-if="item.status === 'invite'" @click="onConfirmJoin(item)">
 								<span>
 								<span>
 									<Icon type="md-checkmark" />
 									<Icon type="md-checkmark" />
-									<span>同意加入</span>
+									<span>{{ $t('settings.agreeJoin')}}</span>
 								</span>
 								</span>
 							</span>
 							</span>
 							<span class="school-item-btn" style="background: rgb(202,54,54);" v-if="item.status === 'invite'">
 							<span class="school-item-btn" style="background: rgb(202,54,54);" v-if="item.status === 'invite'">
 								<span>
 								<span>
 									<Icon type="md-close" />
 									<Icon type="md-close" />
-									<span>取消添加</span>
+									<span>{{ $t('settings.cancelAdd')}}</span>
 								</span>
 								</span>
 							</span>
 							</span>
 						</div>
 						</div>
@@ -70,9 +70,9 @@
 		</div>
 		</div>
 		<div class="school-container-right">
 		<div class="school-container-right">
 			<div class="school-container-header">
 			<div class="school-container-header">
-				<span>申请加入学校</span>
+				<span>{{ $t('settings.requestJoin')}}</span>
 				<div>
 				<div>
-					<Input placeholder="输入要搜索的学校名称" @on-change="onSearchList" v-model="schoolListSearch">
+					<Input :placeholder="$t('settings.inputSearch')" @on-change="onSearchList" v-model="schoolListSearch">
 					<Icon type="ios-search" slot="prefix" />
 					<Icon type="ios-search" slot="prefix" />
 					</Input>
 					</Input>
 				</div>
 				</div>
@@ -83,11 +83,11 @@
 			</div>
 			</div>
 		</div>
 		</div>
 		<Modal v-model="goSchoolModal" class-name="go-school-modal" footer-hide>
 		<Modal v-model="goSchoolModal" class-name="go-school-modal" footer-hide>
-			<p>注意</p>
-			<p>此举动将使您离开当前学校的 IES5 站台,并前往</p>
+			<p>{{ $t('settings.modalTip1')}}</p>
+			<p>{{ $t('settings.modalTip2')}}</p>
 			<p>{{ curSchoolItem ? curSchoolItem.name : '' }}</p>
 			<p>{{ curSchoolItem ? curSchoolItem.name : '' }}</p>
-			<p>当前页面未保存的资料将会丢失,是否同意此操作?</p>
-			<Button @click="onChangeSchool">确定</Button>
+			<p>{{ $t('settings.modalTip3')}}</p>
+			<Button @click="onChangeSchool">{{ $t('evaluation.confirm')}}</Button>
 		</Modal>
 		</Modal>
 
 
 	</div>
 	</div>
@@ -117,24 +117,24 @@
 				schoolList: [],
 				schoolList: [],
 				originSchoolList:[],
 				originSchoolList:[],
 				schoolColumns: [{
 				schoolColumns: [{
-						title: '学校名称',
+						title: this.$t('settings.columnName'),
 						key: 'name',
 						key: 'name',
 						width: 500,
 						width: 500,
 					},
 					},
 					{
 					{
-						title: '地区',
+						title: this.$t('settings.columnArea'),
 						render: (h, params) => {
 						render: (h, params) => {
 							return h('span', params.row.region + '-' +  params.row.province+ '-' + params.row.city);
 							return h('span', params.row.region + '-' +  params.row.province+ '-' + params.row.city);
 						}
 						}
 					},
 					},
 					{
 					{
-						title: '校代码',
+						title: this.$t('settings.columnId'),
 						key: 'id'
 						key: 'id'
 					},
 					},
 					{
 					{
-						title: '操作',
+						title: this.$t('settings.columnTool'),
 						render: (h, params) => {
 						render: (h, params) => {
-							return this.tbStatusFilter(params.row.id) === '申请加入' ? 
+							return this.tbStatusFilter(params.row.id) === this.$t('settings.requestJoin') ? 
 							h('div', [
 							h('div', [
 								h('Button', {
 								h('Button', {
 									props: {
 									props: {
@@ -243,10 +243,8 @@
 			/* 申请加入学校 */
 			/* 申请加入学校 */
 			onJoinSchool(item){
 			onJoinSchool(item){
 				this.$Modal.confirm({
 				this.$Modal.confirm({
-				    title: '温馨提示',
-				    content: '<p>确认申请加入' + item.name + ' ?</p>',
-				    okText: '确认',
-				    cancelText: '取消',
+				    title: this.$t('settings.modalTip4'),
+				    content: this.$t('settings.modalTip5') + item.name + ' ?',
 				    onOk: () => {
 				    onOk: () => {
 						this.$api.schoolSetting.joinSchool({
 						this.$api.schoolSetting.joinSchool({
 							grant_type:'request',
 							grant_type:'request',
@@ -256,13 +254,13 @@
 							(res) => {
 							(res) => {
 								console.log(res)
 								console.log(res)
 								if (!res.error) {
 								if (!res.error) {
-									this.$Message.success("提交成功!")
+									this.$Message.success(this.$t('settings.submitSucTips'))
 									this.initTeacherInfo()
 									this.initTeacherInfo()
 									this.getAllShoolList()
 									this.getAllShoolList()
 								}
 								}
 							},
 							},
 							(err) => {
 							(err) => {
-								this.$Message.error("操作失败!")
+								this.$Message.error(this.$t('settings.submitFailTips'))
 							}
 							}
 						)
 						)
 				    },
 				    },
@@ -275,10 +273,8 @@
 			onConfirmJoin(item){
 			onConfirmJoin(item){
 				console.log(item)
 				console.log(item)
 				this.$Modal.confirm({
 				this.$Modal.confirm({
-				    title: '温馨提示',
-				    content: '<p>确认加入' + item.name + ' ?</p>',
-				    okText: '确认',
-				    cancelText: '取消',
+				    title: this.$t('settings.modalTip4'),
+				    content: this.$t('settings.modalTip5') + item.name + ' ?',
 				    onOk: () => {
 				    onOk: () => {
 						this.$api.schoolSetting.joinSchool({
 						this.$api.schoolSetting.joinSchool({
 							grant_type:'join',
 							grant_type:'join',
@@ -288,7 +284,7 @@
 							async (res) => {
 							async (res) => {
 								console.log(res)
 								console.log(res)
 								if (!res.error) {
 								if (!res.error) {
-									this.$Message.success("加入成功!")
+									this.$Message.success(this.$t('settings.joinSucTips'))
 									// 如果之前用户没有加入任何学校
 									// 如果之前用户没有加入任何学校
 									if(this.mySchoolList.length && this.mySchoolList.filter(i => i.status === 'join').length === 0){
 									if(this.mySchoolList.length && this.mySchoolList.filter(i => i.status === 'join').length === 0){
 										let teacherInfo = await this.getTeacherInfo()
 										let teacherInfo = await this.getTeacherInfo()
@@ -306,7 +302,7 @@
 								}
 								}
 							},
 							},
 							(err) => {
 							(err) => {
-								this.$Message.error("操作失败!")
+								this.$Message.error(this.$t('settings.submitFailTips'))
 							}
 							}
 						)
 						)
 				    },
 				    },
@@ -340,7 +336,7 @@
 		computed: {
 		computed: {
 			statusFilter() { 
 			statusFilter() { 
 				return status => {
 				return status => {
-					return status === 'join' ? '已加入' : status === 'invite' ? '受邀' : '申请中'
+					return status === 'join' ? this.$t('settings.status1') : status === 'invite' ? this.$t('settings.status2') : this.$t('settings.status3')
 				}
 				}
 			},
 			},
 			bgFilter() {
 			bgFilter() {
@@ -354,7 +350,7 @@
 					let isJoin =  this.mySchoolList.filter(i => i.status === 'join').map(j => j.schoolId).indexOf(id)  > -1 
 					let isJoin =  this.mySchoolList.filter(i => i.status === 'join').map(j => j.schoolId).indexOf(id)  > -1 
 					let isInvite =  this.mySchoolList.filter(i => i.status === 'invite').map(j => j.schoolId).indexOf(id)  > -1 
 					let isInvite =  this.mySchoolList.filter(i => i.status === 'invite').map(j => j.schoolId).indexOf(id)  > -1 
 					let isRequest =  this.mySchoolList.filter(i => i.status === 'request').map(j => j.schoolId).indexOf(id)  > -1 
 					let isRequest =  this.mySchoolList.filter(i => i.status === 'request').map(j => j.schoolId).indexOf(id)  > -1 
-					return isJoin ? '已加入' : isInvite ? '收到邀请' : isRequest ? '申请中' : '申请加入'
+					return isJoin ? this.$t('settings.status1') : isInvite ? this.$t('settings.status2') : isRequest ? this.$t('settings.status3') : this.$t('settings.requestJoin')
 				}
 				}
 			},
 			},
 			curSchool(){
 			curSchool(){

+ 1 - 1
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/AchievementAnalysis/AchievementAnalysis.vue

@@ -162,7 +162,7 @@
         },
         },
 
 
         created() {
         created() {
-            
+            this.$parent.$parent.$parent.isShowQuestions = false
         },
         },
         methods: {
         methods: {
 			/* 获取成绩分析模块 -- 及格率统计数据 */
 			/* 获取成绩分析模块 -- 及格率统计数据 */

+ 1 - 3
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/EvaluationList/TotalIndex.vue

@@ -119,9 +119,7 @@
 							<div class="section-title">
 							<div class="section-title">
 								{{ $t("totalAnalysis.ti_title5") }}
 								{{ $t("totalAnalysis.ti_title5") }}
 								<span class="filter-icon" @click="isShowFilter = !isShowFilter">
 								<span class="filter-icon" @click="isShowFilter = !isShowFilter">
-									<Icon type="ios-funnel" />{{
-                    $t("totalAnalysis.echarts_text10")
-                  }}
+									<Icon type="ios-funnel" />{{$t("totalAnalysis.echarts_text10")}}
 								</span>
 								</span>
 							</div>
 							</div>
 							<transition name="indexFade">
 							<transition name="indexFade">

+ 1 - 0
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/KnowledgeAnalysis/KnowledgeAnalysis.vue

@@ -80,6 +80,7 @@
         },
         },
         created() {
         created() {
             this.isShowPie = !(this.knowledgeData.length > 10)
             this.isShowPie = !(this.knowledgeData.length > 10)
+			this.$parent.$parent.$parent.isShowQuestions = false
         },
         },
 
 
         methods: {
         methods: {

+ 1 - 0
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/LevelAnalysis/LevelAnalysis.vue

@@ -65,6 +65,7 @@
         },
         },
         created() {
         created() {
             this.isShowPie = !(this.levelData.length > 10)
             this.isShowPie = !(this.levelData.length > 10)
+			this.$parent.$parent.$parent.isShowQuestions = false
         },
         },
 
 
         methods: {
         methods: {

+ 2 - 0
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/ScatterAnalysis/ScatterAnalysis.vue

@@ -151,6 +151,7 @@
                     this.$refs.scatterTable.exportData(3)
                     this.$refs.scatterTable.exportData(3)
                 }
                 }
             })
             })
+			this.$parent.$parent.$parent.isShowQuestions = false
         },
         },
 
 
         methods: {
         methods: {
@@ -184,6 +185,7 @@
 				analysisJson.students.forEach(stu => {
 				analysisJson.students.forEach(stu => {
 					let obj = {}
 					let obj = {}
 					analysisJson.scatterKey.forEach((key, index) => {
 					analysisJson.scatterKey.forEach((key, index) => {
+						stu.subjects[subjectIndex].scatter[0] = stu.name
 						obj[key] = stu.subjects[subjectIndex].scatter[index]
 						obj[key] = stu.subjects[subjectIndex].scatter[index]
 					})
 					})
 					result.push(obj)
 					result.push(obj)

+ 1 - 1
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/QuestionList.css

@@ -186,7 +186,7 @@
             display:flex;
             display:flex;
             flex-direction:row;
             flex-direction:row;
             flex-wrap:wrap;
             flex-wrap:wrap;
-            margin-top:10px;
+            /* margin-top:10px; */
 			color: #fff;
 			color: #fff;
         }
         }
         .ql-right-box .ql-right-list .ql-right-item {
         .ql-right-box .ql-right-list .ql-right-item {

+ 25 - 11
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/QuestionList.vue

@@ -24,49 +24,52 @@
                         <div class="ql-right-part" v-if="SingleList.length">
                         <div class="ql-right-part" v-if="SingleList.length">
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text2')}}({{sumArr(SingleList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text2')}}({{sumArr(SingleList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <div class="ql-right-items">
                             <div class="ql-right-items">
-                                <span class="ql-right-item" v-for="(item,index) in SingleList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + questionList.indexOf(item)">{{getIndexOrder(item)}}</span>
+                                <span class="ql-right-item" v-for="(item,index) in SingleList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + flatList.indexOf(item)"  :data-order="flatList.indexOf(item)">{{getIndexOrder(item)}}</span>
                             </div>
                             </div>
                         </div>
                         </div>
                         <div class="ql-right-part" v-if="MultipleList.length">
                         <div class="ql-right-part" v-if="MultipleList.length">
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text3')}}({{sumArr(MultipleList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text3')}}({{sumArr(MultipleList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <div class="ql-right-items">
                             <div class="ql-right-items">
-                                <span class="ql-right-item" v-for="(item,index) in MultipleList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + questionList.indexOf(item)">{{getIndexOrder(item)}}</span>
+                                <span class="ql-right-item" v-for="(item,index) in MultipleList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + flatList.indexOf(item)"  :data-order="flatList.indexOf(item)">{{getIndexOrder(item)}}</span>
                             </div>
                             </div>
                         </div>
                         </div>
                         <div class="ql-right-part" v-if="JudgeList.length">
                         <div class="ql-right-part" v-if="JudgeList.length">
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text4')}}({{sumArr(JudgeList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text4')}}({{sumArr(JudgeList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <div class="ql-right-items">
                             <div class="ql-right-items">
-                                <span class="ql-right-item" v-for="(item,index) in JudgeList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + questionList.indexOf(item)">{{getIndexOrder(item)}}</span>
+                                <span class="ql-right-item" v-for="(item,index) in JudgeList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + flatList.indexOf(item)"  :data-order="flatList.indexOf(item)">{{getIndexOrder(item)}}</span>
                             </div>
                             </div>
                         </div>
                         </div>
                         <div class="ql-right-part" v-if="CompleteList.length">
                         <div class="ql-right-part" v-if="CompleteList.length">
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text5')}}({{sumArr(CompleteList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text5')}}({{sumArr(CompleteList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <div class="ql-right-items">
                             <div class="ql-right-items">
-                                <span class="ql-right-item" v-for="(item,index) in CompleteList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + questionList.indexOf(item)">{{getIndexOrder(item)}}</span>
+                                <span class="ql-right-item" v-for="(item,index) in CompleteList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + flatList.indexOf(item)"  :data-order="flatList.indexOf(item)">{{getIndexOrder(item)}}</span>
                             </div>
                             </div>
                         </div>
                         </div>
                         <div class="ql-right-part" v-if="SubjectiveList.length">
                         <div class="ql-right-part" v-if="SubjectiveList.length">
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text6')}}({{sumArr(SubjectiveList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text6')}}({{sumArr(SubjectiveList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <div class="ql-right-items">
                             <div class="ql-right-items">
-                                <span class="ql-right-item" v-for="(item,index) in SubjectiveList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + questionList.indexOf(item)">{{getIndexOrder(item)}}</span>
+                                <span class="ql-right-item" v-for="(item,index) in SubjectiveList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + flatList.indexOf(item)"  :data-order="flatList.indexOf(item)">{{getIndexOrder(item)}}</span>
                             </div>
                             </div>
                         </div>
                         </div>
 						<div class="ql-right-part" v-if="ConnectorList.length">
 						<div class="ql-right-part" v-if="ConnectorList.length">
 						    <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text14')}}({{sumArr(ConnectorList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
 						    <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text14')}}({{sumArr(ConnectorList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
 						    <div class="ql-right-items">
 						    <div class="ql-right-items">
-						        <span class="ql-right-item" v-for="(item,index) in ConnectorList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + questionList.indexOf(item)">{{getIndexOrder(item)}}</span>
+						        <span class="ql-right-item" v-for="(item,index) in ConnectorList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + flatList.indexOf(item)"  :data-order="flatList.indexOf(item)">{{getIndexOrder(item)}}</span>
 						    </div>
 						    </div>
 						</div>
 						</div>
 						<div class="ql-right-part" v-if="CorrectList.length">
 						<div class="ql-right-part" v-if="CorrectList.length">
 						    <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text15')}}({{sumArr(CorrectList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
 						    <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text15')}}({{sumArr(CorrectList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
 						    <div class="ql-right-items">
 						    <div class="ql-right-items">
-						        <span class="ql-right-item" v-for="(item,index) in CorrectList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + questionList.indexOf(item)">{{getIndexOrder(item)}}</span>
+						        <span class="ql-right-item" v-for="(item,index) in CorrectList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + flatList.indexOf(item)"  :data-order="flatList.indexOf(item)">{{getIndexOrder(item)}}</span>
 						    </div>
 						    </div>
 						</div>
 						</div>
                         <div class="ql-right-part" v-if="ComposeList.length">
                         <div class="ql-right-part" v-if="ComposeList.length">
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text7')}}({{sumArr(ComposeList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text7')}}({{sumArr(ComposeList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
                             <div class="ql-right-items">
                             <div class="ql-right-items">
-                                <span class="ql-right-item" v-for="(item,index) in ComposeList" :key="index" @click="handleItemClick(item,$event)" :ref="'indexRef' + questionList.indexOf(item)">{{getIndexOrder(item)}}</span>
+								<!-- 如果是综合题 则需要把小题题序放出来 -->
+								<span v-for="(item,index) in ComposeList" :key="index" style="background-color: none;" class="ql-right-items">
+									<span class="ql-right-item" v-for="(child,childIndex) in item.children" :key="childIndex" @click="handleItemClick(item,$event)" :ref="'indexRef' + (flatList.indexOf(child))"  :data-order="flatList.indexOf(child)">{{getIndexOrder(item)}} - {{ childIndex + 1 }}</span>
+								</span>
                             </div>
                             </div>
                         </div>
                         </div>
                     </div>
                     </div>
@@ -95,6 +98,7 @@
                 optionsData: [],
                 optionsData: [],
                 collapseList: [],
                 collapseList: [],
                 questionList: [],
                 questionList: [],
+				flatList:[],
                 SingleList: [],
                 SingleList: [],
                 MultipleList: [],
                 MultipleList: [],
                 JudgeList: [],
                 JudgeList: [],
@@ -332,11 +336,16 @@
 				// 如果是试题页面过来带有题序 则获取指定题目并进行滚动
 				// 如果是试题页面过来带有题序 则获取指定题目并进行滚动
 				let qIndex = this.$route.query.QIndex
 				let qIndex = this.$route.query.QIndex
 				if (qIndex) {
 				if (qIndex) {
+					let paperItems = fullPaperJson.item
+					let allItems = []
+					paperItems.forEach(i => {
+						allItems = allItems.concat(i.type === 'compose' ? i.children : [i])
+					})
+					this.flatList = allItems
+					console.log('拉平后的题目',allItems)
 					this.$nextTick(() => {
 					this.$nextTick(() => {
-						let listLength = this.questionList.length
-						let index = qIndex > listLength ? (+listLength - 1) :  (+qIndex - 1)
 						setTimeout(() => {
 						setTimeout(() => {
-							this.$refs['indexRef' + index][0].click() // 根据路由携带的题序 来触发对应题序的点击事件 完成滚动
+							this.$refs['indexRef' + (qIndex - 1)][0].click() // 根据路由携带的题序 来触发对应题序的点击事件 完成滚动
 						}, 1000)
 						}, 1000)
 					})
 					})
 				} else {
 				} else {
@@ -373,6 +382,7 @@
 
 
             // 点击右边题序 获取到题目DOM 进行滚动操作
             // 点击右边题序 获取到题目DOM 进行滚动操作
             handleItemClick(item, e) {
             handleItemClick(item, e) {
+				console.log(e)
 				this.$nextTick(() => {
 				this.$nextTick(() => {
 					let parentVm = this.$parent.$parent.$parent
 					let parentVm = this.$parent.$parent.$parent
 					let currentSpan = e.target || e
 					let currentSpan = e.target || e
@@ -387,6 +397,10 @@
 					})
 					})
 					// 将当前选中项修改选中色
 					// 将当前选中项修改选中色
 					currentSpan.style.background = '#139c51'
 					currentSpan.style.background = '#139c51'
+					
+					console.log(itemIndex)
+					console.log(this.$refs.exList)
+					this.$refs.exList.collapseList = [itemIndex]
 				})
 				})
                 
                 
             },
             },

+ 1 - 1
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/TestAnalysis.vue

@@ -278,7 +278,7 @@
             }
             }
         },
         },
         created() {
         created() {
-
+				this.$parent.$parent.$parent.isShowQuestions = false
         },
         },
 
 
         methods: {
         methods: {

+ 1 - 6
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/index.vue

@@ -153,12 +153,6 @@
                 switch (Number(index)) {
                 switch (Number(index)) {
                     case 0:
                     case 0:
                         path = '/total'
                         path = '/total'
-                        // 往Vuex获取模块数据
-						console.log(this.currentExamItem)
-						let vuexAchievement = this.$store.state.totalAnalysis.achievementData
-						if(!vuexAchievement){
-							this.$store.commit('updateCurExam', this.currentExamItem)
-						}
                         this.$store.commit('updateExportTable', [{
                         this.$store.commit('updateExportTable', [{
                             tableRef: 'entryTable',
                             tableRef: 'entryTable',
                             tableName:'进线情况统计'
                             tableName:'进线情况统计'
@@ -300,6 +294,7 @@
 				}
 				}
 			})
 			})
 			this.getTotalAverage()
 			this.getTotalAverage()
+			this.handleDataSelect(0)
 			this.currentExamItem = JSON.parse(localStorage.getItem('curExam'))
 			this.currentExamItem = JSON.parse(localStorage.getItem('curExam'))
 			console.log(this.currentExamItem)
 			console.log(this.currentExamItem)
         },
         },

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

@@ -186,7 +186,6 @@
                 <embed v-else-if="previewFile.extension == 'PDF'" :src="previewFile.url" width="870" height="720" />
                 <embed v-else-if="previewFile.extension == 'PDF'" :src="previewFile.url" width="870" height="720" />
                 <iframe v-else :src="'https://view.officeapps.live.com/op/view.aspx?src=' + escapeBlobUrl" width='870' height='700' frameborder='1'></iframe>
                 <iframe v-else :src="'https://view.officeapps.live.com/op/view.aspx?src=' + escapeBlobUrl" width='870' height='700' frameborder='1'></iframe>
             </div>
             </div>
-
         </div>
         </div>
     </div>
     </div>
 </template>
 </template>

+ 220 - 0
TEAMModelOS/Controllers/Analysis/AchievementController.cs

@@ -22,6 +22,7 @@ using static TEAMModelOS.SDK.Models.Cosmos.Student.StudentAnalysis;
 using TEAMModelOS.SDK.Models.Cosmos.School;
 using TEAMModelOS.SDK.Models.Cosmos.School;
 using static TEAMModelOS.SDK.Models.Cosmos.School.ClassAnalysis;
 using static TEAMModelOS.SDK.Models.Cosmos.School.ClassAnalysis;
 using static TEAMModelOS.SDK.Models.Cosmos.School.GradeAnalysis;
 using static TEAMModelOS.SDK.Models.Cosmos.School.GradeAnalysis;
+using TEAMModelOS.Models.Dto;
 
 
 namespace TEAMModelOS.Controllers.Analysis
 namespace TEAMModelOS.Controllers.Analysis
 {
 {
@@ -2726,6 +2727,225 @@ namespace TEAMModelOS.Controllers.Analysis
                 return BadRequest();
                 return BadRequest();
             }
             }
         }
         }
+
+
+        [HttpPost("import")]
+        public async Task<IActionResult> importIES3(JsonElement request)
+        {
+            //获取评测的ID
+            if (!request.TryGetProperty("exam", out JsonElement exam)) return BadRequest();
+            //if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                ExamDto examDtos = new ExamDto();
+                examDtos = exam.ToObject<ExamDto>();
+                ExamInfo info = new ExamInfo();
+                info.code = info.pk + "-hbcn";
+                info.progress = "pending";
+                info.id = examDtos.id;
+                info.name = examDtos.name;
+                info.grades = examDtos.grades;
+                info.subjects = examDtos.subjects;
+                info.period = examDtos.period;
+                examDtos.targetClasses.ForEach(e => {
+                    info.targetClassIds.Add(e.id);
+                });
+                examDtos.papers.ForEach(p => {
+                    PaperSimple simple = new PaperSimple();
+                    simple.id = p.id;
+                    simple.name = p.name;
+                    p.points.ForEach(po => {
+                        simple.point.Add(double.Parse(po));
+                    });
+                    p.answers.ForEach(an =>
+                    {
+                        List<string> ans = new List<string>();
+                        if (an.Length > 1)
+                        {
+                            char[] aa = an.ToCharArray();
+                            foreach (char a in aa) {
+                                switch (a)
+                                {
+                                    case '1':
+                                        ans.Add("A");
+                                        break;
+                                    case '2':
+                                        ans.Add("B");
+                                        break;
+                                    case '3':
+                                        ans.Add("C");
+                                        break;
+                                    case '4':
+                                        ans.Add("D");
+                                        break;
+                                    default:
+                                        ans.Add("");
+                                        break;
+                                }
+                            }
+                        }
+                        else {
+                            switch (an) {
+                                case "1":
+                                    ans.Add("A");
+                                    break;
+                                case "2":
+                                    ans.Add("B");
+                                    break;
+                                case "3":
+                                    ans.Add("C");
+                                    break;
+                                case "4":
+                                    ans.Add("D");
+                                    break;
+                                default:
+                                    ans.Add("");
+                                    break;
+                            }
+
+                        }
+                        simple.answers.Add(ans);
+                    });
+                    info.papers.Add(simple);
+                });
+                await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(info, new PartitionKey("Exam-hbcn"));
+                return Ok(new { info });
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},analysis/scoring()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
+        [HttpPost("importResult")]
+        public async Task<IActionResult> importClassResult(JsonElement request)
+        {
+            //获取评测的ID
+            if (!request.TryGetProperty("classResult", out JsonElement classResult)) return BadRequest();
+            if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                List<ExamClassResultDto> examClassResultDto = new List<ExamClassResultDto>();
+                examClassResultDto = classResult.ToObject<List<ExamClassResultDto>>();
+                //获取本次评测所有班级作答结果
+                List<ExamClassResult> examClassResults = new List<ExamClassResult>();
+                var queryClass = $"select value(c) from c where c.examId =  '{id}'";
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<ExamClassResult>(queryText: queryClass, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("ExamClassResult-hbcn") }))
+                {
+                    examClassResults.Add(item);
+
+                }
+                foreach (ExamClassResultDto e in examClassResultDto) {
+                    foreach (ExamClassResult ex in examClassResults)
+                    {
+                        if (e.subject.Equals(ex.subjectId))
+                        {
+                            foreach (ClassResults examClass in e.examClassResult)
+                            {
+                                if (examClass.classInfo.id.Equals(ex.info.id))
+                                {
+                                    ex.studentIds = examClass.studentIds;
+                                    List<List<double>> newScores = new List<List<double>>();
+                                    examClass.studentScores.ForEach(sc =>
+                                    {
+                                        List<double> scores = new List<double>();
+                                        if (sc.Count == 0)
+                                        {
+                                            for (int i =0;i< ex.studentScores[0].Count;i++) {
+                                                scores.Add(0);
+                                            }                                          
+                                        }
+                                        else
+                                        {
+                                            sc.ForEach(s =>
+                                            {
+                                                scores.Add(double.Parse(s));
+                                            });
+                                        }                                                                             
+                                        newScores.Add(scores);
+                                    });
+                                    ex.studentScores = newScores;
+                                    int index = 0;
+                                    List<Task<string>> tasks = new List<Task<string>>();
+                                    foreach (List<string> an in examClass.studentAnswers)
+                                    {
+                                        List<string> ans = new List<string>();
+                                        an.ForEach(aa =>
+                                        {
+                                            if (aa.Length > 1)
+                                            {
+                                                char[] str = aa.ToCharArray();
+                                                foreach (char a in aa)
+                                                {
+                                                    switch (a)
+                                                    {
+                                                        case '1':
+                                                            ans.Add("A");
+                                                            break;
+                                                        case '2':
+                                                            ans.Add("B");
+                                                            break;
+                                                        case '3':
+                                                            ans.Add("C");
+                                                            break;
+                                                        case '4':
+                                                            ans.Add("D");
+                                                            break;
+                                                        default:
+                                                            ans.Add("");
+                                                            break;
+                                                    }
+                                                }
+                                            }
+                                            else
+                                            {
+                                                switch (aa)
+                                                {
+                                                    case "1":
+                                                        ans.Add("A");
+                                                        break;
+                                                    case "2":
+                                                        ans.Add("B");
+                                                        break;
+                                                    case "3":
+                                                        ans.Add("C");
+                                                        break;
+                                                    case "4":
+                                                        ans.Add("D");
+                                                        break;
+                                                    default:
+                                                        ans.Add("");
+                                                        break;
+                                                }
+
+                                            }
+
+                                        });
+                                        string FileName = ex.examId + "/" + ex.subjectId + "/" + examClass.studentIds[index];
+                                        string blob =  FileName + "/" + "ans.json";
+                                        tasks.Add(_azureStorage.UploadFileByContainer(ex.school.ToString(), ans.ToJsonString(), "exam", FileName + "/" + "ans.json"));
+                                        ex.studentAnswers[index].Add(blob);
+                                        index++;
+                                    }
+                                    await Task.WhenAll(tasks);
+                                }
+                            }
+                        }
+                    }
+                }
+                foreach (ExamClassResult result in examClassResults) {
+                   await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(result, result.id, new PartitionKey($"{result.code}"));
+                }
+                return Ok(new { examClassResults });
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},analysis/importResult()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
         private List<Dictionary<string, dynamic>> getKnowledgePoint(List<ExamResult> examResults, ExamInfo info)
         private List<Dictionary<string, dynamic>> getKnowledgePoint(List<ExamResult> examResults, ExamInfo info)
         {
         {
             Dictionary<string, object> stuMap = new Dictionary<string, object>
             Dictionary<string, object> stuMap = new Dictionary<string, object>

+ 210 - 6
TEAMModelOS/Controllers/Analysis/AnalysisController.cs

@@ -339,14 +339,23 @@ namespace TEAMModelOS.Controllers.Analysis
                         fieldClassTotal.Add(new KeyValuePair<string, List<double>>(sub, fields));
                         fieldClassTotal.Add(new KeyValuePair<string, List<double>>(sub, fields));
 
 
                     });
                     });
+
                     classStudents.ForEach(x => {
                     classStudents.ForEach(x => {
                         studentIds.Add(x.id);
                         studentIds.Add(x.id);
                         x.classId = classId;
                         x.classId = classId;
                         x.className = classroom.name;
                         x.className = classroom.name;
                         x.gradeId = classroom.gradeId;
                         x.gradeId = classroom.gradeId;
-                        var stu = classroom.students.Where(s => s.id == x.id).First();
-                        x.name = stu.name;
-                        x.no = stu.no;
+                        var stu = classroom.students.Where(s => s.id == x.id).FirstOrDefault();
+                        if (stu != null)
+                        {
+                            x.name = stu.name;
+                            x.no = stu.no;
+                        }
+                        else {
+                            x.name =x.id;
+                            x.no = "-";
+                        }
+                       
                         //标准差
                         //标准差
                         powSum += Math.Pow(x.total - totalAverage, 2);
                         powSum += Math.Pow(x.total - totalAverage, 2);
                         //进线人数
                         //进线人数
@@ -759,8 +768,8 @@ namespace TEAMModelOS.Controllers.Analysis
                 }
                 }
                 e.studentIds.ForEach(s =>
                 e.studentIds.ForEach(s =>
                 {
                 {
-                    if (e.studentScores[i].Sum() != 0)
-                    {
+/*                    if (e.studentScores[i].Sum() != 0)
+                    {*/
                        
                        
                         List<string> info = new List<string>
                         List<string> info = new List<string>
                                 {
                                 {
@@ -819,7 +828,7 @@ namespace TEAMModelOS.Controllers.Analysis
                         KeyValuePair<string, List<string>> keyValue = new KeyValuePair<string, List<string>>(s,info);
                         KeyValuePair<string, List<string>> keyValue = new KeyValuePair<string, List<string>>(s,info);
                         datas.Add(keyValue);
                         datas.Add(keyValue);
 
 
-                    }
+                    //}
                     i++;
                     i++;
                 });
                 });
               return  new KeyValuePair<string,List<KeyValuePair<string,List<string>>>>(e.subjectId,   datas);
               return  new KeyValuePair<string,List<KeyValuePair<string,List<string>>>>(e.subjectId,   datas);
@@ -1634,6 +1643,201 @@ namespace TEAMModelOS.Controllers.Analysis
             KeyValuePair<string, List<KeyValuePair<string, List<double>>>> valuePair = new KeyValuePair<string, List<KeyValuePair<string, List<double>>>>(exam.subjectId, datas);
             KeyValuePair<string, List<KeyValuePair<string, List<double>>>> valuePair = new KeyValuePair<string, List<KeyValuePair<string, List<double>>>>(exam.subjectId, datas);
             return (key1, key2, key3, key4,keyValue, valuePair);
             return (key1, key2, key3, key4,keyValue, valuePair);
         }
         }
+        [HttpPost("simple")]
+        public async Task<IActionResult> simple(JsonElement request)
+        {
+            //获取评测的ID
+            if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
+            if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
+            try
+            {
+                List<Dictionary<string, object>> averageMap = new List<Dictionary<string, object>>();
+                List<Dictionary<string, object>> averageTotal = new List<Dictionary<string, object>>();
+                var client = _azureCosmos.GetCosmosClient();
+                ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{code}"));
+                List<ExamResult> examResults = new List<ExamResult>();
+                var query = $"select c.id,c.name,c.subjectId,c.studentScores,c.studentIds,c.paper,c.classes from c where c.examId =  '{id}' ";
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<ExamResult>(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamResult-{id}") }))
+                {
+                    examResults.Add(item);
+                }
+                foreach (ExamResult result in examResults) {
+                    List<double> ClassAverage = new List<double>();
+                    List<ClassSimple> ClassName = new List<ClassSimple>();
+                    Dictionary<string, object> mapSubject = new Dictionary<string, object>();
+                    Dictionary<string, object> mapClass = new Dictionary<string, object>();
+                    mapClass.Add("subjectId", result.subjectId);
+                    foreach (ClassRange range in result.classes) {
+                        ClassSimple classSimple = new ClassSimple();
+                        classSimple.id = range.id;
+                        classSimple.name = range.name;
+                        ClassName.Add(classSimple);
+                        double totalClass = 0;
+                        for (int i = range.range[0]; i<=range.range[1] ;i++) {
+                            totalClass += result.studentScores[i].Sum();
+                        }
+                        ClassAverage.Add(range.range[1] - range.range[0] + 1 > 0 ? totalClass * 1.0 / (range.range[1] - range.range[0] + 1) : 0);
+                    }
+                    mapClass.Add("className", ClassName);
+                    mapClass.Add("ClassAverage", ClassAverage);
+                    averageMap.Add(mapClass);
+                    List<double> SubjectTotal = new List<double>();
+                    foreach (List<double> score in result.studentScores)
+                    {
+                        SubjectTotal.Add(score.Sum()) ;
+                    }
+                    mapSubject.Add("subjectId", result.subjectId);
+                    mapSubject.Add("total", SubjectTotal);
+                    averageTotal.Add(mapSubject);
+                }
+                return Ok(new { averageMap, averageTotal });
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},analysis/simple()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
+        public class ClassSimple { 
+            public string id { get; set; }
+            public string name { get; set; }
+        }
+
+
+        [HttpPost("studentAnalysis")]
+        public async Task<IActionResult> studentAnalysis(JsonElement request)
+        {
+            //获取个人或者校本
+            if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
+            //评测Id
+            if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
+            if (!request.TryGetProperty("sId", out JsonElement sId)) return BadRequest();
+            if (!request.TryGetProperty("cId", out JsonElement cId)) return BadRequest();
+            if (!request.TryGetProperty("gId", out JsonElement gId)) return BadRequest();
+            try
+            {
+                List<Dictionary<string, object>> averageMap = new List<Dictionary<string, object>>();
+                List<Dictionary<string, object>> averageTotal = new List<Dictionary<string, object>>();
+                List<List<double>> classAllAverage = new List<List<double>>();
+                var client = _azureCosmos.GetCosmosClient();
+                ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{code}"));
+                School school = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<School>(code.ToString(), new PartitionKey($"Base"));
+                List<ExamResult> examResults = new List<ExamResult>();
+                var query = $"select c.id,c.name,c.subjectId,c.studentScores,c.studentIds,c.paper,c.classes from c where c.examId =  '{id}' ";
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<ExamResult>(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamResult-{id}") }))
+                {
+                    examResults.Add(item);
+                }
+                int indexClass = 0;
+                HashSet<string> cla = new HashSet<string>();
+                HashSet<string> stu = new HashSet<string>();
+                double totalScore = 0;
+                List<List<double>> allList = new List<List<double>>();
+                double income = 0;
+                foreach (Period period in school.period)
+                {
+                    if (info.period.id.Equals(period.id))
+                    {
+                        income = period.analysis.income;
+                    }
+                }
+                //获取进线人数
+                int count = (int)System.Math.Round(info.stuCount * (income / 100.0), MidpointRounding.AwayFromZero);
+                foreach (ExamResult result in examResults)
+                {
+                    
+                    List<double> ClassAverage = new List<double>();
+                    List<int> personCount = new List<int>();
+                    List<string> ClassId = new List<string>();
+                    Dictionary<string, object> mapClass = new Dictionary<string, object>();
+                    int index = result.studentIds.IndexOf(sId.ToString());
+                    //个人总分
+                    totalScore += result.studentScores[index].Sum();
+                    mapClass.Add("subjectId", result.subjectId);
+                    double totalGrade = 0;
+                    List<double> gradeScores = new List<double>();
+                    List<List<double>> classScores = new List<List<double>>();
+                    //此处声明集合存储原本的成绩序列
+                    List<List<double>> cScores = new List<List<double>>();
+                    foreach (ClassRange range in result.classes)
+                    {
+                        List<double> scores = new List<double>();
+                        List<double> finalScores = new List<double>();
+                        if (range.gradeId.Equals(gId.ToString(), StringComparison.OrdinalIgnoreCase))
+                        {
+                            ClassId.Add(range.id);
+                            cla.Add(range.id);
+                            double totalClass = 0;
+                            for (int i = range.range[0]; i <= range.range[1]; i++)
+                            {
+                                totalClass += result.studentScores[i].Sum();
+                                scores.Add(result.studentScores[i].Sum());
+                                finalScores.Add(result.studentScores[i].Sum());
+                                gradeScores.Add(result.studentScores[i].Sum());
+                                totalGrade += result.studentScores[i].Sum();
+                                stu.Add(result.studentIds[i]);
+                            }
+                            classScores.Add(scores);
+                            cScores.Add(finalScores);
+                            ClassAverage.Add(range.range[1] - range.range[0] + 1 > 0 ? Math.Round(totalClass * 1.0 / (range.range[1] - range.range[0] + 1),2) : 0);
+                            personCount.Add(range.range[1] - range.range[0] + 1);
+                        }                                
+                    }
+                    classAllAverage.Add(ClassAverage);
+                    gradeScores.Sort((s1, s2) => { return s2.CompareTo(s1); });
+                    indexClass = ClassId.IndexOf(cId.ToString());
+                    //单科成绩
+                    allList.Add(cScores[indexClass]);
+                    classScores[indexClass].Sort((s1, s2) => { return s2.CompareTo(s1); });
+                    mapClass.Add("scoreSum", result.paper.point.Sum());
+                    mapClass.Add("score",result.studentScores[index].Sum());
+                    mapClass.Add("classAverage", ClassAverage[indexClass]);
+                    mapClass.Add("classCount", personCount[indexClass]);
+                    mapClass.Add("classRank", classScores[indexClass].IndexOf(result.studentScores[index].Sum()));
+                    mapClass.Add("gradeAverage", Math.Round(totalGrade*1.0 / result.studentIds.Count,2));
+                    mapClass.Add("gradeCount", result.studentIds.Count);
+                    mapClass.Add("gradeRank", gradeScores.IndexOf(result.studentScores[index].Sum()));
+                    averageMap.Add(mapClass);
+                }
+                //处理班级/年级全科均分
+                List<double> AllAverage = new List<double>();
+                double a = 0;
+                for (int k = 0;k< cla.Count;k++) {
+                    for (int i = 0; i < classAllAverage.Count; i++)
+                    {
+                        a += classAllAverage[i][k];
+                    }
+                    AllAverage.Add(a);
+                }
+                List<double> classScore = new List<double>();
+                for (int i =0; i<allList[0].Count;i++) {
+                    double b = 0;
+                    for (int m = 0; m< allList.Count; m++) {
+                        b += allList[m][i];
+                    }
+                    classScore.Add(b);
+                }
+                classScore.Sort((s1, s2) => { return s2.CompareTo(s1); });
+                //处理年级总分以及排名
+                List<double> GradeScore = new List<double>();
+                foreach (string ss in stu) {
+                    double score = 0;
+                    foreach (ExamResult result in examResults) {
+                        int index = result.studentIds.IndexOf(ss);
+                        score += result.studentScores[index].Sum();
+                    }
+                    GradeScore.Add(score);
+                }
+                GradeScore.Sort((s1, s2) => { return s2.CompareTo(s1); });
+                double ipoint = GradeScore[count];
+                return Ok(new { income = ipoint, rankc = classScore.IndexOf(totalScore),rankg = GradeScore.IndexOf(totalScore), classAverage = Math.Round(AllAverage[indexClass],2), gradeAverage = Math.Round(AllAverage.Sum() * 1.0 / cla.Count,2), averageMap }); ;
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},analysis/studentAnalysis()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
 
 
     }
     }
 }
 }

+ 50 - 9
TEAMModelOS/Controllers/Client/HiTeachController.cs

@@ -170,7 +170,7 @@ namespace TEAMModelOS.Controllers.Client
             {
             {
                 string id_token = HttpContext.GetXAuth("IdToken");
                 string id_token = HttpContext.GetXAuth("IdToken");
                 if (string.IsNullOrEmpty(id_token)) return BadRequest();
                 if (string.IsNullOrEmpty(id_token)) return BadRequest();
-                if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();            
+                if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();       
                 var jwt = new JwtSecurityToken(id_token);
                 var jwt = new JwtSecurityToken(id_token);
                 if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
                 if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
                 var id = jwt.Payload.Sub;
                 var id = jwt.Payload.Sub;
@@ -783,20 +783,56 @@ namespace TEAMModelOS.Controllers.Client
                 if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
                 if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
                 var id = jwt.Payload.Sub;
                 var id = jwt.Payload.Sub;
 
 
-
                 if (!request.TryGetProperty("exam", out JsonElement exam)) return BadRequest();
                 if (!request.TryGetProperty("exam", out JsonElement exam)) return BadRequest();
-                //if (!request.TryGetProperty("examResult", out JsonElement examResult)) return BadRequest();
                 if (!request.TryGetProperty("examClassResult", out JsonElement examClassResult)) return BadRequest();
                 if (!request.TryGetProperty("examClassResult", out JsonElement examClassResult)) return BadRequest();
 
 
                 ExamInfo dbExamInfo = exam.ToObject<ExamInfo>();
                 ExamInfo dbExamInfo = exam.ToObject<ExamInfo>();
-                //ExamResult dbExamResult = examResult.ToObject<ExamResult>();
-                List<ExamClassResult> dbExamClassResultList = examClassResult.ToObject<List<ExamClassResult>>();
+                List<ExamClassResultStudentAnswerArray> dbExamClassResultList = examClassResult.ToObject<List<ExamClassResultStudentAnswerArray>>();
 
 
+                //ExamInfo內容取得、調整
+                string blobContainer = (dbExamInfo.range == "school" && dbExamInfo.scope == "school" && dbExamInfo.school != null) ? dbExamInfo.school : id; //blob容器
+                dbExamInfo.source = "1"; //評測來源固定為  1:課中評量 
+                //UPDATE
                 var examResponse = _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Common").UpsertItemAsync(dbExamInfo, new PartitionKey(dbExamInfo.code)).GetAwaiter().GetResult();
                 var examResponse = _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Common").UpsertItemAsync(dbExamInfo, new PartitionKey(dbExamInfo.code)).GetAwaiter().GetResult();
-                //var examResultResponse = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Common").UpsertItemAsync(dbExamResult, new PartitionKey(dbExamResult.code));
-                foreach (ExamClassResult examClassResultRow in dbExamClassResultList)
-                {
-                    var examClassResultResponse = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Common").UpsertItemAsync(examClassResultRow, new PartitionKey(examClassResultRow.code));
+                
+                //ExamClassResult內容調整
+                foreach (ExamClassResultStudentAnswerArray examClassResultRow in dbExamClassResultList)
+                {
+                    ExamClassResult examClassResultUpd = new ExamClassResult();
+                    examClassResultUpd.pk = examClassResultRow.pk;
+                    examClassResultUpd.code = examClassResultRow.code;
+                    examClassResultUpd.id = examClassResultRow.id;
+                    examClassResultUpd.school = examClassResultRow.school;
+                    examClassResultUpd.examId = examClassResultRow.examId;
+                    examClassResultUpd.subjectId = examClassResultRow.subjectId;
+                    examClassResultUpd.gradeId = examClassResultRow.gradeId;
+                    examClassResultUpd.year = examClassResultRow.year;
+                    examClassResultUpd.info = examClassResultRow.info;
+                    examClassResultUpd.progress = examClassResultRow.progress;
+                    examClassResultUpd.studentIds = examClassResultRow.studentIds;
+                    examClassResultUpd.studentAnswers = new List<List<string>>();
+                    examClassResultUpd.studentScores = examClassResultRow.studentScores;
+                    examClassResultUpd.scope = examClassResultRow.scope;
+                    examClassResultUpd.sum = examClassResultRow.sum;
+
+                    string examId = examClassResultRow.examId;
+                    string subjectId = examClassResultRow.subjectId;
+                    //examClassResult.studentAnswers 將學生答案上傳blob後轉換內容為blob路徑
+                    if (examClassResultRow.studentIds != null && examClassResultRow.studentIds.Count > 0 && examClassResultRow.studentAnswersArray != null && examClassResultRow.studentAnswersArray.Count > 0)
+                    {
+                        for (int i = 0; i < examClassResultRow.studentAnswersArray.Count; i++)
+                        {
+                            string studentId = examClassResultRow.studentIds[i];
+                            string fileName = examId + "/" + subjectId + "/" + studentId;
+                            string blob = fileName + "/" + "ans.json";
+                            await _azureStorage.UploadFileByContainer(blobContainer, examClassResultRow.studentAnswersArray[i].ToJsonString(), "exam", blob, false);
+                            List<string> studenrAnswerRow = new List<string>();
+                            studenrAnswerRow.Add(blob);
+                            examClassResultUpd.studentAnswers.Add(studenrAnswerRow);
+                        }
+                    }
+                    //UPDATE
+                    var examClassResultResponse = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Common").UpsertItemAsync(examClassResultUpd, new PartitionKey(examClassResultUpd.code));
                 }
                 }
 
 
                 return Ok(new { error, message });
                 return Ok(new { error, message });
@@ -874,5 +910,10 @@ namespace TEAMModelOS.Controllers.Client
             }
             }
         }
         }
 
 
+        public class ExamClassResultStudentAnswerArray : ExamClassResult
+        {
+            public List<List<List<string>>> studentAnswersArray { get; set; }
+        }
+
     }
     }
 }
 }

+ 21 - 5
TEAMModelOS/Controllers/Common/ExamController.cs

@@ -73,7 +73,7 @@ namespace TEAMModelOS.Controllers
                     int count = 0;
                     int count = 0;
                     for (int i = 0; i < request.targetClassIds.Count; i++)
                     for (int i = 0; i < request.targetClassIds.Count; i++)
                     {
                     {
-                        if (request.scope.Equals("private"))
+                        if (request.scope.Equals("private") || request.scope.Equals("teacher"))
                         {
                         {
                              var sresponse = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(request.targetClassIds[i], new PartitionKey($"Class-{code}"));
                              var sresponse = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(request.targetClassIds[i], new PartitionKey($"Class-{code}"));
                             if (sresponse.Status == 200)
                             if (sresponse.Status == 200)
@@ -343,6 +343,7 @@ namespace TEAMModelOS.Controllers
                     standard = simple.answers;
                     standard = simple.answers;
                     points = simple.point;
                     points = simple.point;
                 }
                 }
+                List<Task<string>> tasks = new List<Task<string>>();
                 foreach (ExamClassResult result in examClassResults) {
                 foreach (ExamClassResult result in examClassResults) {
                     int index = result.studentIds.IndexOf(studentId.ToString());
                     int index = result.studentIds.IndexOf(studentId.ToString());
                     //classResult.studentAnswers[index] = ans;
                     //classResult.studentAnswers[index] = ans;
@@ -359,11 +360,25 @@ namespace TEAMModelOS.Controllers
                         result.studentAnswers.Add(new List<string>());
                         result.studentAnswers.Add(new List<string>());
                         result.sum.Add(0);
                         result.sum.Add(0);
                     }
                     }
-                    int newIndex = result.studentIds.IndexOf(studentId.ToString());
-                    string FileName = result.examId + "/" + result.subjectId+"/" +studentId ;
-                    string blob = await _azureStorage.UploadFileByContainer(school.ToString(), ans.ToJsonString(), "exam", FileName +"/"+ "ans.json");
-                    result.studentAnswers[newIndex].Add(blob);
+                    //int flagCount = 0;
+                    /*foreach (List<string> str in ans) {
 
 
+                            if (str.Count == 0) {
+                                flagCount++;
+                        }
+                    }    */                
+                    int newIndex = result.studentIds.IndexOf(studentId.ToString());
+                    /*if (flagCount != standard.Count)
+                    {*/
+/*                    StringBuilder builder = new StringBuilder();
+                    builder.Append(result.examId + "/");
+                    builder.Append(result.subjectId + "/");
+                    builder.Append(studentId);*/
+                        string FileName = result.examId + "/" + result.subjectId + "/" + studentId;
+                        string blob = FileName + "/" + "ans.json";
+                        tasks.Add(_azureStorage.UploadFileByContainer(school.ToString(), ans.ToJsonString(), "exam", FileName + "/" + "ans.json", false));
+                        result.studentAnswers[newIndex].Add(blob);
+                    //}                  
                     for (int i = 0; i < ans.Count; i++)
                     for (int i = 0; i < ans.Count; i++)
                     {                         
                     {                         
                         //result.studentAnswers[index][i] = ans[i];
                         //result.studentAnswers[index][i] = ans[i];
@@ -513,6 +528,7 @@ namespace TEAMModelOS.Controllers
                     result.sum[newIndex] = result.studentScores[newIndex].Sum();
                     result.sum[newIndex] = result.studentScores[newIndex].Sum();
                     classResult = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(result, result.id, new PartitionKey($"{result.code}"));
                     classResult = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(result, result.id, new PartitionKey($"{result.code}"));
                 }
                 }
+                await Task.WhenAll(tasks);
                 
                 
                 return Ok(new { classResult });
                 return Ok(new { classResult });
             }
             }

+ 112 - 4
TEAMModelOS/Controllers/Core/BlobController.cs

@@ -16,6 +16,10 @@ using TEAMModelOS.SDK.Extension;
 using System.IdentityModel.Tokens.Jwt;
 using System.IdentityModel.Tokens.Jwt;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Authorization;
 using TEAMModelOS.Filter;
 using TEAMModelOS.Filter;
+using StackExchange.Redis;
+using Azure.Messaging.ServiceBus;
+using static TEAMModelOS.SDK.DI.AzureStorageBlobExtensions;
+using System.Linq;
 
 
 namespace TEAMModelOS.Controllers.Core
 namespace TEAMModelOS.Controllers.Core
 {
 {
@@ -26,11 +30,14 @@ namespace TEAMModelOS.Controllers.Core
 
 
         private readonly AzureStorageFactory _azureStorage;
         private readonly AzureStorageFactory _azureStorage;
         private readonly IHttpClientFactory _clientFactory;
         private readonly IHttpClientFactory _clientFactory;
-
-        public BlobController(AzureStorageFactory azureStorage, IHttpClientFactory clientFactory)
+        private readonly AzureRedisFactory _azureRedis;
+        private readonly AzureServiceBusFactory _serviceBus;
+        public BlobController(AzureStorageFactory azureStorage, AzureServiceBusFactory serviceBus, IHttpClientFactory clientFactory, AzureRedisFactory azureRedis)
         {
         {
             _azureStorage = azureStorage;
             _azureStorage = azureStorage;
             _clientFactory = clientFactory;
             _clientFactory = clientFactory;
+            _serviceBus = serviceBus;
+            _azureRedis = azureRedis;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -231,10 +238,111 @@ namespace TEAMModelOS.Controllers.Core
         public async Task<ActionResult> GetBlobsSize(JsonElement request)
         public async Task<ActionResult> GetBlobsSize(JsonElement request)
         {
         {
             request.TryGetProperty("containerName", out JsonElement containerName);
             request.TryGetProperty("containerName", out JsonElement containerName);
+            request.TryGetProperty("cache", out JsonElement cache);
             var name =containerName.GetString();
             var name =containerName.GetString();
+            try {
+                if (cache.GetBoolean())
+                {
+                    long blobsize = 0;
+                    RedisValue value = default;
+                    value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", name);
+                    if (value != default && !value.IsNullOrEmpty)
+                    {
+                        JsonElement record = value.ToString().ToObject<JsonElement>();
+                        if (record.TryGetInt64(out  blobsize))
+                        {
+                           
+                        }
+                    }
+                    Dictionary<string, double> catalog = new Dictionary<string, double>();
+                    SortedSetEntry[] Scores = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Blob:Catalog:{name}");
+                    if (Scores != null )
+                    {
+                        foreach (var score in Scores) {
+                            double val = score.Score;
+                            string key = score.Element.ToString();
+                            catalog.Add(key, val);
+                        }   
+                    }
+                    return Ok(new { size = blobsize, catalog= catalog });
+                }
+            } catch { }
             var client = _azureStorage.GetBlobContainerClient(name);
             var client = _azureStorage.GetBlobContainerClient(name);
-            var size = await client.GetBlobsSize();
-            return Ok(new { size });
+            var size = await client.GetBlobsCatalogSize();
+            await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", name, size.Item1);
+            foreach (var key in size.Item2.Keys) {
+                await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{name}", key);
+                await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", key, size.Item2[key].HasValue?size.Item2[key].Value:0);
+            }
+            return Ok(new { size = size.Item1, catalog = size.Item2 });
+        }
+
+        /// <summary>
+        /// 测试单个文本内容的上传
+        /// {"containerName":"hbcn","urls":["video/xxx.mp4","res/xxx.png"]}
+        /// </summary>
+        /// <param name="azureBlobSASDto"></param>
+        /// <returns></returns>
+        [HttpPost("check-blobsize")]
+        public async Task<ActionResult> checkBlobsSize(JsonElement request)
+        {
+            request.TryGetProperty("containerName", out JsonElement containerName);
+            request.TryGetProperty("urls", out JsonElement optUrls);
+            var name = containerName.GetString();
+            var urls = optUrls.ToObject<List<string>>();
+            var client = _azureStorage.GetBlobContainerClient(name);
+            var urlsSize = await client.GetBlobsSize(urls);
+            return Ok(new {  urlsSize });
+        }
+
+        /*
+         * 
+         {
+            "containerName": "hbcn",
+            "cache": true,
+            "optUrls": [
+                {
+                    "url": "video%2F37Z888piCvm9.mp4",
+                    "size": 1000
+                }
+            ]
+         }
+        */
+        /// <summary>
+        /// 测试单个文本内容的上传
+        /// {"containerName":"hbcn","uploadSize":5000,"optUrls":[{"url":"video/37Z888piCvm9.mp4","size":0},{}]}
+        /// </summary>
+        /// <param name="azureBlobSASDto"></param>
+        /// <returns></returns>
+        [HttpPost("update-blobsize")]
+        public async Task<ActionResult> updateBlobsSize(JsonElement request)
+        {
+            request.TryGetProperty("containerName", out JsonElement containerName);
+            request.TryGetProperty("optUrls", out JsonElement optUrls);
+            var name = containerName.GetString();
+            var urls = optUrls.ToObject<List<OptUrl>>();
+            var client = _azureStorage.GetBlobContainerClient(name);
+            var disSize = urls.Select(x => x.size).Sum();
+            RedisValue value = default;
+            long blobSize = 0;
+            value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", name);
+            if (value != default && !value.IsNullOrEmpty)
+            {
+                JsonElement record = value.ToString().ToObject<JsonElement>();
+                if (record.TryGetInt64(out blobSize))
+                {
+                }
+            }
+            long? useSize = blobSize + disSize;
+            await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", name, useSize);
+             
+            foreach (var x in urls) {
+                await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", System.Web.HttpUtility.UrlDecode(x.url, Encoding.UTF8).Split("/")[0], x.size);
+            }
+            var messageBlob = new ServiceBusMessage(new {id=Guid.NewGuid().ToString(), progress = "update",name=name}.ToJsonString());
+            messageBlob.ApplicationProperties.Add("name", "Blob");
+            await _serviceBus.GetServiceBusClient().SendMessageAsync("active-task", messageBlob);
+            return Ok(new { size=useSize });
         }
         }
 
 
         private static (string, string) BlobUrlString(string sasUrl)
         private static (string, string) BlobUrlString(string sasUrl)

+ 1 - 1
TEAMModelOS/Controllers/Core/ImportController.cs

@@ -356,7 +356,7 @@ namespace TEAMModelOS.Controllers
         public string thumbnail { get; set; }
         public string thumbnail { get; set; }
         //  public int page { get; set; }
         //  public int page { get; set; }
         // public Dictionary<string, Store> stores { get; set; }
         // public Dictionary<string, Store> stores { get; set; }
-        public List<string> points { get; set; }
+        public List<string> knowledge { get; set; }
         public string periodId { get; set; }
         public string periodId { get; set; }
         public List<string> gradeIds { get; set; }
         public List<string> gradeIds { get; set; }
         public string subjectId { get; set; }
         public string subjectId { get; set; }

+ 1 - 1
TEAMModelOS/JsonFile/Core/LangConfigV3.json

@@ -38,7 +38,7 @@
           "judge": "是非題",
           "judge": "是非題",
           "complete": "填充題",
           "complete": "填充題",
           "subjective": "問答題",
           "subjective": "問答題",
-          "connector": "連題",
+          "connector": "連題",
           "correct": "改錯題"
           "correct": "改錯題"
         },
         },
         "Answer": "答案",
         "Answer": "答案",

+ 24 - 0
TEAMModelOS/Models/Dto/ExamClassResultDto.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.Models.Dto
+{
+    public class ExamClassResultDto
+    {
+        public string subject { get; set; }
+        public List<ClassResults> examClassResult { get; set; } = new List<ClassResults>();
+    }
+    public class ClassResults
+    {
+        public ClassInfo classInfo { get; set; } = new ClassInfo();
+        public List<string> studentIds { get; set; } = new List<string>();
+        public List<List<string>> studentAnswers { get; set; } = new List<List<string>>();
+        public List<List<string>> studentScores { get; set; } = new List<List<string>>();
+    }
+    public class ClassInfo { 
+        public string id { get; set; }
+        public string name { get; set; }
+    }
+}

+ 33 - 0
TEAMModelOS/Models/Dto/ExamDto.cs

@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.Models;
+
+namespace TEAMModelOS.Models.Dto
+{
+    public class ExamDto
+    {
+        public string id { get; set; }
+        public string name { get; set; }
+        public List<Grade> grades { get; set; } = new List<Grade>();
+        public List<TargetClass> targetClasses { get; set; } = new List<TargetClass>();
+        public List<Papers> papers { get; set; } = new List<Papers>();
+        public List<ExamSubject> subjects { get; set; } = new List<ExamSubject>();
+        public PeriodSimple period { get; set; } = new PeriodSimple();
+
+    }
+    public class TargetClass {
+        public string id { get; set; }
+        public string name { get; set; }
+    }
+    public class Papers
+    {
+        public string id { get; set; }
+        public string name { get; set; }
+        public string itemCount { get; set; }
+        public List<string> points { get; set; } = new List<string>();
+        public List<string> answers { get; set; } = new List<string>();
+
+    }
+}

+ 1 - 2
TEAMModelOS/TEAMModelOS.csproj

@@ -7,7 +7,7 @@
     <PackageReference Include="Caching.CSRedis" Version="3.6.50" />
     <PackageReference Include="Caching.CSRedis" Version="3.6.50" />
     <PackageReference Include="CSRedisCore" Version="3.6.5" />
     <PackageReference Include="CSRedisCore" Version="3.6.5" />
     <PackageReference Include="DotNetZip" Version="1.15.0" />
     <PackageReference Include="DotNetZip" Version="1.15.0" />
-    <PackageReference Include="HTEXLib" Version="2.3.1" />
+    <PackageReference Include="HTEXLib" Version="2.3.4" />
     <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
     <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
       <PackageReference Include="VueCliMiddleware" Version="3.1.2" />  </ItemGroup>
       <PackageReference Include="VueCliMiddleware" Version="3.1.2" />  </ItemGroup>
   <PropertyGroup>
   <PropertyGroup>
@@ -51,7 +51,6 @@
   <ItemGroup>
   <ItemGroup>
     <Folder Include="JwtRsaFile\" />
     <Folder Include="JwtRsaFile\" />
     <Folder Include="Services\Evaluation\" />
     <Folder Include="Services\Evaluation\" />
-    <Folder Include="wwwroot\" />
   </ItemGroup>
   </ItemGroup>
   
   
   <ItemGroup>
   <ItemGroup>

+ 1 - 1
TEAMModelOS/appsettings.Development.json

@@ -31,7 +31,7 @@
       "ScanModel": [ "TEAMModelOS" ]
       "ScanModel": [ "TEAMModelOS" ]
     },
     },
     "Redis": {
     "Redis": {
-      "ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True"
+      "ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False"
       //"ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False,defaultDatabase=8,writeBuffer=10240,poolsize=50"
       //"ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False,defaultDatabase=8,writeBuffer=10240,poolsize=50"
     },
     },
     "ServiceBus": {
     "ServiceBus": {

+ 1 - 1
TEAMModelOS/appsettings.json

@@ -30,7 +30,7 @@
       "ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;"     
       "ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;"     
     },
     },
     "Redis": {
     "Redis": {
-      "ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False"
+      "ConnectionString": "teammodel.redis.cache.chinacloudapi.cn:6380,password=9wcTVDiAWiAf0IF5NOjZBvYrZe9JlbEw1E3F1QFcNbo=,ssl=True,abortConnect=False"
     },
     },
     "ServiceBus": {
     "ServiceBus": {
       "ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
       "ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",