瀏覽代碼

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

osbert 4 年之前
父節點
當前提交
1ae430e2bf
共有 100 個文件被更改,包括 6312 次插入3061 次删除
  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/BaseItem.cs
  8. 1 1
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Exercise.cs
  9. 1 1
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Repair.cs
  10. 1 1
      TEAMModelOS.SDK/Models/Cosmos/Common/ItemInfo.cs
  11. 4 4
      TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs
  12. 72 0
      TEAMModelOS.SDK/Models/Cosmos/School/Knowledge.cs
  13. 8 0
      TEAMModelOS/ClientApp/src/api/learnActivity.js
  14. 4 0
      TEAMModelOS/ClientApp/src/api/stuAccount.js
  15. 12 2
      TEAMModelOS/ClientApp/src/api/studentWeb.js
  16. 23 0
      TEAMModelOS/ClientApp/src/assets/iconfont/demo_index.html
  17. 12 7
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css
  18. 二進制
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.eot
  19. 1 1
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.js
  20. 7 0
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.json
  21. 3 0
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.svg
  22. 二進制
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.ttf
  23. 二進制
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff
  24. 二進制
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff2
  25. 4 2
      TEAMModelOS/ClientApp/src/boot-app.js
  26. 355 329
      TEAMModelOS/ClientApp/src/common/BaseCanvas.vue
  27. 40 40
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  28. 37 1
      TEAMModelOS/ClientApp/src/common/BaseMyCanvas.vue
  29. 146 105
      TEAMModelOS/ClientApp/src/common/NewUploadFile.vue
  30. 496 0
      TEAMModelOS/ClientApp/src/common/UploadModal.vue
  31. 1 1
      TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.less
  32. 6 14
      TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.vue
  33. 415 425
      TEAMModelOS/ClientApp/src/components/selflearn/ExerciseList.vue
  34. 549 596
      TEAMModelOS/ClientApp/src/components/selflearn/NewChooseContent.vue
  35. 25 13
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseKnowledgeDetail.vue
  36. 0 1
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseKnowledgeRadar.vue
  37. 97 94
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseLevelPie.vue
  38. 160 164
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseLevelRadar.vue
  39. 15 13
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseMyTable.vue
  40. 17 15
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseRadar.vue
  41. 1 1
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseScatter.vue
  42. 1 2
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContent.vue
  43. 236 144
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue
  44. 178 80
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReportCharts/StudentScore.vue
  45. 24 25
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperTest.vue
  46. 11 9
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperView.vue
  47. 16 5
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/composePaper.vue
  48. 33 126
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventList.vue
  49. 0 2
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventOverView/EventFinishedNumChart.vue
  50. 0 19
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventOverView/EventLatest.vue
  51. 2 15
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventView.vue
  52. 3 3
      TEAMModelOS/ClientApp/src/components/student-web/EventView/PreviewProgressPie.vue
  53. 0 4
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/CourseListView.vue
  54. 9 29
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/HomeView.vue
  55. 14 37
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/MissionListCard.vue
  56. 15 0
      TEAMModelOS/ClientApp/src/css/site.css
  57. 2 4
      TEAMModelOS/ClientApp/src/locale/index.js
  58. 5 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/global.js
  59. 6 2
      TEAMModelOS/ClientApp/src/locale/lang/en-US/index.js
  60. 182 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/learnActivity.js
  61. 11 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolBaseInfo.js
  62. 181 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/serviceDriveAuth.js
  63. 0 8
      TEAMModelOS/ClientApp/src/locale/lang/en-US/seviceDriveAuth.js
  64. 265 216
      TEAMModelOS/ClientApp/src/locale/lang/en-US/studentWeb.js
  65. 38 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/system.js
  66. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/totalAnalysis.js
  67. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/courseManage.js
  68. 229 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/evaluation.js
  69. 13 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/global.js
  70. 10 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/index.js
  71. 182 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/learnActivity.js
  72. 79 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/schoolBaseInfo.js
  73. 181 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/serviceDriveAuth.js
  74. 38 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/settings.js
  75. 0 8
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/seviceDriveAuth.js
  76. 83 30
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/studentWeb.js
  77. 38 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/system.js
  78. 6 4
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/totalAnalysis.js
  79. 229 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/evaluation.js
  80. 5 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/global.js
  81. 6 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/index.js
  82. 187 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/learnActivity.js
  83. 96 15
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/schoolBaseInfo.js
  84. 182 7
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/serviceDriveAuth.js
  85. 38 3
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/settings.js
  86. 95 44
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/studentWeb.js
  87. 38 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/system.js
  88. 231 231
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/totalAnalysis.js
  89. 137 33
      TEAMModelOS/ClientApp/src/static/Global.js
  90. 8 0
      TEAMModelOS/ClientApp/src/store/module/serviceDriveAuth.js
  91. 12 11
      TEAMModelOS/ClientApp/src/store/module/spaceAuth.js
  92. 36 0
      TEAMModelOS/ClientApp/src/store/module/totalAnalysis.js
  93. 0 6
      TEAMModelOS/ClientApp/src/utils/MathJax.js
  94. 109 62
      TEAMModelOS/ClientApp/src/utils/blobTool.js
  95. 5 4
      TEAMModelOS/ClientApp/src/utils/editorTools.js
  96. 64 22
      TEAMModelOS/ClientApp/src/utils/evTools.js
  97. 10 2
      TEAMModelOS/ClientApp/src/utils/js-fn.js
  98. 1 1
      TEAMModelOS/ClientApp/src/utils/kityformula.js
  99. 85 1
      TEAMModelOS/ClientApp/src/utils/public.js
  100. 0 0
      TEAMModelOS/ClientApp/src/view/evaluation/bank/ExerciseList.vue

+ 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}"));
             List<ExamClassResult> examClassResults = new List<ExamClassResult>();
             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 } });
             //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)
                     {
-                        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();

+ 33 - 1
TEAMModelFunction/MonitorServicesBus.cs

@@ -6,6 +6,7 @@ using Azure.Cosmos;
 using Microsoft.Azure.WebJobs;
 using Microsoft.Azure.WebJobs.Host;
 using Microsoft.Extensions.Logging;
+using StackExchange.Redis;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models;
@@ -16,10 +17,16 @@ namespace TEAMModelFunction
     {
         private readonly AzureCosmosFactory _azureCosmos;
         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;
             _dingDing = dingDing;
+            _azureStorage = azureStorage;
+            _azureRedis = azureRedis;
         }
         [FunctionName("Exam")]
         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.醍摩豆服務運維群組);
             }
         }
+        [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.AddAzureStorage(Environment.GetEnvironmentVariable("Azure:Starage: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>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <AzureFunctionsVersion>v3</AzureFunctionsVersion>
+    <_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
   </PropertyGroup>
   <ItemGroup>
     <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:ServiceBus:ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
     "Azure:Cosmos:ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;",
+    "Azure:Redis:ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False",
     "FUNCTIONS_WORKER_RUNTIME": "dotnet",
     "ScanModel": "TEAMModelOS",
     "Database": "TEAMModelOS"

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

@@ -11,6 +11,8 @@ using System.IO;
 using Azure.Storage.Blobs.Specialized;
 using System.Collections.Generic;
 using System.Linq;
+using System.Text;
+using Azure.Core;
 
 namespace TEAMModelOS.SDK.DI
 {
@@ -26,7 +28,8 @@ namespace TEAMModelOS.SDK.DI
             long? size = 0;
             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;
                 };
@@ -37,6 +40,70 @@ namespace TEAMModelOS.SDK.DI
                 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>        
         /// 批量刪除Blobs
         /// </summary>      

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

@@ -23,7 +23,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
         /// </summary>
         public string pid { get; set; }
         //管理知识点
-        public List<string> points { get; set; }
+        public List<string> knowledge { get; set; }
         //认知层次 应用 综合 理解 评鉴 知识
         public int? field { get; set; }
 

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

@@ -14,7 +14,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
             pk = "Item";
             children = new List<string>();
             answer = new List<string>();
-            points = new List<string>();
+            knowledge = new List<string>();
             gradeIds = new List<string>();
             repair = new List<Repair>();
         }

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

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

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/ItemInfo.cs

@@ -15,7 +15,7 @@ namespace TEAMModelOS.SDK.Models
             children = new List<ItemInfo>();
             option = new List<CodeValue>();
             answer = new List<string>();
-            points = new List<string>();
+            knowledge = new List<string>();
             gradeIds = new List<string>();
             repair = new List<Repair>();
         }

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

@@ -97,10 +97,10 @@ namespace TEAMModelOS.SDK.Models
         public string scope { 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
     {

+ 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) {
         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', {
       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
 import fetch from 'node-fetch';
 global.fetch = fetch;
-
-
 var Mock = require('mockjs')
 
 var mockdata = [];
@@ -154,6 +152,18 @@ export default {
     SaveStuExamPaper: function (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)
+    },
 
 }
 

+ 23 - 0
TEAMModelOS/ClientApp/src/assets/iconfont/demo_index.html

@@ -30,6 +30,12 @@
       <div class="content unicode" style="display: block;">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+              <span class="icon iconfont">&#xe666;</span>
+                <div class="name">转换</div>
+                <div class="code-name">&amp;#xe666;</div>
+              </li>
+          
             <li class="dib">
               <span class="icon iconfont">&#xe640;</span>
                 <div class="name">半对</div>
@@ -464,6 +470,15 @@
       <div class="content font-class">
         <ul class="icon_lists dib-box">
           
+          <li class="dib">
+            <span class="icon iconfont icon-convert"></span>
+            <div class="name">
+              转换
+            </div>
+            <div class="code-name">.icon-convert
+            </div>
+          </li>
+          
           <li class="dib">
             <span class="icon iconfont icon-half-right"></span>
             <div class="name">
@@ -1069,6 +1084,14 @@
       <div class="content symbol">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-convert"></use>
+                </svg>
+                <div class="name">转换</div>
+                <div class="code-name">#icon-convert</div>
+            </li>
+          
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#icon-half-right"></use>

File diff suppressed because it is too large
+ 12 - 7
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css


二進制
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.eot


File diff suppressed because it is too large
+ 1 - 1
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.js


+ 7 - 0
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.json

@@ -5,6 +5,13 @@
   "css_prefix_text": "icon-",
   "description": "",
   "glyphs": [
+    {
+      "icon_id": "2604478",
+      "name": "转换",
+      "font_class": "convert",
+      "unicode": "e666",
+      "unicode_decimal": 58982
+    },
     {
       "icon_id": "5831259",
       "name": "半对",

File diff suppressed because it is too large
+ 3 - 0
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.svg


二進制
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.ttf


二進制
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff


二進制
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff2


+ 4 - 2
TEAMModelOS/ClientApp/src/boot-app.js

@@ -100,7 +100,10 @@ Vue.prototype.$User = User
 
 // 工具类
 Vue.prototype.$Mock = mockTools
-Vue.prototype.$GLOBAL = GLOBAL
+// Vue.prototype.$GLOBAL = GLOBAL
+Vue.use(GLOBAL, {
+    i18n: (key, value) => i18n.t(key, value)
+})
 Vue.prototype.$FileSaver = FileSaver
 Vue.prototype.$jwtDecode = jwtDecode
 Vue.prototype.$JSONPath = JSONPath
@@ -109,7 +112,6 @@ Vue.prototype.$tools = tools
 Vue.prototype.$evTools = evTools
 Vue.prototype.$editorTools = editorTools
 Vue.prototype.$jsFn = jsFn //常用工具方法
-Vue.prototype.$azblob = window.azblob //azblob API
 Vue.prototype._ = _
 
 // Registration of global components

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

@@ -1,362 +1,388 @@
 <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>
 <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>

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

@@ -82,14 +82,14 @@
                 menuTree: [
                     {
                         icon: 'iconfont icon-school',
-                        name: '智慧校园',
+                        name: this.$t('system.menu.smartSc'),
                         router: '',
                         role: 'teacher|admin',
                         permission: '',
                         child: [
                             {
                                 icon: 'iconfont icon-basic-setting',
-                                name: '基础设置',
+                                name: this.$t('system.menu.baseSetting'),
                                 router: '/home/system',
                                 tag: '',
                                 role: 'admin',
@@ -97,7 +97,7 @@
                             },
                             {
                                 icon: 'iconfont icon-teacher-mgt',
-                                name: '老师账号',
+                                name: this.$t('system.menu.teacherMgt'),
                                 router: '/home/teachermgmt',
                                 tag: '',
                                 role: 'admin',
@@ -105,7 +105,7 @@
                             },
                             {
                                 icon: 'iconfont icon-student-mgt',
-                                name: '学生账号',
+                                name: this.$t('system.menu.stuMgt'),
                                 router: '/home/studentAccount',
                                 tag: '',
                                 role: 'admin',
@@ -113,7 +113,7 @@
                             },
                             {
                                 icon: 'iconfont icon-class-mgt',
-                                name: '教室管理',
+                                name: this.$t('system.menu.classMgt'),
                                 router: '/home/classroom',
                                 tag: '',
                                 role: 'admin',
@@ -121,7 +121,7 @@
                             },
                             {
                                 icon: 'iconfont icon-kecheng',
-                                name: '课程设置',
+                                name: this.$t('system.menu.cusSetting'),
                                 router: '/home/ManageCourse',
                                 tag: '',
                                 role: 'admin',
@@ -137,7 +137,7 @@
                             //},
                             {
                                 icon: 'iconfont icon-schedule',
-                                name: '排课管理',
+                                name: this.$t('system.menu.cusPlanMgt'),
                                 router: '/home/NewCoursePlan',
                                 tag: '',
                                 role: 'admin',
@@ -145,23 +145,23 @@
                             },
                             {
                                 icon: 'iconfont icon-auth',
-                                name: '授权管理',
+                                name: this.$t('system.menu.authMgt'),
                                 router: '/home/serviceDriveAuth',
-                                tag: '(预览)',
+                                tag: this.$t('system.menu.preview'),
                                 role: 'admin',
                                 permission: 'auth-read|auth-upd'
                             },
                             {
                                 icon: 'iconfont icon-syllabus',
-                                name: '校本课纲',
+                                name: this.$t('system.menu.scSyllabus'),
                                 router: '/home/syllabus',
-                                tag: '(预览)',
+                                tag: this.$t('system.menu.preview'),
                                 role: 'teacher|admin',
                                 permission: '',
                             },
                             {
                                 icon: 'iconfont icon-file',
-                                name: '校本内容',
+                                name: this.$t('system.menu.scContent'),
                                 router: '/home/schoolcontent',
                                 tag: '',
                                 role: 'teacher|admin',
@@ -169,7 +169,7 @@
                             },
                             {
                                 icon: 'iconfont icon-question-bank',
-                                name: '校本题库',
+                                name: this.$t('system.menu.scQuBack'),
                                 router: '/home/evaluation/schoolBank',
                                 tag: '*',
                                 role: 'teacher|admin',
@@ -177,7 +177,7 @@
                             },
                             {
                                 icon: 'iconfont icon-k-point',
-                                name: '知识点库',
+                                name: this.$t('system.menu.kdBack'),
                                 router: '/home/knowledge',
                                 tag: '*',
                                 role: 'teacher|admin',
@@ -187,14 +187,14 @@
                     },
                     {
                         icon: 'iconfont icon-analysis',
-                        name: '统计分析',
+                        name: this.$t('system.menu.staAna'),
                         router: '',
                         role: 'admin',
                         permission: 'analysis-read|scboard-read',
                         child: [
                             {
                                 icon: 'iconfont icon-xueqing',
-                                name: '学情分析',
+                                name: this.$t('system.menu.evAna'),
                                 router: '/totalIndex',
                                 tag: '*',
                                 role: 'admin',
@@ -202,9 +202,9 @@
                             },
                             {
                                 icon: 'iconfont icon-school-analysis',
-                                name: '校园分析',
+                                name: this.$t('system.menu.scAna'),
                                 router: '/home/scboard',
-                                tag: '(预览)',
+                                tag: this.$t('system.menu.preview'),
                                 role: 'admin',
                                 permission: 'scboard-read'
                             }
@@ -212,14 +212,14 @@
                     },
                     {
                         icon: 'iconfont icon-activityS',
-                        name: '校园活动',
+                        name: this.$t('system.menu.scAc'),
                         router: '',
                         role: 'admin',
                         permission: 'schoolAc-read|schoolAc-upd',
                         child: [
                             {
                                 icon: 'iconfont icon-test',
-                                name: '评量测验',
+                                name: this.$t('system.menu.scEv'),
                                 router: '/home/schoolEvaluation',
                                 tag: '*',
                                 role: 'admin',
@@ -227,7 +227,7 @@
                             },
                             {
                                 icon: 'iconfont icon-vote',
-                                name: '投票活动',
+                                name: this.$t('system.menu.scVote'),
                                 router: '/home/manageVote',
                                 tag: '*',
                                 role: 'admin',
@@ -235,7 +235,7 @@
                             },
                             {
                                 icon: 'iconfont icon-questionnaire',
-                                name: '问卷调查',
+                                name: this.$t('system.menu.scQu'),
                                 router: '/home/manageQuestionnaire',
                                 tag: '*',
                                 role: 'admin',
@@ -245,14 +245,14 @@
                     },
                     {
                         icon: 'iconfont icon-kecheng',
-                        name: '班级课程',
+                        name: this.$t('system.menu.classCus'),
                         router: '',
                         role: 'teacher',
                         permission: 'analysis',
                         child: [
                             {
                                 icon: 'iconfont icon-class-self',
-                                name: '我的班级',
+                                name: this.$t('system.menu.myClass'),
                                 router: '/home/manageClass',
                                 tag: '',
                                 role: 'teacher',
@@ -260,7 +260,7 @@
                             },
                             {
                                 icon: 'iconfont icon-course-self',
-                                name: '我的课程',
+                                name: this.$t('system.menu.myCus'),
                                 router: '/home/myCourse',
                                 tag: '*',
                                 role: 'teacher',
@@ -278,22 +278,22 @@
                     },
                     {
                         icon: 'iconfont icon-textbook',
-                        name: '课程教材',
+                        name: this.$t('system.menu.cusContent'),
                         router: '',
                         role: 'teacher',
                         permission: '',
                         child: [
                             {
                                 icon: 'iconfont icon-syllabus',
-                                name: '个人课纲',
+                                name: this.$t('system.menu.prtSyllabus'),
                                 router: '/home/personalSyllabus',
-                                tag: '(预览)',
+                                tag: this.$t('system.menu.preview'),
                                 role: 'teacher|admin',
                                 permission: '',
                             },
                             {
                                 icon: 'iconfont icon-file',
-                                name: '个人内容',
+                                name: this.$t('system.menu.prtContent'),
                                 router: '/home/personalcontent',
                                 tag: '',
                                 role: 'teacher|admin',
@@ -301,7 +301,7 @@
                             },
                             {
                                 icon: 'iconfont icon-question-bank',
-                                name: '个人题库',
+                                name: this.$t('system.menu.prtQuBack'),
                                 router: '/home/evaluation/personalBank',
                                 tag: '*',
                                 role: 'teacher|admin',
@@ -311,14 +311,14 @@
                     },
                     {
                         icon: 'iconfont icon-activityT',
-                        name: '学习活动',
+                        name: this.$t('system.menu.stuAc'),
                         router: '',
                         role: 'teacher|admin',
                         permission: '',
                         child: [
                             {
                                 icon: 'iconfont icon-test',
-                                name: '个人评测',
+                                name: this.$t('system.menu.prtEv'),
                                 router: '/home/privateEvaluation',
                                 tag: '*',
                                 role: 'teacher|admin',
@@ -326,7 +326,7 @@
                             },
                             {
                                 icon: 'iconfont icon-vote',
-                                name: '个人投票',
+                                name: this.$t('system.menu.prtVote'),
                                 router: '/home/personalVote',
                                 tag: '*',
                                 role: 'teacher|admin',
@@ -334,7 +334,7 @@
                             },
                             {
                                 icon: 'iconfont icon-questionnaire',
-                                name: '个人问卷',
+                                name: this.$t('system.menu.prtQu'),
                                 router: '/home/personalSurvey',
                                 tag: '*',
                                 role: 'teacher|admin',
@@ -342,25 +342,25 @@
                             },
                             {
                                 icon: 'iconfont icon-learning-self',
-                                name: '自主学习',
+                                name: this.$t('system.menu.selfLearn'),
                                 router: '/home/SelfLearn',
-                                tag: '(预览)',
+                                tag: this.$t('system.menu.preview'),
                                 role: 'teacher|admin',
                                 permission: '',
                             },
                             {
                                 icon: 'iconfont icon-hw',
-                                name: '作业活动',
+                                name: this.$t('system.menu.homework'),
                                 router: '/home/manageHomeWork',
-                                tag: '(预览)',
+                                tag: this.$t('system.menu.preview'),
                                 role: 'teacher|admin',
                                 permission: '',
                             },
                             {
                                 icon: 'iconfont icon-syllabus',
-                                name: '活动记录',
+                                name: this.$t('system.menu.acRecord'),
                                 router: '/home/manageRecord',
-                                tag: '(预览)',
+                                tag: this.$t('system.menu.preview'),
                                 role: 'teacher|admin',
                                 permission: '',
                             }

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

@@ -1,6 +1,6 @@
 <template>
 	<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">
 			<span class="canvas-tools-item" style="border-radius: 15px 0 0 0;">
 				<Poptip trigger="hover">
@@ -33,6 +33,10 @@
 					</div>
 				</Poptip>
 			</span>
+			<span class="canvas-tools-item" @click="addText()">
+				<Icon type="md-text" />
+				<span>文本输入</span>
+			</span>
 			<span class="canvas-tools-item" @click="canvasClear()">
 				<Icon type="md-refresh" />
 				<span>清屏</span>
@@ -46,6 +50,14 @@
 				<span>保存</span>
 			</span>
 		</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>
 </template>
 <script>
@@ -59,6 +71,10 @@
 				type: Boolean,
 				default: false
 			},
+			hideBorder: {
+				type: Boolean,
+				default: false
+			},
 			bgImg: {
 				type: String,
 				default: ''
@@ -71,6 +87,8 @@
 		data() {
 			return {
 				value: null,
+				addTextModal:false,
+				addTextVal:'',
 				activeDot: 5,
 				activeColor: 'black',
 				options: {
@@ -107,6 +125,15 @@
 			onChangeWriteColor(val) {
 				this.options.writeColor = val
 			},
+			
+			addText(){
+				this.addTextModal = true
+			},
+			
+			doAddText(){
+				this.$refs.SignCanvas.doAddText(this.addTextVal);
+				this.addTextModal = false
+			},
 
 			onSelectWriteColor(val) {
 				console.log(val)
@@ -174,6 +201,15 @@
 					this.onSelectWriteColor(n)
 				},
 				immediate: true
+			},
+			hideBorder:{
+				handler(n, o) {
+					if(n){
+						this.options.borderWidth = 0
+						this.options.borderColor = 'transparent'
+					}
+				},
+				immediate: true
 			}
 		}
 	}

+ 146 - 105
TEAMModelOS/ClientApp/src/common/NewUploadFile.vue

@@ -1,29 +1,45 @@
 <template>
     <div class="upload-file-box">
         <Upload type="drag" action="" :show-upload-list="false" multiple :before-upload="customUpload" class="upload-wrap">
-            <Icon class="upload-icon" custom="iconfont icon-upload" />
-            <p class="upload-text">{{$t('teachContent.uploadText')}}</p>
-            <p class="upload-text" style="font-size:12px;margin-bottom:50px;">* 相同名字的文件上传会自动覆盖</p>
+            <Icon class="upload-icon" custom="iconfont icon-upload" v-show="!uploadedList.length" />
+            <p class="upload-text" :style="{marginTop: uploadedList.length ? '25px':'0px'}">
+                <Icon size="24" style="font-size: 22px;vertical-align: baseline;margin-right: 5px;" custom="iconfont icon-upload" v-show="uploadedList.length" />
+                {{$t('teachContent.uploadText')}}
+            </p>
+            <p class="upload-text" style="font-size:12px;">* 上传相同名字的文件会自动覆盖</p>
+            <p class="upload-text" :style="{fontSize:'12px',marginBottom: uploadedList.length ? '25px':'50px'}">
+                * 勾选
+                <Icon custom="iconfont icon-convert" size="12"  class="is-parse-htex"/>
+                支持PPTX文档转换成HTEX教材
+            </p>
         </Upload>
         <div class="upload-file-box">
             <div class="upload-file-item" v-for="(item,index) in uploadedList" :key="index">
-                <p class="upload-file-name">
-                    <span v-if="item.type == 'res'" class="file-type-tag" style="color: #1FFCC5;border-color: #1FFCC5">教材</span>
-                    <span v-else-if="item.type == 'image'" class="file-type-tag" style="color: #45C84A;border-color: #45C84A">图片</span>
-                    <span v-else-if="item.type == 'video'" class="file-type-tag" style="color: #8E2BDD;border-color: #8E2BDD">视频</span>
-                    <span v-else-if="item.type == 'audio'" class="file-type-tag" style="color: #E1027B;border-color: #E1027B">音频</span>
-                    <span v-else-if="item.type == 'doc'" class="file-type-tag" style="color: #03C0C2;border-color: #03C0C2">文档</span>
-                    <span v-else class="file-type-tag" style="color: #E87B22; border-color: #E87B22">其他</span>
-                    <span>{{item.name}}</span>
-                </p>
-                <Icon type="ios-close" class="delete-btn" color="red" size="30" style="float:right;" @click="deleteFile(index)" />
-                <span style="float:right;margin-left:10px;vertical-align:middle;color:white; line-height:30px;">
-                    {{parseInt(item.loadedBytes * 100 / item.size)+'%'}}
-                </span>
-                <span style="float: right;font-size: 12px;vertical-align: middle;line-height: 30px;">
-                    {{getSizeByBytes(item.loadedBytes)+'/'+getSizeByBytes(item.size)}}
-                </span>
-                <Progress style="top:-10px;" v-if="item.status == 0" :percent="item.loadedBytes * 100 / item.size" status="active" stroke-color="#1CC0F3" :stroke-width="2" hide-info />
+                <div class="upload-item-left">
+                    <p class="upload-file-name">
+                        <span v-if="item.type == 'res'" class="file-type-tag" style="color: #1FFCC5;border-color: #1FFCC5">教材</span>
+                        <span v-else-if="item.type == 'image'" class="file-type-tag" style="color: #45C84A;border-color: #45C84A">图片</span>
+                        <span v-else-if="item.type == 'video'" class="file-type-tag" style="color: #8E2BDD;border-color: #8E2BDD">视频</span>
+                        <span v-else-if="item.type == 'audio'" class="file-type-tag" style="color: #E1027B;border-color: #E1027B">音频</span>
+                        <span v-else-if="item.type == 'doc'" class="file-type-tag" style="color: #03C0C2;border-color: #03C0C2">{{item.isParse ? '转换':'文档'}}</span>
+                        <span v-else class="file-type-tag" style="color: #E87B22; border-color: #E87B22">其他</span>
+                        <span>{{item.name}}</span>
+                    </p>
+                    <span class="upload-info-wrap" style="color:white;">
+                        {{parseInt(item.loadedBytes * 100 / item.size)+'%'}}
+                    </span>
+                    <span class="upload-info-wrap">
+                        {{getSizeByBytes(item.loadedBytes)+'/'+getSizeByBytes(item.size)}}
+                    </span>
+                    <span v-if="item.extension == 'PPTX'" class="upload-info-wrap parse-label" @click="item.isParse = !item.isParse" :style="{color:item.isParse ? '#1cc0f3':'#808080'}">
+                        <Icon class="is-parse-htex" size="12" custom="iconfont icon-convert" />
+                        转成HTEX教材
+                    </span>
+                    <Progress style="top:-10px;" v-if="item.status == 0" :percent="item.loadedBytes * 100 / item.size" status="active" stroke-color="#1CC0F3" :stroke-width="2" hide-info />
+                </div>
+                <div class="upload-item-right">
+                    <Icon type="ios-close" class="delete-btn" color="red" size="30" style="float:right;" @click="deleteFile(index)" />
+                </div>
             </div>
         </div>
     </div>
@@ -147,89 +163,93 @@ export default {
                 loadedBytes: 0,
                 progress: 0,
                 status: 0,
-                type: fileType
+                type: fileType,
+                file: file,
+                extension: extension.toUpperCase(),
+                isParse: false
             }
             this.uploadedList.push(fileInfo)
             let _this = this
             let index = this.uploadedList.length - 1
-            this.containerClient.upload(file, fileType, {
-                onProgress: function (e) {
-                    _this.uploadedList[index].loadedBytes = e.loadedBytes
-                    _this.uploadedList[index].progress = parseInt(e.loadedBytes * 100 / file.size)
-                }
-            }).then(
-                res => {
-                    this.uploadedList[index].status = 1
-                    this.uploadedList[index].blob = res.blob
-                    extension = extension.toUpperCase()
-                    if (res.type == 'image') {
-                        this.uploadThum(file)
-                        this.$emit('successData', res)
-                    } else if (res.type == 'video') {
-                        this.uploadPoater(res)
-                        this.$emit('successData', res)
-                    } else if (extension == 'PPTX') {
-                        this.$Modal.confirm({
-                            title: '文件解析',
-                            okText: '是',
-                            cancelText: '否',
-                            content: `<p>是否将<strong style='color:red;'>${file.name}</strong>转成HTEX文件?</p>`,
-                            onOk: () => {
-                                this.$emit('parsing')
-                                let delBlob = res.blob
-                                this.$api.teachContent.ParseDoc({
-                                    file: res.url,
-                                    scope: this.routerScope
-                                }).then(
-                                    parseRes => {
-                                        this.containerClient.deleteBlob(delBlob)
-                                        res.blob = `/res/${res.name}/index.json`
-                                        res.extension = 'HTEX'
-                                        res.name = res.name.replace('pptx', 'HTEX').replace('PPTX', 'HTEX')
-                                        res.type = 'res'
-                                        this.$emit('successData', res.blob)
-                                        this.$emit('parseComplete')
-                                        this.$Message.success('解析成功')
-                                    },
-                                    parseErr => {
-                                        this.$Message.error('解析失败')
-                                    }
-                                )
-                            },
-                            onCancel: () => {
-                                this.$emit('successData', res)
-                            }
-                        })
-                    } else if (extension == 'HTEX') {
-                        let delBlob = res.blob
-                        this.$emit('parsing')
-                        res.blob = `/res/${res.name}/index.json`
-                        this.$emit('successData', res)
-                        this.$api.teachContent.ParseDoc({
-                            file: res.url,
-                            scope: this.routerScope
-                        }).then(
-                            parseRes => {
-                                this.containerClient.deleteBlob(delBlob)
-                            },
-                            parseErr => {
-                                this.$Message.error('上传失败')
-                                this.containerClient.deleteBlob(delBlob)
-                            }
-                        ).finally(() => {
-                            this.$emit('parseComplete')
-                        })
-                    }
-                },
-                err => {
-                    this.uploadedList[index].status = 2
-                    if (err.spaceError) {
-                        this.$Message.error(err.spaceError)
-                    } else {
-                        this.$Message.error("上传失败")
-                    }
-                }
-            )
+            // this.containerClient.upload(file, fileType, {
+            //     onProgress: function (e) {
+            //         _this.uploadedList[index].loadedBytes = e.loadedBytes
+            //         _this.uploadedList[index].progress = parseInt(e.loadedBytes * 100 / file.size)
+            //     }
+            // }).then(
+            //     res => {
+            //         this.uploadedList[index].status = 1
+            //         this.uploadedList[index].blob = res.blob
+            //         extension = extension.toUpperCase()
+            //         if (res.type == 'image') {
+            //             this.uploadThum(file)
+            //             this.$emit('successData', res)
+            //         } else if (res.type == 'video') {
+            //             this.uploadPoater(res)
+            //             this.$emit('successData', res)
+            //         } else if (extension == 'PPTX') {
+            //             this.$Modal.confirm({
+            //                 title: '文件解析',
+            //                 okText: '是',
+            //                 cancelText: '否',
+            //                 content: `<p>是否将<strong style='color:red;'>${file.name}</strong>转成HTEX文件?</p>`,
+            //                 onOk: () => {
+            //                     this.$emit('parsing')
+            //                     this.$emit('successData', res)
+            //                     let delBlob = res.blob
+            //                     this.$api.teachContent.ParseDoc({
+            //                         file: res.url,
+            //                         scope: this.routerScope
+            //                     }).then(
+            //                         parseRes => {
+            //                             this.containerClient.deleteBlob(delBlob)
+            //                             res.blob = `/res/${res.name}/index.json`
+            //                             res.extension = 'HTEX'
+            //                             res.name = res.name.replace('pptx', 'HTEX').replace('PPTX', 'HTEX')
+            //                             res.type = 'res'
+
+            //                             this.$emit('parseComplete')
+            //                             this.$Message.success('解析成功')
+            //                         },
+            //                         parseErr => {
+            //                             this.$Message.error('解析失败')
+            //                         }
+            //                     )
+            //                 },
+            //                 onCancel: () => {
+            //                     this.$emit('successData', res)
+            //                 }
+            //             })
+            //         } else if (extension == 'HTEX') {
+            //             let delBlob = res.blob
+            //             this.$emit('parsing')
+            //             res.blob = `/res/${res.name}/index.json`
+            //             this.$emit('successData', res)
+            //             this.$api.teachContent.ParseDoc({
+            //                 file: res.url,
+            //                 scope: this.routerScope
+            //             }).then(
+            //                 parseRes => {
+            //                     this.containerClient.deleteBlob(delBlob)
+            //                 },
+            //                 parseErr => {
+            //                     this.$Message.error('上传失败')
+            //                     this.containerClient.deleteBlob(delBlob)
+            //                 }
+            //             ).finally(() => {
+            //                 this.$emit('parseComplete')
+            //             })
+            //         }
+            //     },
+            //     err => {
+            //         this.uploadedList[index].status = 2
+            //         if (err.spaceError) {
+            //             this.$Message.error(err.spaceError)
+            //         } else {
+            //             this.$Message.error("上传失败")
+            //         }
+            //     }
+            // )
             return false
         },
         //处理图片缩略图
@@ -321,23 +341,36 @@ export default {
 </script>
 <style scoped>
 .upload-text {
-    margin: 20px 0px;
-    font-size: 26px;
+    margin: 10px 0px;
+    font-size: 24px;
 }
 .upload-icon {
     font-size: 50px;
     margin-top: 60px;
 }
 .upload-file-item {
-    cursor: pointer;
     color: #909090;
     margin-top: 5px;
     padding: 5px 2px 0px 5px;
+    display: flex;
+}
+.upload-item-left {
+    width: calc(100% - 25px);
+}
+.upload-item-right {
+    width: 25px;
+}
+.upload-info-wrap {
+    float: right;
+    margin-left: 10px;
+    vertical-align: middle;
+    /* color: white; */
+    line-height: 30px;
 }
 
 .upload-file-item:hover {
-    color: white;
-    background: #585858;
+    /* color: white; */
+    /* background: #585858; */
     border-radius: 5px;
 }
 
@@ -359,9 +392,17 @@ export default {
 .file-type-tag {
     border: 1px solid;
     /*border-color:white;*/
-    border-radius: 4px;
+    border-radius: 2px;
     padding: 0px 4px;
     margin-right: 5px;
     font-size: 12px;
 }
+.parse-label {
+    cursor: pointer;
+    font-size: 12px;
+    user-select: none;
+}
+.is-parse-htex {
+    vertical-align: baseline;
+}
 </style>

+ 496 - 0
TEAMModelOS/ClientApp/src/common/UploadModal.vue

@@ -0,0 +1,496 @@
+<template>
+    <Modal v-model="uploadStatus" :ok-text="textLoading ? '上传中': isComplete ? '完成':'确认上传'" cancel-text="取消上传" :title="$t('teachContent.btnUpload')" class="upload-modal dark-iview-modal" width="660" :mask-closable="false" :closable="false" @on-ok="modalOk" @on-cancel="modalCancel" :loading="modalLoading">
+        <div class="upload-file-box">
+            <Upload type="drag" action="" :show-upload-list="false" multiple :before-upload="customUpload" class="upload-wrap">
+                <Icon class="upload-icon" custom="iconfont icon-upload" v-show="!uploadedList.length" />
+                <p class="upload-text" :style="{marginTop: uploadedList.length ? '25px':'0px'}">
+                    <Icon size="24" style="font-size: 22px;vertical-align: baseline;margin-right: 5px;" custom="iconfont icon-upload" v-show="uploadedList.length" />
+                    {{$t('teachContent.uploadText')}}
+                </p>
+                <p class="upload-text" style="font-size:12px;">* 上传相同名字的文件会自动覆盖</p>
+                <p class="upload-text" :style="{fontSize:'12px',marginBottom: uploadedList.length ? '25px':'50px'}">
+                    * 勾选
+                    <Icon custom="iconfont icon-convert" size="12" class="is-parse-htex" />
+                    支持PPTX文档转换成HTEX教材
+                </p>
+            </Upload>
+            <div class="upload-file-box">
+                <div class="upload-file-item" v-for="(item,index) in uploadedList" :key="index">
+                    <div class="upload-item-left">
+                        <p class="upload-file-name">
+                            <span v-if="item.type == 'res'" class="file-type-tag" style="color: #1FFCC5;border-color: #1FFCC5">教材</span>
+                            <span v-else-if="item.type == 'image'" class="file-type-tag" style="color: #45C84A;border-color: #45C84A">图片</span>
+                            <span v-else-if="item.type == 'video'" class="file-type-tag" style="color: #8E2BDD;border-color: #8E2BDD">视频</span>
+                            <span v-else-if="item.type == 'audio'" class="file-type-tag" style="color: #E1027B;border-color: #E1027B">音频</span>
+                            <span v-else-if="item.type == 'doc'" class="file-type-tag" style="color: #03C0C2;border-color: #03C0C2">{{item.isParse ? '转换':'文档'}}</span>
+                            <span v-else class="file-type-tag" style="color: #E87B22; border-color: #E87B22">其他</span>
+                            <span>{{item.name}}</span>
+                        </p>
+                        <span class="upload-info-wrap" style="color:white;">
+                            {{parseInt(item.loadedBytes * 100 / item.size)+'%'}}
+                        </span>
+                        <span class="upload-info-wrap">
+                            {{getSizeByBytes(item.loadedBytes)+'/'+getSizeByBytes(item.size)}}
+                        </span>
+                        <span v-if="item.extension == 'PPTX'" class="upload-info-wrap parse-label" @click="item.isParse = !item.isParse" :style="{color:item.isParse ? '#1cc0f3':'#808080'}">
+                            <Icon class="is-parse-htex" size="12" custom="iconfont icon-convert" />
+                            转成HTEX教材
+                        </span>
+                        <Progress style="top:-10px;" v-if="item.status == 0" :percent="item.loadedBytes * 100 / item.size" status="active" stroke-color="#1CC0F3" :stroke-width="2" hide-info />
+                    </div>
+                    <div class="upload-item-right">
+                        <Icon type="ios-close" class="delete-btn" color="red" size="30" style="float:right;" @click="deleteFile(index)" />
+                    </div>
+                </div>
+            </div>
+        </div>
+    </Modal>
+
+</template>
+<script>
+import BlobTool from '@/utils/blobTool.js';
+export default {
+    data() {
+        return {
+            uploadedList: [],
+            containerClient: null,
+            routerScope: '',
+            uploadStatus: false,
+            textLoading: false,
+            modalLoading: false,
+            isComplete: false, //是否完成上传
+            loadingCount: 0
+        }
+    },
+    props: {
+        //默认文件列表
+        defaultFileList: {
+            default: () => {
+                return []
+            },
+            type: Array
+        },
+        //文件路径
+        path: {
+            default: '',
+            type: String,
+            required: true
+        },
+        //授权信息
+        sasString: {
+            default: '',
+            type: String,
+            required: true
+        },
+        //blob链接
+        urlString: {
+            default: '',
+            type: String,
+            required: true
+        },
+        //容器名称
+        containerName: {
+            default: '',
+            type: String,
+            required: true
+        },
+        //文件大小限制
+        maxSize: {
+            default: 2 * 1024 * 1024 * 1024,
+            type: Number
+        },
+        //文件格式限制
+        format: {
+            default: () => {
+                return []
+            },
+            type: Array
+        }
+    },
+    methods: {
+        //删除文件
+        deleteFile(index) {
+            this.containerClient.deleteBlob(this.uploadedList[index].blob).then(
+                res => {
+                    //删除缩略图和封面
+                    if (this.uploadedList[index].type == 'image') {
+                        let thum = this.uploadedList[index].blob.replace('/image/', '/thum/')
+                        this.containerClient.deleteBlob(thum)
+                    } else if (this.uploadedList[index].type == 'video') {
+                        let thum = this.uploadedList[index].blob.replace('/video/', '/thum/')
+                        thum = thum.slice(0, thum.lastIndexOf('.')) + '.png'
+                        this.containerClient.deleteBlob(thum)
+                    }
+                    this.uploadedList.splice(index, 1)
+                    this.$Message.success('删除成功!')
+                },
+                err => {
+                    this.$Message.error('删除失败!')
+                }
+            )
+        },
+        getFileType(fileName) {
+            let extension = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length)
+            extension = extension.toUpperCase()
+            for (let key in this.$GLOBAL.CONTENT_TYPES) {
+                if (this.$GLOBAL.CONTENT_TYPES[key].indexOf(extension) != -1) {
+                    return key
+                }
+            }
+            return 'other'
+        },
+        getSizeByBytes(bytes) {
+            return bytes / 1024 < 1024 ? (bytes / 1024).toFixed(1) + 'KB' : bytes / 1024 / 1024 < 1024 ? (bytes / 1024 / 1024).toFixed(1) + 'M' : (bytes / 1024 / 1024 / 1024).toFixed(1) + 'G'
+        },
+        async customUpload(file) {
+            if (file.size > this.maxSize) {
+                this.$Message.error({
+                    content: "文件大小超出限制",
+                    duration: 3
+                })
+                return false
+            }
+
+            let extension = file.name.substring(file.name.lastIndexOf('.') + 1, file.name.length)
+            if (this.format.length > 0 && this.format.indexOf(extension) == -1) {
+                this.$Message.error({
+                    content: "文件类型不支持",
+                    duration: 3
+                })
+                return false
+            }
+
+            let fileType = this.getFileType(file.name)
+            //上传文件
+            let fileInfo = {
+                url: this.urlString + '/' + this.containerName + '/' + fileType + '/' + file.name,
+                name: file.name,
+                size: file.size,
+                loadedBytes: 0,
+                progress: 0,
+                status: 0,
+                type: fileType,
+                file: file,
+                extension: extension.toUpperCase(),
+                isParse: false
+            }
+            this.uploadedList.push(fileInfo)
+            this.modalLoading = true
+            this.isComplete = false
+            return false
+        },
+        // modal取消事件
+        modalCancel() {
+            if (this.uploadedList.length) {
+                let blobsFile = this.uploadedList.filter(item => {
+                    let flag = true
+                    if (item.extension == 'HTEX') {
+                        flag = false
+                    }
+                    if (item.extension == 'PPTX' && item.isParse) {
+                        flag = false
+                    }
+                    return flag
+                })
+                if (blobsFile.length) {
+                    let blobs = blobsFile.map(item => {
+                        return item.blob
+                    })
+                    this.containerClient.deleteBlobBatch(blobs).then().finally(() => {
+                        blobsFile.forEach((item) => {
+                            if (item.type == 'image') {
+                                let thum = item.blob.replace('/image/', '/thum/')
+                                this.containerClient.deleteBlob(thum)
+                            } else if (item.type == 'video') {
+                                let thum = item.blob.replace('/video/', '/thum/')
+                                thum = thum.slice(0, thum.lastIndexOf('.')) + '.png'
+                                this.containerClient.deleteBlob(thum)
+                            }
+                        })
+                        this.uploadedList = []
+                    })
+                }
+
+                let prefixFiles = this.uploadedList.filter(item => {
+                    let flag = false
+                    if (item.extension == 'HTEX') {
+                        flag = true
+                    }
+                    if (item.extension == 'PPTX' && item.isParse) {
+                        flag = true
+                    }
+                    return flag
+                })
+
+                if (prefixFiles.length) {
+                    prefixFiles.forEach(item => {
+                        this.$api.uploadFile.deletePrefix({
+                            cntr: this.routerScope == 'school' ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId,
+                            prefix: `res/${item.name.replace('.HTEX', '')}`
+                        }).then(
+                            res => {
+                            },
+                            err => {
+                                this.$Message.error('取消失败!')
+                            }
+                        )
+                    })
+                    this.uploadedList = []
+                }
+            }
+            this.textLoading = false
+        },
+        // modal确认事件
+        modalOk() {
+            //已完成上传操作,关闭对话框、emit
+            if (this.isComplete) {
+                this.$emit("successData", this.uploadedList)
+                this.uploadedList = []
+            } else { //还未上传文件,则上传文件
+                this.textLoading = true
+                this.uploadedList.forEach((item, index) => {
+                    if (item.loadedBytes < item.size) {
+                        this.loadingCount++
+                        this.confirmUpload(item.file, item.type, index)
+                    }
+                })
+
+            }
+        },
+        // 确认上传文件
+        confirmUpload(file, fileType, index) {
+            let extension = this.uploadedList[index].extension
+            let _this = this
+            this.containerClient.upload(file, fileType, {
+                onProgress: function (e) {
+                    _this.uploadedList[index].loadedBytes = e.loadedBytes
+                    _this.uploadedList[index].progress = parseInt(e.loadedBytes * 100 / file.size)
+                }
+            }).then(
+                res => {
+                    this.uploadedList[index].status = 1
+                    this.uploadedList[index].blob = res.blob
+                    if (res.type == 'image') {
+                        this.uploadThum(file)
+                    } else if (res.type == 'video') {
+                        this.uploadPoater(res)
+                    } else if (extension == 'PPTX') {
+                        if (_this.uploadedList[index].isParse) {
+                            let delBlob = res.blob
+                            this.$api.teachContent.ParseDoc({
+                                file: res.url,
+                                scope: this.routerScope
+                            }).then(
+                                parseRes => {
+                                    this.containerClient.deleteBlob(delBlob)
+                                    this.uploadedList[index].blob = `/res/${res.name}/index.json`
+                                    this.uploadedList[index].extension = 'HTEX'
+                                    this.uploadedList[index].name = res.name.replace('pptx', 'HTEX').replace('PPTX', 'HTEX')
+                                    this.uploadedList[index].type = 'res'
+                                },
+                                parseErr => {
+                                    this.$Message.error('PPTX解析失败')
+                                }
+                            ).finally(() => {
+                                this.counterReduce()
+                            })
+                        } else {
+                            this.counterReduce()
+                        }
+                    } else if (extension == 'HTEX') {
+                        let delBlob = res.blob
+                        this.uploadedList[index].blob = `/res/${res.name}/index.json`
+                        this.$api.teachContent.ParseDoc({
+                            file: res.url,
+                            scope: this.routerScope
+                        }).then(
+                            parseRes => {
+                                this.containerClient.deleteBlob(delBlob)
+                            },
+                            parseErr => {
+                                this.$Message.error('上传失败')
+                                this.containerClient.deleteBlob(delBlob)
+                            }
+                        ).finally(() => {
+                            this.counterReduce()
+                        })
+                    }
+                    this.uploadedList[index].createTime = res.createTime
+                },
+                err => {
+                    this.uploadedList[index].status = 2
+                    if (err.spaceError) {
+                        this.$Message.error(err.spaceError)
+                    } else {
+                        this.$Message.error("上传失败")
+                    }
+                }
+            ).finally(() => {
+                if (extension !== 'PPTX' && extension !== 'HTEX') {
+                    this.counterReduce()
+                }
+            })
+        },
+        // 上传/解析完成计数器减1
+        counterReduce() {
+            if (--this.loadingCount == 0) {
+                this.textLoading = false
+                this.isComplete = true
+                this.modalLoading = false
+            }
+        },
+        //处理图片缩略图
+        async uploadThum(file) {
+            let dataUrl = await this.$jsFn.fileToURL(file)
+            dataUrl = await this.$jsFn.compressImgByUrl(dataUrl, file.name, 0.1)
+            let f = this.$jsFn.dataURLtoFile(dataUrl, file.name)
+            this.containerClient.upload(f, 'thum').then(
+                res => {
+                    console.log('压缩图上传成功')
+                },
+                err => {
+                    console.log('压缩图上传失败')
+                }
+            )
+        },
+        //处理视频封面
+        async uploadPoater(file) {
+            let n = file.name.substring(0, file.name.lastIndexOf('.'))
+            console.log(n)
+            console.log('视频蜂蜜昂')
+            let dataUrl = await this.$jsFn.createVideoPoster(file.url + this.sasString, file.name, 0.1)
+            let f = this.$jsFn.dataURLtoFile(dataUrl, n + '.png')
+            console.log(f)
+            this.containerClient.upload(f, 'thum').then(
+                res => {
+                    console.log('视频封面上传成功')
+                },
+                err => {
+                    console.log('视频封面上传失败')
+                }
+            )
+        }
+    },
+    created() {
+        let route = this.$route
+        if (route.name == 'personalcontent') {
+            this.routerScope = 'private'
+        } else {
+            this.routerScope = 'school'
+        }
+    },
+    watch: {
+        urlString: {
+            handler(v, o) {
+                if (this.urlString && this.containerName && this.sasString) {
+                    let scope = ''
+                    if (this.containerName == this.$store.state.userInfo.TEAMModelId) {
+                        scope = 'private'
+                    } else if (this.containerName == this.$store.state.userInfo.schoolCode) {
+                        scope = 'school'
+                    }
+                    //初始化Blob
+                    this.containerClient = new BlobTool(this.urlString, this.containerName, this.sasString, scope)
+                }
+            }
+        },
+        containerName: {
+            handler(v, o) {
+                if (this.urlString && this.containerName && this.sasString) {
+                    let scope = ''
+                    if (this.containerName == this.$store.state.userInfo.TEAMModelId) {
+                        scope = 'private'
+                    } else if (this.containerName == this.$store.state.userInfo.schoolCode) {
+                        scope = 'school'
+                    }
+                    //初始化Blob
+                    this.containerClient = new BlobTool(this.urlString, this.containerName, this.sasString, scope)
+                }
+            }
+        },
+        sasString: {
+            handler(v, o) {
+                if (this.urlString && this.containerName && this.sasString) {
+                    let scope = ''
+                    if (this.containerName == this.$store.state.userInfo.TEAMModelId) {
+                        scope = 'private'
+                    } else if (this.containerName == this.$store.state.userInfo.schoolCode) {
+                        scope = 'school'
+                    }
+                    //初始化Blob
+                    this.containerClient = new BlobTool(this.urlString, this.containerName, this.sasString, scope)
+                }
+            }
+        }
+    }
+}
+
+</script>
+<style scoped>
+.upload-text {
+    margin: 10px 0px;
+    font-size: 24px;
+}
+.upload-icon {
+    font-size: 50px;
+    margin-top: 60px;
+}
+.upload-file-item {
+    color: #909090;
+    margin-top: 5px;
+    padding: 5px 2px 0px 5px;
+    display: flex;
+}
+.upload-item-left {
+    width: calc(100% - 25px);
+}
+.upload-item-right {
+    width: 25px;
+}
+.upload-info-wrap {
+    float: right;
+    margin-left: 10px;
+    vertical-align: middle;
+    /* color: white; */
+    line-height: 30px;
+}
+
+.upload-file-item:hover {
+    /* color: white; */
+    /* background: #585858; */
+    border-radius: 5px;
+}
+
+.upload-file-item:hover .delete-btn {
+    display: inline-block;
+}
+.upload-loading-icon {
+    vertical-align: middle;
+}
+.upload-file-name {
+    display: inline-block;
+    color: #eeeeee;
+    line-height: 30px;
+}
+
+.delete-btn {
+    display: none;
+    cursor: pointer;
+}
+.file-type-tag {
+    border: 1px solid;
+    /*border-color:white;*/
+    border-radius: 2px;
+    padding: 0px 4px;
+    margin-right: 5px;
+    font-size: 12px;
+}
+.parse-label {
+    cursor: pointer;
+    font-size: 12px;
+    user-select: none;
+}
+.is-parse-htex {
+    vertical-align: baseline;
+}
+</style>

+ 1 - 1
TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.less

@@ -316,7 +316,7 @@
       }
     }
     span {
-      &:nth-child(4) {
+      &:nth-child(5) {
         border-right-width: 0;
       }
     }

+ 6 - 14
TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.vue

@@ -62,9 +62,9 @@
 							<div class="item-explain">
 								<span class="explain-title">【知识点】</span>
 								<div class="item-explain-details">
-									<span v-if="!item.points.length">暂未绑定知识点</span>
+									<span v-if="!item.knowledge || !item.knowledge.length">暂未绑定知识点</span>
 									<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 }}
 										</span>
 									</div>
@@ -84,6 +84,7 @@
 					<span class="item-tools-info">难度:{{ exersicesDiff[item.level - 1] }}</span>
 					<span class="item-tools-info">认知层次:{{ exersicesField[item.field - 1] }}</span>
 					<span class="item-tools-info">使用次数:{{ item.usageCount || 0 }} 次</span>
+					<span class="item-tools-info">更新时间:{{ $tools.formatTime(item.createTime)  || 0 }} </span>
 					<Button type="info" v-if="!isAnalysis" :style="{backgroundColor:selectList.map(i => i.id).indexOf(item.id) > -1 ? '#bbbbbb' : '#2db7f5'}"
 					 @click.stop="onSelectItem(item,index)">{{ selectList.map(i => i.id).indexOf(item.id) > -1 ? '移除' : '选题'}}</Button>
 				</div>
@@ -121,18 +122,9 @@
 		data() {
 			return {
 				dataLoading: false,
-				exersicesType: {
-					single: "单选题",
-					multiple: "多选题",
-					judge: "判断题",
-					complete: "填空题",
-					subjective: "问答题",
-					connector: "连线题",
-					correct: "改错题",
-					compose: "综合题",
-				},
-				exersicesDiff: ["容易", "较易", "一般", "较难", "困难"],
-				exersicesField:["知识", "理解", "应用", "分析", "综合", "评鉴"],
+				exersicesType: this.$GLOBAL.EXERCISE_TYPES(),
+				exersicesDiff: this.$GLOBAL.EXERCISE_DIFFS(),
+				exersicesField: this.$GLOBAL.EXERCISE_LEVELS(),
 				diffColors: ["#32CF74", "#E8BE15", "#F19300", "#EB5E00", "#D30000"],
 				totalNum: 0,
 				isShowAnswer: true,

+ 415 - 425
TEAMModelOS/ClientApp/src/components/selflearn/ExerciseList.vue

@@ -122,10 +122,7 @@
                                     </div>
                                     <!-- 其余题型答案 -->
                                     <div v-else>
-                                        <span :class="[
-                        item.type === 'complete' ? 'item-answer-item' : '',
-                      ]"
-                                              v-for="(answer, index) in item.answer" :key="index">{{ answer }}</span>
+                                        <span :class="[item.type === 'complete' ? 'item-answer-item' : '',]" v-for="(answer, index) in item.answer" :key="index">{{ answer }}</span>
                                     </div>
                                 </div>
                             </div>
@@ -140,7 +137,7 @@
                             <div class="item-explain">
                                 <span class="explain-title">【知识点】</span>
                                 <div class="item-explain-details">
-                                    <span v-if="!item.points.length">暂未绑定知识点</span>
+                                    <span v-if="!item.points">暂未绑定知识点</span>
                                     <div v-else>
                                         <span v-for="(point, index) in item.points" class="item-point-tag" :key="index">
                                             {{ point }}
@@ -181,447 +178,440 @@
         </Modal>
 
         <!-- 底部分页区域 -->
-        <Page :total="totalNum" show-sizer show-total :page-size="pageSize" :current="pageNum" @on-page-size-change="pageSizeChange"
-              @on-change="pageChange" :page-size-opts="[5, 10, 15, 20]" />
+        <Page :total="totalNum" show-sizer show-total :page-size="pageSize" :current="pageNum" @on-page-size-change="pageSizeChange" @on-change="pageChange" :page-size-opts="[5, 10, 15, 20]" />
     </div>
 </template>
 <script>
-    import blobTool from "@/utils/blobTool.js";
-
-    export default {
-        data() {
-            return {
-                userId: "",
-                schoolCode: "",
-                dataLoading: false,
-                exerciseList: [],
-                schoolInfo: {},
-                exersicesType: {
-                    single: "单选题",
-                    multiple: "多选题",
-                    judge: "判断题",
-                    complete: "填空题",
-                    subjective: "问答题",
-                    compose: "综合题",
-                },
-                exersicesDiff: ["容易", "较易", "一般", "较难", "困难"],
-                diffColors: ["#32CF74", "#E8BE15", "#F19300", "#EB5E00", "#D30000"],
-                filterType: ["all"],
-                filterOrigin: "",
-                filterDiff: ["all"],
-                filterField: ["all"],
-                filterSort: "createTime",
-                filterPeriod: 0,
-                filterGrade: [false],
-                filterSubject: [false],
-                totalNum: 0,
-                pageSize: 20,
-                pageNum: 1,
-                currentPage: 1,
-                collapseList: [],
-                periodList: [],
-                gradeList: [],
-                subjectList: [],
-                filterParams: {},
-                allPointList: [],
-                originData: [],
-                playAudioModal: false,
-                playVideoModal: false,
-                curAudioSrc: "",
-                curAudioName: "",
-                curVideoSrc: "",
-                curVideoName: "",
-            };
+import blobTool from "@/utils/blobTool.js";
+
+export default {
+    data() {
+        return {
+            userId: "",
+            schoolCode: "",
+            dataLoading: false,
+            exerciseList: [],
+            schoolInfo: {},
+            exersicesType: this.$GLOBAL.EXERCISE_TYPES(),
+            exersicesDiff: this.$GLOBAL.EXERCISE_DIFFS(),
+            exersicesField: this.$GLOBAL.EXERCISE_LEVELS(),
+            diffColors: ["#32CF74", "#E8BE15", "#F19300", "#EB5E00", "#D30000"],
+            filterType: ["all"],
+            filterOrigin: "",
+            filterDiff: ["all"],
+            filterField: ["all"],
+            filterSort: "createTime",
+            filterPeriod: 0,
+            filterGrade: [false],
+            filterSubject: [false],
+            totalNum: 0,
+            pageSize: 20,
+            pageNum: 1,
+            currentPage: 1,
+            collapseList: [],
+            periodList: [],
+            gradeList: [],
+            subjectList: [],
+            filterParams: {},
+            allPointList: [],
+            originData: [],
+            playAudioModal: false,
+            playVideoModal: false,
+            curAudioSrc: "",
+            curAudioName: "",
+            curVideoSrc: "",
+            curVideoName: "",
+        };
+    },
+    created() {
+        this.getSchoolInfo()
+    },
+    methods: {
+        /* 音频弹窗切换事件 */
+        onAudioModalChange(val) {
+            if (!val) {
+                this.$refs.audioPlayer.onCloseAudio();
+            }
         },
-        created() {
-            this.getSchoolInfo()
+
+        /* 视频弹窗切换事件 */
+        onVideoModalChange(val) {
+            if (!val) {
+                this.$refs.videoPlayer.onCloseAudio();
+            }
         },
-        methods: {
-            /* 音频弹窗切换事件 */
-            onAudioModalChange(val) {
-                if (!val) {
-                    this.$refs.audioPlayer.onCloseAudio();
-                }
-            },
 
-            /* 视频弹窗切换事件 */
-            onVideoModalChange(val) {
-                if (!val) {
-                    this.$refs.videoPlayer.onCloseAudio();
-                }
-            },
-
-            /* 音频点击播放事件 */
-            onRichTextClick(e) {
-                // e.stopPropagation()
-                let sasString = JSON.parse(
-                    decodeURIComponent(localStorage.getItem("user_profile"))
-                ).blob_sas;
-                // console.log(JSON.parse(decodeURIComponent(localStorage.getItem('school_profile'))))
-                if (e.srcElement.classList[0] === "richText-audio") {
-                    this.playAudioModal = true;
-                    this.curAudioSrc = e.srcElement.dataset.url;
-                    this.curAudioName = e.srcElement.dataset.name;
-                } else if (e.srcElement.classList[0] === "richText-video") {
-                    this.playVideoModal = true;
-                    this.curVideoSrc =
-                        e.srcElement.dataset.url.split("?")[0] + "?" + sasString;
-                    console.log(this.curVideoSrc);
-                    this.curVideoName = e.srcElement.dataset.name;
-                }
-            },
-
-            /** 获取区班校信息 */
-            getSchoolInfo() {
-                this.dataLoading = true;
-                this.$store.dispatch("user/getSchoolProfile").then((res) => {
-                    let schoolBaseInfo = res.school_base;
-                    if (schoolBaseInfo) {
-                        this.schoolInfo = schoolBaseInfo;
-                        this.schoolCode = schoolBaseInfo.id;
-                        this.userId = this.$store.state.userInfo.TEAMModelId;
-                        this.filterOrigin = this.$store.state.userInfo.TEAMModelId;
-                        this.periodList = schoolBaseInfo.period;
-                        console.log('periodList:', this.periodList)
-                        if (schoolBaseInfo.period.length) {
-                            this.gradeList = schoolBaseInfo.period[0].grades;
-                            this.subjectList = schoolBaseInfo.period[0].subjects;
-                        }
-                        this.doFilter();
+        /* 音频点击播放事件 */
+        onRichTextClick(e) {
+            // e.stopPropagation()
+            let sasString = JSON.parse(
+                decodeURIComponent(localStorage.getItem("user_profile"))
+            ).blob_sas;
+            // console.log(JSON.parse(decodeURIComponent(localStorage.getItem('school_profile'))))
+            if (e.srcElement.classList[0] === "richText-audio") {
+                this.playAudioModal = true;
+                this.curAudioSrc = e.srcElement.dataset.url;
+                this.curAudioName = e.srcElement.dataset.name;
+            } else if (e.srcElement.classList[0] === "richText-video") {
+                this.playVideoModal = true;
+                this.curVideoSrc =
+                    e.srcElement.dataset.url.split("?")[0] + "?" + sasString;
+                console.log(this.curVideoSrc);
+                this.curVideoName = e.srcElement.dataset.name;
+            }
+        },
+
+        /** 获取区班校信息 */
+        getSchoolInfo() {
+            this.dataLoading = true;
+            this.$store.dispatch("user/getSchoolProfile").then((res) => {
+                let schoolBaseInfo = res.school_base;
+                if (schoolBaseInfo) {
+                    this.schoolInfo = schoolBaseInfo;
+                    this.schoolCode = schoolBaseInfo.id;
+                    this.userId = this.$store.state.userInfo.TEAMModelId;
+                    this.filterOrigin = this.$store.state.userInfo.TEAMModelId;
+                    this.periodList = schoolBaseInfo.period;
+                    console.log('periodList:', this.periodList)
+                    if (schoolBaseInfo.period.length) {
+                        this.gradeList = schoolBaseInfo.period[0].grades;
+                        this.subjectList = schoolBaseInfo.period[0].subjects;
                     }
-                });
-            },
-
-            /* 获取BLOB所有试题LIST */
-            async getBlobOrigin() {
-                // 获取初始化Blob需要的数据
-                let sasData = await this.$tools.getPrivateSas();
-                //初始化Blob
-                let containerClient = new blobTool(
-                    sasData.url,
-                    sasData.name,
-                    sasData.sas,
-                    "private"
-                );
-                // 等待blob的返回结果
-                containerClient
-                    .listBlob({
-                        prefix: "paper",
-                    })
-                    .then(
-                        (res) => {
-                            console.log(res);
-                        },
-                        (err) => {
-                            this.$Message.error("API Error");
-                        }
-                    );
-            },
-
-            /** 执行筛选条件获取数据 */
-            doFilter() {
-                this.dataLoading = true;
-                this.collapseList = []; // 所有详情都收起来
-                /** 定义查询接口的参数规格 */
-                this.filterParams = {
-                    // '@CURRPAGE': this.pageNum,
-                    // '@PAGESIZE': this.pageSize,
-                    "@DESC": this.filterSort,
-                    code: this.filterOrigin,
-                    periodId: this.filterOrigin == this.schoolCode ? [this.periodList[this.filterPeriod].id] : [],
-                    "gradeIds[*]": this.filterOrigin == this.schoolCode ? this.deleteFalse(this.filterGrade) : [],
-                    subjectId: this.filterOrigin == this.schoolCode ? this.deleteFalse(this.filterSubject) : [],
-                    level: this.deleteFalse(this.filterDiff),
-                    type: this.deleteFalse(this.filterType),
-                    field: this.deleteFalse(this.filterField),
-                    scope: this.curScope,
-                };
-                this.getExerciseList(this.filterParams);
-            },
-
-            /**
-             * 获取最新题库列表
-             * @param data
-             */
-            async getExerciseList(data) {
-                let that = this;
-                this.$api.newEvaluation.FindExerciseList(data).then(async (res) => {
-                    let list = res.items;
-                    /* 获取试题总数 */
-                    this.totalNum = res.items.length;
-                    /* 查找当前页面所有知识点ID换名称 */
-                    // this.getPointsByIds(this.getPointIds(list)).then(res => {
-                    // 	this.allPointList = res
-                    // })
-                    this.exerciseList = list;
-                    this.originData = list;
-                    this.pageChange(1);
-
-                    setTimeout(() => {
-                        that.dataLoading = false;
-                    }, 1000);
-                });
-            },
-
-            /**
-             * 拿到当前页面所有知识点集合
-             * @param arr
-             */
-            getPointIds(arr) {
-                let ids = [];
-                arr.forEach((i) => {
-                    ids = ids.concat(i.points);
-                });
-                return [...new Set(ids)];
-            },
-
-            /**
-             * 根据知识点id集合换取知识点对象集合
-             * @param ids
-             */
-            getPointsByIds(ids) {
-                if (typeof ids[0] !== "string") {
-                    ids = ids.map((item) => item.id);
+                    this.doFilter();
                 }
-                return new Promise((r, j) => {
-                    if (ids.length) {
-                        this.$api.knowledge
-                            .FindKnowledgebyId(ids)
-                            .then((res) => {
-                                if (!res.error && res.result.data.length) {
-                                    r(res.result.data);
-                                } else {
-                                    r([]);
-                                }
-                            })
-                            .catch((err) => {
-                                j(err);
-                            });
-                    } else {
-                        r([]);
+            });
+        },
+
+        /* 获取BLOB所有试题LIST */
+        async getBlobOrigin() {
+            // 获取初始化Blob需要的数据
+            let sasData = await this.$tools.getPrivateSas();
+            //初始化Blob
+            let containerClient = new blobTool(
+                sasData.url,
+                sasData.name,
+                sasData.sas,
+                "private"
+            );
+            // 等待blob的返回结果
+            containerClient
+                .listBlob({
+                    prefix: "paper",
+                })
+                .then(
+                    (res) => {
+                        console.log(res);
+                    },
+                    (err) => {
+                        this.$Message.error("API Error");
                     }
-                });
-            },
-
-            /**
-             * 题干展开与收缩
-             * @param index
-             * @param id
-             */
-            onQuestionToggle(index, id, e) {
-                let curClassName = e.target.className;
-                console.log(curClassName);
-                if (
-                    curClassName === "item-tools" ||
-                    curClassName === "richText-video" ||
-                    curClassName === "richText-audio"
-                )
-                    return;
-                e.stopPropagation();
-                let listIndex = this.collapseList.indexOf(index);
-                if (listIndex > -1) {
-                    this.collapseList.splice(listIndex, 1);
+                );
+        },
+
+        /** 执行筛选条件获取数据 */
+        doFilter() {
+            this.dataLoading = true;
+            this.collapseList = []; // 所有详情都收起来
+            /** 定义查询接口的参数规格 */
+            this.filterParams = {
+                // '@CURRPAGE': this.pageNum,
+                // '@PAGESIZE': this.pageSize,
+                "@DESC": this.filterSort,
+                code: this.filterOrigin,
+                periodId: this.filterOrigin == this.schoolCode ? [this.periodList[this.filterPeriod].id] : [],
+                "gradeIds[*]": this.filterOrigin == this.schoolCode ? this.deleteFalse(this.filterGrade) : [],
+                subjectId: this.filterOrigin == this.schoolCode ? this.deleteFalse(this.filterSubject) : [],
+                level: this.deleteFalse(this.filterDiff),
+                type: this.deleteFalse(this.filterType),
+                field: this.deleteFalse(this.filterField),
+                scope: this.curScope,
+            };
+            this.getExerciseList(this.filterParams);
+        },
+
+        /**
+         * 获取最新题库列表
+         * @param data
+         */
+        async getExerciseList(data) {
+            let that = this;
+            this.$api.newEvaluation.FindExerciseList(data).then(async (res) => {
+                let list = res.items;
+                /* 获取试题总数 */
+                this.totalNum = res.items.length;
+                /* 查找当前页面所有知识点ID换名称 */
+                // this.getPointsByIds(this.getPointIds(list)).then(res => {
+                // 	this.allPointList = res
+                // })
+                this.exerciseList = list;
+                this.originData = list;
+                this.pageChange(1);
+
+                setTimeout(() => {
+                    that.dataLoading = false;
+                }, 1000);
+            });
+        },
+
+        /**
+         * 拿到当前页面所有知识点集合
+         * @param arr
+         */
+        getPointIds(arr) {
+            let ids = [];
+            arr.forEach((i) => {
+                ids = ids.concat(i.points);
+            });
+            return [...new Set(ids)];
+        },
+
+        /**
+         * 根据知识点id集合换取知识点对象集合
+         * @param ids
+         */
+        getPointsByIds(ids) {
+            if (typeof ids[0] !== "string") {
+                ids = ids.map((item) => item.id);
+            }
+            return new Promise((r, j) => {
+                if (ids.length) {
+                    this.$api.knowledge
+                        .FindKnowledgebyId(ids)
+                        .then((res) => {
+                            if (!res.error && res.result.data.length) {
+                                r(res.result.data);
+                            } else {
+                                r([]);
+                            }
+                        })
+                        .catch((err) => {
+                            j(err);
+                        });
                 } else {
-                    this.collapseList.push(index);
-                    let exerciseItemDom = e.path.filter(
-                        (i) => i.className === "exercise-item"
-                    );
+                    r([]);
                 }
+            });
+        },
+
+        /**
+         * 题干展开与收缩
+         * @param index
+         * @param id
+         */
+        onQuestionToggle(index, id, e) {
+            let curClassName = e.target.className;
+            console.log(curClassName);
+            if (
+                curClassName === "item-tools" ||
+                curClassName === "richText-video" ||
+                curClassName === "richText-audio"
+            )
+                return;
+            e.stopPropagation();
+            let listIndex = this.collapseList.indexOf(index);
+            if (listIndex > -1) {
+                this.collapseList.splice(listIndex, 1);
+            } else {
+                this.collapseList.push(index);
+                let exerciseItemDom = e.path.filter(
+                    (i) => i.className === "exercise-item"
+                );
+            }
+
+            this.$emit("toggleChange", this.collapseList);
+        },
+
+        /**
+         * 筛选学段条件
+         * @param val
+         */
+        filterPeriodChange(val) {
+            // this.filterPeriod = this.periodList[val].periodCode
+            this.gradeList = this.schoolInfo.period[val].grades;
+            this.subjectList = this.schoolInfo.period[val].subjects;
+            this.filterGrade = [false];
+            this.filterSubject = [false];
+            this.doFilter();
+        },
 
-                this.$emit("toggleChange", this.collapseList);
-            },
-
-            /**
-             * 筛选学段条件
-             * @param val
-             */
-            filterPeriodChange(val) {
-                // this.filterPeriod = this.periodList[val].periodCode
-                this.gradeList = this.schoolInfo.period[val].grades;
-                this.subjectList = this.schoolInfo.period[val].subjects;
+        /**
+         * 筛选年级
+         * @param val
+         */
+        filterGradeChange(val) {
+            if (val.length > 1 && val.indexOf(false) === 0) {
+                this.filterGrade.splice(val.indexOf(false), 1);
+            } else if (val.indexOf(false) > -1 || val.length === 0) {
                 this.filterGrade = [false];
+            }
+            this.doFilter();
+        },
+
+        /**
+         * 筛选科目
+         * @param val
+         */
+        filterSubjectChange(val) {
+            if (val.length > 1 && val.indexOf(false) === 0) {
+                this.filterSubject.splice(val.indexOf(false), 1);
+            } else if (val.indexOf(false) > -1 || val.length === 0) {
                 this.filterSubject = [false];
-                this.doFilter();
-            },
-
-            /**
-             * 筛选年级
-             * @param val
-             */
-            filterGradeChange(val) {
-                if (val.length > 1 && val.indexOf(false) === 0) {
-                    this.filterGrade.splice(val.indexOf(false), 1);
-                } else if (val.indexOf(false) > -1 || val.length === 0) {
-                    this.filterGrade = [false];
-                }
-                this.doFilter();
-            },
-
-            /**
-             * 筛选科目
-             * @param val
-             */
-            filterSubjectChange(val) {
-                if (val.length > 1 && val.indexOf(false) === 0) {
-                    this.filterSubject.splice(val.indexOf(false), 1);
-                } else if (val.indexOf(false) > -1 || val.length === 0) {
-                    this.filterSubject = [false];
-                }
-                this.doFilter();
-            },
-
-            /**
-             * 根据题库加载题目
-             * @param val
-             */
-            filterOriginChange(origin) {
-                this.filterOrigin = origin;
-                this.doFilter();
-            },
-
-            /**
-             * 筛选题型
-             * @param val
-             */
-            filterTypeChange(val) {
-                if (val.length > 1 && val.indexOf("all") === 0) {
-                    this.filterType.splice(val.indexOf("all"), 1);
-                } else if (val.indexOf("all") > -1 || val.length === 0) {
-                    this.filterType = ["all"];
-                }
-                this.doFilter();
-            },
-
-            /**
-             * 筛选难度
-             * @param val
-             */
-            filterDiffChange(val) {
-                if (val.length > 1 && val.indexOf("all") === 0) {
-                    this.filterDiff.splice(val.indexOf("all"), 1);
-                } else if (val.indexOf("all") > -1 || val.length === 0) {
-                    this.filterDiff = ["all"];
-                }
-                this.doFilter();
-            },
-
-            /**
-             * 筛选认知层次
-             * @param val
-             */
-            filterFieldChange(val) {
-                if (val.length > 1 && val.indexOf("all") === 0) {
-                    this.filterField.splice(val.indexOf("all"), 1);
-                } else if (val.indexOf("all") > -1 || val.length === 0) {
-                    this.filterField = ["all"];
-                }
-                this.doFilter();
-            },
-
-            /**
-             * 排序条件更换
-             * @param val
-             */
-            filterSortChange(val) {
-                this.doFilter();
-            },
-
-            /**
-             * 删除筛选条件里面的False值与All值
-             * @param arr
-             */
-            deleteFalse(arr) {
-                let list = JSON.parse(JSON.stringify(arr));
-                list.forEach((item, index) => {
-                    if (!item || item === "all") list.splice(index, 1);
-                });
-                return list;
-            },
-
-            /**
-             * 切换页码操作
-             * @param page
-             */
-            async pageChange(page) {
-                this.pageNum = page;
-                let start = this.pageSize * (page - 1);
-                let end = this.pageSize * page;
-                // 拿到当前页码需要展示的数据
-                let simpleList = this.originData.slice(start, end);
-                try {
-                    // 执行试题换取完整JSON数据
-                    this.exerciseList = await this.$evTools.getFullItem(simpleList);
-                    this.currentPage = page;
-                    // 公式渲染
-                    this.$nextTick(() => {
-                        this.$MathJax.MathQueue(this.$refs.mathJaxContainer);
-                    });
-                } catch (e) {
-                    console.log(e);
-                }
-            },
-
-            /**
-             * 切换每页显示数量
-             * @param val
-             */
-            pageSizeChange(val) {
-                this.pageSize = val;
-                this.pageChange(1);
-            },
-            
+            }
+            this.doFilter();
         },
-        mounted() {
-            // 公式渲染
-            this.$nextTick(() => {
-                window.MathJax.Hub.Queue([
-                    "Typeset",
-                    MathJax.Hub,
-                    this.$refs.mathJaxContainer,
-                ]);
+
+        /**
+         * 根据题库加载题目
+         * @param val
+         */
+        filterOriginChange(origin) {
+            this.filterOrigin = origin;
+            this.doFilter();
+        },
+
+        /**
+         * 筛选题型
+         * @param val
+         */
+        filterTypeChange(val) {
+            if (val.length > 1 && val.indexOf("all") === 0) {
+                this.filterType.splice(val.indexOf("all"), 1);
+            } else if (val.indexOf("all") > -1 || val.length === 0) {
+                this.filterType = ["all"];
+            }
+            this.doFilter();
+        },
+
+        /**
+         * 筛选难度
+         * @param val
+         */
+        filterDiffChange(val) {
+            if (val.length > 1 && val.indexOf("all") === 0) {
+                this.filterDiff.splice(val.indexOf("all"), 1);
+            } else if (val.indexOf("all") > -1 || val.length === 0) {
+                this.filterDiff = ["all"];
+            }
+            this.doFilter();
+        },
+
+        /**
+         * 筛选认知层次
+         * @param val
+         */
+        filterFieldChange(val) {
+            if (val.length > 1 && val.indexOf("all") === 0) {
+                this.filterField.splice(val.indexOf("all"), 1);
+            } else if (val.indexOf("all") > -1 || val.length === 0) {
+                this.filterField = ["all"];
+            }
+            this.doFilter();
+        },
+
+        /**
+         * 排序条件更换
+         * @param val
+         */
+        filterSortChange(val) {
+            this.doFilter();
+        },
+
+        /**
+         * 删除筛选条件里面的False值与All值
+         * @param arr
+         */
+        deleteFalse(arr) {
+            let list = JSON.parse(JSON.stringify(arr));
+            list.forEach((item, index) => {
+                if (!item || item === "all") list.splice(index, 1);
             });
+            return list;
         },
-        computed: {
-            headers() {
-                let hd = {};
-                hd["Authorization"] = "Bearer " + localStorage.getItem("token");
-                return hd;
-            },
-            curScope() {
-                return this.filterOrigin === this.$store.state.userInfo.schoolCode ?
-                    "school" :
-                    "private";
-            },
-            hasSchool() {
-                return this.$store.state.userInfo.hasSchool;
-            },
+
+        /**
+         * 切换页码操作
+         * @param page
+         */
+        async pageChange(page) {
+            this.pageNum = page;
+            let start = this.pageSize * (page - 1);
+            let end = this.pageSize * page;
+            // 拿到当前页码需要展示的数据
+            let simpleList = this.originData.slice(start, end);
+            try {
+                // 执行试题换取完整JSON数据
+                this.exerciseList = await this.$evTools.getFullItem(simpleList);
+                this.currentPage = page;
+                // 公式渲染
+                this.$nextTick(() => {
+                    this.$MathJax.MathQueue(this.$refs.mathJaxContainer);
+                });
+            } catch (e) {
+                console.log(e);
+            }
         },
-    };
+
+        /**
+         * 切换每页显示数量
+         * @param val
+         */
+        pageSizeChange(val) {
+            this.pageSize = val;
+            this.pageChange(1);
+        },
+
+    },
+    mounted() {
+        // 公式渲染
+        this.$nextTick(() => {
+            window.MathJax.Hub.Queue([
+                "Typeset",
+                MathJax.Hub,
+                this.$refs.mathJaxContainer,
+            ]);
+        });
+    },
+    computed: {
+        headers() {
+            let hd = {};
+            hd["Authorization"] = "Bearer " + localStorage.getItem("token");
+            return hd;
+        },
+        curScope() {
+            return this.filterOrigin === this.$store.state.userInfo.schoolCode ?
+                "school" :
+                "private";
+        },
+        hasSchool() {
+            return this.$store.state.userInfo.hasSchool;
+        },
+    },
+};
 </script>
 <style scoped lang="less">
-    @import "./ExerciseList.less";
+@import "./ExerciseList.less";
 </style>
 
 <style>
-    .circle {
-        border: solid 1px red;
-        background-color: red;
-        border-radius: 50%;
-        width: 50px;
-        height: 50px;
-    }
-
-    .slide-enter-active {
-        transition: all 0.3s ease;
-    }
-
-    .slide-leave-active {
-        transition: all 0.3s ease;
-    }
-
-    .slide-enter,
-    .slide-leave-to {
-        transform: translateY(10px);
-        opacity: 0;
-    }
+.circle {
+    border: solid 1px red;
+    background-color: red;
+    border-radius: 50%;
+    width: 50px;
+    height: 50px;
+}
+
+.slide-enter-active {
+    transition: all 0.3s ease;
+}
+
+.slide-leave-active {
+    transition: all 0.3s ease;
+}
+
+.slide-enter,
+.slide-leave-to {
+    transform: translateY(10px);
+    opacity: 0;
+}
 </style>

File diff suppressed because it is too large
+ 549 - 596
TEAMModelOS/ClientApp/src/components/selflearn/NewChooseContent.vue


+ 25 - 13
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseKnowledgeDetail.vue

@@ -193,8 +193,9 @@
             },
 
             doRender(data) {
+				console.log(data)
                 this.x = data.pointList
-                this.y = data.stupercent.grade.map(item => (Number(item) * 100).toFixed(0))
+                this.y = data.stupercent.grade.map(item => (Number(item)).toFixed(2))
                 this.drawLine()
             }
         },
@@ -219,21 +220,32 @@
             // 获取最新散点图数据
             getKnowledgeData() {
 				let curSubjectIndex = this.$store.state.totalAnalysis.analysisJson.subjects.map(i => i.name).indexOf(this.$store.state.totalAnalysis.currentSubject)
-                return this.echartsId === 'knowDetailBar' ? this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].pointKey : 
+                let curJson = this.echartsId === 'knowDetailBar' ? this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].pointKey : 
 				this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].levelKey
+				if(this.echartsId !== 'knowDetailBar'){
+					let transArr = this.$GLOBAL.EXERCISE_LEVELS()
+					curJson.pointList = curJson.pointList.map((i,index) => transArr[index])
+					for(let key in curJson.classpercent){
+						if(!isNaN(key)){
+							let newKey = transArr[+key - 1]
+							curJson.classpercent[newKey] = curJson.classpercent[key]
+							curJson.stupercent[newKey] = curJson.stupercent[key]
+						}
+					}
+				}
+				return curJson
             }
         },
-        watch: {
-            getKnowledgeData: {
-                deep: true,
-                handler(val) {
-                    if (val) {
-                        this.doRender(val)
-                    }
-                }
-
-            }
-        }
+		
+		watch: {
+		    getKnowledgeData: {
+		        handler(val) {
+		            if (val) {
+		                this.doRender(val)
+		            }
+		        }
+		    }
+		}
     }
 </script>
 

+ 0 - 1
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseKnowledgeRadar.vue

@@ -144,7 +144,6 @@
         },
         watch: {
             getKnowledgeData: {
-                deep: true,
                 handler(val) {
                     if (val) {
                         this.doRender(val)

+ 97 - 94
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseLevelPie.vue

@@ -1,108 +1,111 @@
 <template>
-    <div class="myLevelPie" :id="pieId" ></div>
+	<div class="myLevelPie" :id="pieId"></div>
 </template>
 
 <script>
-    export default {
-        name: 'BasePie',
-        props: ['pieId'],
-        data() {
-            return {
-                pieData: []
-            }
-        },
-        methods: {
+	export default {
+		name: 'BasePie',
+		props: ['pieId'],
+		data() {
+			return {
+				pieData: []
+			}
+		},
+		methods: {
 
-            drawLine(data) {
-                let that = this
+			drawLine(data) {
+				let that = this
 
-                // 基于准备好的dom,初始化echarts实例
-                let myLevelPie = this.$echarts.init(document.getElementById(this.pieId), 'chalk')
+				// 基于准备好的dom,初始化echarts实例
+				let myLevelPie = this.$echarts.init(document.getElementById(this.pieId), 'chalk')
 
-                // 指定图表的配置项和数据
-                var option = {
-                    tooltip: {
-                        trigger: 'item',
-                        formatter: '{a} <br/>{b} : {c} ({d}%)'
-                    },
-                    calculable: true,
-                    roseType: true,
-                    series: {
-                        name: that.$t('totalAnalysis.ka_title1'),
-                        type: 'pie',
-                        radius: [40, 150],
-                        center: ['45%', 190],
-                        max: 100, // for funnel
-                        sort: 'ascending', // for funnel
-                        data: data
-                    }
-                }
+				// 指定图表的配置项和数据
+				var option = {
+					tooltip: {
+						trigger: 'item',
+						formatter: '{a} <br/>{b} : {c} ({d}%)'
+					},
+					calculable: true,
+					roseType: true,
+					series: {
+						name: that.$t('totalAnalysis.le_title1'),
+						type: 'pie',
+						radius: [40, 150],
+						center: ['45%', 190],
+						max: 100, // for funnel
+						sort: 'ascending', // for funnel
+						data: data
+					}
+				}
 
-                // 绘制图表
-                myLevelPie.setOption(option)
-                window.addEventListener('resize', function() {
-                    myLevelPie.resize()
-                })
-            }
-        },
-        mounted() {
-            if (this.getPieData) {
-                let pointList = this.getPieData.pointList
-                let valList = this.getPieData.fper
-                let arr = []
-                pointList.forEach((item, index) => {
-                    let o = {}
-                    o.name = item
-                    o.value = valList[index].replace('%', '')
-                    arr.push(o)
-                })
-                this.drawLine(arr)
-            }
-        },
-        computed: {
-            // 获取最新知识点占比饼图数据
-            getPieData() {
-				let curSubjectIndex = this.$store.state.totalAnalysis.analysisJson.subjects.map(i => i.name).indexOf(this.$store.state.totalAnalysis.currentSubject)
-                let levelJson = this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].levelKey
-                let transArr = ["知识", "理解", "应用", "分析", "综合", "评鉴"]
-                levelJson.pointList = levelJson.pointList.map((i,index) => transArr[index])
-                for(let key in levelJson.classpercent){
-                	if(key !== 'className'){
-                		let newKey = transArr[+key - 1]
-                		levelJson.classpercent[newKey] = levelJson.classpercent[key]
-                	}
-                }
-                return levelJson
-            }
-        },
-        watch: {
-            // getPieData: {
-            //     deep: true,
-            //     handler(val) {
-            //         let pointList = val.level
-            //         let valList = val.fper
-            //         let arr = []
-            //         pointList.forEach((item, index) => {
-            //             let o = {}
-            //             o.name = item
-            //             o.value = valList[index].replace('%', '')
-            //             arr.push(o)
-            //         })
-            //         this.drawLine(arr)
-            //     }
-            // }
-        }
+				// 绘制图表
+				myLevelPie.setOption(option)
+				window.addEventListener('resize', function() {
+					myLevelPie.resize()
+				})
+			}
+		},
+		mounted() {
+			if (this.getPieData) {
+				let pointList = this.getPieData.pointList
+				let valList = this.getPieData.per
+				let arr = []
+				pointList.forEach((item, index) => {
+					let o = {}
+					o.name = item
+					o.value = valList[index].replace('%', '')
+					arr.push(o)
+				})
+				this.drawLine(arr)
+			}
+		},
+		computed: {
+			// 获取最新知识点占比饼图数据
+			getPieData() {
+				let curSubjectIndex = this.$store.state.totalAnalysis.analysisJson.subjects.map(i => i.name).indexOf(this.$store.state
+					.totalAnalysis.currentSubject)
+				let levelJson = this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].levelKey
+				let transArr = this.$GLOBAL.EXERCISE_LEVELS()
+				levelJson.pointList = levelJson.pointList.map((i, index) => transArr[index])
+				for (let key in levelJson.classpercent) {
+					if (key !== 'className') {
+						let newKey = transArr[+key - 1]
+						levelJson.classpercent[newKey] = levelJson.classpercent[key]
+					}
+				}
+				return levelJson
+			},
+			getKnowledgeData() {
+				let curSubjectIndex = this.$store.state.totalAnalysis.analysisJson.subjects.map(i => i.name).indexOf(this.$store.state
+					.totalAnalysis.currentSubject)
+				return this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].pointKey
+			},
+		},
+		watch: {
+			getKnowledgeData(val) {
+				if (!val) return
+				let pointList = this.getPieData.pointList
+				let valList = this.getPieData.per
+				let arr = []
+				pointList.forEach((item, index) => {
+					let o = {}
+					o.name = item
+					o.value = valList[index].replace('%', '')
+					arr.push(o)
+				})
+				this.drawLine(arr)
+			}
+		}
 
-    }
+	}
 </script>
 
 <!-- Add "scoped" attribute to limit CSS to this component only -->
 <style scoped>
-
-    .myLevelPie {
-        width: 100%;
-        height: 380px;
-        margin: 0 auto;
-        display: block;
-    }
+	.myLevelPie {
+		width: 100%;
+		height: 380px;
+		margin: 0 auto;
+		display: block;
+	}
 </style>

+ 160 - 164
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseLevelRadar.vue

@@ -1,178 +1,174 @@
 <template>
-    <div>
-        <div :id="echartsId" class="myRadar"></div>
-    </div>
+	<div>
+		<div :id="echartsId" class="myRadar"></div>
+	</div>
 </template>
 
 <script>
-    export default {
-        name: 'helloLine',
-        props: ['echartsId'],
-        data() {
-            return {
-                radarData: []
-            }
-        },
-        mounted() {
-            this.radarData = this.getRadarData
-            this.drawLine(this.radarData)
-        },
-        methods: {
-            drawLine(indicator, data) {
-                // 基于准备好的dom,初始化echarts实例
-                let that = this
-                let myRadar = this.$echarts.init(document.getElementById(this.echartsId), 'chalk')
+	export default {
+		name: 'helloLine',
+		props: ['echartsId'],
+		data() {
+			return {
+				radarData: []
+			}
+		},
+		mounted() {
+			this.radarData = this.getRadarData
+			this.drawLine(this.radarData)
+		},
+		methods: {
+			drawLine(indicator, data) {
+				// 基于准备好的dom,初始化echarts实例
+				let that = this
+				let myRadar = this.$echarts.init(document.getElementById(this.echartsId), 'chalk')
 
-                // 指定图表的配置项和数据
-                var option = {
-                    tooltip: {
-                        formatter: function(params) {
-                            var results = params.marker + '知识点占比情况<br>'
-                            for (var i = 0; i < params.value.length; i++) {
-                                results += indicator[i].name + ':' + params.value[i] + '%<br>'
-                            }
-                            return results
-                        } },
-                    radar: {
-                        triggerEvent: true,
-                        name: {
-                            textStyle: {
-                                color: '#fff',
-                                borderRadius: 3,
-                                fontSize: 14,
-                                padding: [13, 15]
-                            }
-                        },
-                        center: ['50%', '50%'],
-                        tooltip: {
+				// 指定图表的配置项和数据
+				var option = {
+					tooltip: {
+						formatter: function(params) {
+							var results = params.marker + '认知层次占比情况<br>'
+							for (var i = 0; i < params.value.length; i++) {
+								results += indicator[i].name + ':' + params.value[i] + '%<br>'
+							}
+							return results
+						}
+					},
+					radar: {
+						triggerEvent: true,
+						name: {
+							textStyle: {
+								color: '#fff',
+								borderRadius: 3,
+								fontSize: 14,
+								padding: [13, 15]
+							}
+						},
+						center: ['50%', '50%'],
+						tooltip: {
 
-                        },
-                        indicator: indicator,
-                        splitArea: {
-                            areaStyle: {
-                                // color: [
-                                //  'rgba(222,134,85, 0.1)', 'rgba(222,134,85, 0.2)',
-                                //  'rgba(222,134,85, 0.4)', 'rgba(222,134,85, 0.6)',
-                                //  'rgba(222,134,85, 0.8)', 'rgba(222,134,85, 1)'
-                                // ].reverse()
-                            }
-                        },
-                        axisLine: { // 指向外圈文本的分隔线样式
-                            lineStyle: {
-                                color: 'rgba(255,255,255,0.2)'
-                            }
-                        },
-                        splitLine: {
-                            lineStyle: {
-                                width: 2,
-                                color: [
-                                    'rgba(224,134,82, 0.1)', 'rgba(224,134,82, 0.2)',
-                                    'rgba(224,134,82, 0.4)', 'rgba(224,134,82, 0.6)',
-                                    'rgba(224,134,82, 0.8)', 'rgba(224,134,82, 1)'
-                                ].reverse()
-                            }
-                        }
-                    },
-                    series: [
-                        {
-                            name: '',
-                            type: 'radar',
-                            itemStyle: {
-                                color: '#22CEE7'
-                            },
-                            areaStyle: {
-                                color: {
-                                    type: 'linear',
-                                    x: 0,
-                                    y: 0,
-                                    x2: 0,
-                                    y2: 1,
-                                    colorStops: [
-                                        {
-                                            offset: 0,
-                                            color: '#2cc7cb' // 0% 处的颜色
-                                        },
-                                        {
-                                            offset: 1,
-                                            color: '#59b2ef' // 100% 处的颜色
-                                        }
-                                    ],
-                                    global: false // 缺省为 false
-                                }
-                            },
-                            lineStyle: {
-                                color: '#9FACE6'
-                            },
-                            data: [
-                                {
-                                    value: data,
-                                    name: '知识点占比'
-                                }
-                            ]
-                        }
-                    ]
-                }
+						},
+						indicator: indicator,
+						splitArea: {
+							areaStyle: {
+								// color: [
+								//  'rgba(222,134,85, 0.1)', 'rgba(222,134,85, 0.2)',
+								//  'rgba(222,134,85, 0.4)', 'rgba(222,134,85, 0.6)',
+								//  'rgba(222,134,85, 0.8)', 'rgba(222,134,85, 1)'
+								// ].reverse()
+							}
+						},
+						axisLine: { // 指向外圈文本的分隔线样式
+							lineStyle: {
+								color: 'rgba(255,255,255,0.2)'
+							}
+						},
+						splitLine: {
+							lineStyle: {
+								width: 2,
+								color: [
+									'rgba(224,134,82, 0.1)', 'rgba(224,134,82, 0.2)',
+									'rgba(224,134,82, 0.4)', 'rgba(224,134,82, 0.6)',
+									'rgba(224,134,82, 0.8)', 'rgba(224,134,82, 1)'
+								].reverse()
+							}
+						}
+					},
+					series: [{
+						name: '',
+						type: 'radar',
+						itemStyle: {
+							color: '#22CEE7'
+						},
+						areaStyle: {
+							color: {
+								type: 'linear',
+								x: 0,
+								y: 0,
+								x2: 0,
+								y2: 1,
+								colorStops: [{
+										offset: 0,
+										color: '#2cc7cb' // 0% 处的颜色
+									},
+									{
+										offset: 1,
+										color: '#59b2ef' // 100% 处的颜色
+									}
+								],
+								global: false // 缺省为 false
+							}
+						},
+						lineStyle: {
+							color: '#9FACE6'
+						},
+						data: [{
+							value: data,
+							name: '知识点占比'
+						}]
+					}]
+				}
 
-                // 绘制图表
-                myRadar.setOption(option)
-            },
+				// 绘制图表
+				myRadar.setOption(option)
+			},
 
-            doRender(data) {
-                let list = data
-                let indicator = []
-                list.pointList.forEach(item => {
-                    indicator.push({
-                        name: item,
-                        max: 100
-                    })
-                })
-                this.drawLine(indicator, list.per.map(item => (Number(item) * 100).toFixed(2)))
-            }
-        },
-        mounted() {
-            if (this.getKnowledgeData) {
-                this.doRender(this.getKnowledgeData)
-            }
-        },
+			doRender(data) {
+				let list = data
+				let indicator = []
+				list.pointList.forEach(item => {
+					indicator.push({
+						name: item,
+						max: 100
+					})
+				})
+				this.drawLine(indicator, list.per.map(item => (Number(item) * 100).toFixed(2)))
+			}
+		},
+		mounted() {
+			if (this.getLevelData) {
+				this.doRender(this.getLevelData)
+			}
+		},
 
-        computed: {
-            // 获取最新散点图数据
-            getKnowledgeData() {
-                let curSubjectIndex = this.$store.state.totalAnalysis.analysisJson.subjects.map(i => i.name).indexOf(this.$store.state.totalAnalysis.currentSubject)
-                let levelJson = this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].levelKey
-                let transArr = ["知识", "理解", "应用", "分析", "综合", "评鉴"]
-                levelJson.pointList = levelJson.pointList.map((i,index) => transArr[index])
-                for(let key in levelJson.classpercent){
-                	if(key !== 'className'){
-                		let newKey = transArr[+key - 1]
-                		levelJson.classpercent[newKey] = levelJson.classpercent[key]
-                	}
-                }
-                return levelJson
-            }
-        },
-        watch: {
-            getKnowledgeData: {
-                deep: true,
-                handler(val) {
-                    if (val) {
-                        this.doRender(val)
-                    }
-                }
-
-            }
-        }
-    }
+		computed: {
+			// 获取最新散点图数据
+			getLevelData() {
+				let curSubjectIndex = this.$store.state.totalAnalysis.analysisJson.subjects.map(i => i.name).indexOf(this.$store.state
+					.totalAnalysis.currentSubject)
+				let levelJson = this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].levelKey
+				let transArr = this.$GLOBAL.EXERCISE_LEVELS()
+				levelJson.pointList = levelJson.pointList.map((i, index) => transArr[index])
+				for (let key in levelJson.classpercent) {
+					if (key !== 'className') {
+						let newKey = transArr[+key - 1]
+						levelJson.classpercent[newKey] = levelJson.classpercent[key]
+					}
+				}
+				return levelJson
+			},
+			getKnowledgeData() {
+				let curSubjectIndex = this.$store.state.totalAnalysis.analysisJson.subjects.map(i => i.name).indexOf(this.$store.state
+					.totalAnalysis.currentSubject)
+				return this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].pointKey
+			},
+		},
+		watch: {
+			getKnowledgeData(val) {
+				if (!val) return
+				this.doRender(this.getLevelData)
+			}
+		}
+	}
 </script>
 
 <!-- Add "scoped" attribute to limit CSS to this component only -->
 <style scoped>
-
-    .myRadar {
-        width: 100%;
-        height: 480px;
-        margin: 50px auto 0 auto;
-        padding: 30px;
-        display: block;
-    }
+	.myRadar {
+		width: 100%;
+		height: 480px;
+		margin: 50px auto 0 auto;
+		padding: 30px;
+		display: block;
+	}
 </style>

+ 15 - 13
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseMyTable.vue

@@ -146,12 +146,14 @@
 			// 筛选操作
             onFilterChange(val) {
                 let filterValue = val._filterChecked[0]
+				const ipoint = this.$store.state.totalAnalysis.analysisJson.ipoint
+				const touchScore = this.$store.state.totalAnalysis.analysisJson.touchScore
                 switch (filterValue) {
                     case 1:
-                        this.originData = this.tableDatas.filter(item => item.score > 180)
+                        this.originData = this.tableDatas.filter(item => item.score > ipoint)
                         break
                     case 2:
-                        this.originData = this.tableDatas.filter(item => item.score > 180 && item.score < 200)
+                        this.originData = this.tableDatas.filter(item => item.score > ipoint && item.score < (ipoint + touchScore))
                         break
                     case 3:
                         console.log('进步班级')
@@ -213,17 +215,17 @@
                             className: 'table-rank-value'
                         }
                     }, params.row.classId),
-                    h('Icon', {
-                        props: {
-                            type: (row.changesStatus === 1 && row.changesVal !== 0) ? 'md-trending-up' : (row.changesStatus === -1 && row.changesVal !== 0) ? 'md-trending-down' : 'md-git-commit',
-                            color: (row.changesStatus === 1 && row.changesVal !== 0) ? '#13ff13' : (row.changesStatus === -1 && row.changesVal !== 0) ? '#fd4e4e' : 'yellow',
-                            size: '22'
-                        },
-                        style: {
-                            cursor: 'pointer',
-                            marginLeft: '10px'
-                        }
-                    })
+                    // h('Icon', {
+                    //     props: {
+                    //         type: (row.changesStatus === 1 && row.changesVal !== 0) ? 'md-trending-up' : (row.changesStatus === -1 && row.changesVal !== 0) ? 'md-trending-down' : 'md-git-commit',
+                    //         color: (row.changesStatus === 1 && row.changesVal !== 0) ? '#13ff13' : (row.changesStatus === -1 && row.changesVal !== 0) ? '#fd4e4e' : 'yellow',
+                    //         size: '22'
+                    //     },
+                    //     style: {
+                    //         cursor: 'pointer',
+                    //         marginLeft: '10px'
+                    //     }
+                    // })
 
                 ])
             },

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

@@ -120,15 +120,14 @@
             },
 
             doRender(data) {
-                let list = data
                 let indicator = []
-                list.pointList.forEach(item => {
+                data.pointList.forEach(item => {
                     indicator.push({
                         name: item,
                         max: 100
                     })
                 })
-                this.drawLine(indicator, list.stupercent.grade.map(item => (Number(item) * 100).toFixed(0)))
+                this.drawLine(indicator, data.stupercent.grade.map(item => (Number(item)).toFixed(2)))
             }
         },
         mounted() {
@@ -140,18 +139,21 @@
         computed: {
             // 获取最新雷达图数据
             getKnowledgeData() {
-                return this.echartsId === 'knowRadar' ? this.$store.state.totalAnalysis.analysisJson.pointKey : this.$store.state.totalAnalysis.analysisJson.levelKey
-            }
-        },
-        watch: {
-            getKnowledgeData: {
-                deep: true,
-                handler(val) {
-                    if (val) {
-                        this.doRender(val)
-                    }
-                }
-
+				let curSubjectIndex = this.$store.state.totalAnalysis.analysisJson.subjects.map(i => i.name).indexOf(this.$store.state.totalAnalysis.currentSubject)
+				let curJson = this.echartsId === 'knowRadar' ? this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].pointKey : 
+				this.$store.state.totalAnalysis.analysisJson.pointLevelKey[curSubjectIndex].levelKey
+				if(this.echartsId !== 'knowRadar'){
+					let transArr = this.$GLOBAL.EXERCISE_LEVELS()
+					curJson.pointList = curJson.pointList.map((i,index) => transArr[index])
+					for(let key in curJson.classpercent){
+						if(!isNaN(key)){
+							let newKey = transArr[+key - 1]
+							curJson.classpercent[newKey] = curJson.classpercent[key]
+							curJson.stupercent[newKey] = curJson.stupercent[key]
+						}
+					}
+				}
+				return curJson
             }
         }
     }

+ 1 - 1
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseScatter.vue

@@ -28,7 +28,7 @@
 				let newArr = []
 				analysisJson.forEach(item => {
 					let arr2 = []
-					arr2.push((item.x * 100).toFixed(2))
+					arr2.push((+item.x).toFixed(2))
 					arr2.push((item.y * 100).toFixed(2))
 					arr2.push(item.name)
 					arr2.push(item.memberId)

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

@@ -21,14 +21,13 @@
     </div>
         <!-- 如果篩選時未選的時候預設顯示列表第一個-->
     <div class="noSelected" v-if="!this.$store.getters.getIsSelectedNow">
-        <h3>请从列表挑选一个活动</h3>
+        <h3>{{$t("studentWeb.event.selectActivity")}}</h3>
     </div>
 
   </div>
 </template>
 
 <script>
-import mockdata from "@/api";
 import Homework from "./EventContentTypeTemplate/Homework";
 import PreviewMission from "./EventContentTypeTemplate/PreviewMission";
 import Vote from "./EventContentTypeTemplate/Vote";

+ 236 - 144
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue

@@ -5,8 +5,8 @@
                 <svg-icon icon-class="handonHint" class="warm-icon" />
                 <span class="warm-hint">{{ $t("studentWeb.exam.timeoutHint") }}</span>
             </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'>
                 <i-col :xs="24" :sm="24" :md="24" :lg="12">
                     <Row :gutter="20">
@@ -39,7 +39,7 @@
                         </i-col>
                         <i-col :xs="24" :sm="24" :md="12" :lg="12">
                             <Card class="score-card">
-                                <p class="card-title">得分题目数</p>
+                                <p class="card-title">{{$t("studentWeb.exam.report.getScore")}}</p>
                                 <div class="card-content">
                                     <span class="myscore">{{rightAns.right}}</span> / {{rightAns.all}}
                                 </div>
@@ -70,23 +70,22 @@
         <div class="QAsheet" v-if='testState != 1'>
             <div class='title-rect-group '>
                 <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 class="filterBtn">
-                <br />
                 <label class="checkAns">
                     <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>
                 </label>
                 <label class="checkAns">
                     <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>
-                </label>           
+                </label>
                 <label class="checkAns" v-show=" rightAns.noAns != 0 ">
                     <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>
                 </label>
             </div>
@@ -95,83 +94,156 @@
             </div>
             <br style="clear:both" />
             <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] != 0 && examInfo.stuScore[index] != -1"
-                                              icon-class="rightAns" />
-                                    <svg-icon class="qIcon"
-                                              v-show="examInfo.stuScore[index] == 0"
-                                              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>
-                            </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>
-                                    <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 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>
-                            <!--<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 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 />
-                                <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 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>
 </template>
 
 <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 { Random } from "mockjs";
     import Loading from "vue-loading-overlay";
@@ -202,11 +274,7 @@
                 isLoading: true,
                 opacity: 0.6,
                 //loading畫面
-                currentReportSubject: "國文",
                 closeAnsDetail: false,
-                RandomComment: Random.paragraph(1, 2),
-                RandomKeypoint: Random.paragraph(1, 3),
-                mockQASheet: mockQASheet.mockQASheet,
                 checkedAns: ["right", "wrong", "noAns"],
                 testState: 0,
                 testType: [
@@ -244,7 +312,13 @@
                     },
                 ],
                 paperData: [],
-                ansData:[]
+                ansData: [],
+                repairSource: {
+                    normal: [],
+                    file: []
+                },
+                repairData: [],
+                previewStatus: false
             };
         },
         mounted() {
@@ -252,6 +326,54 @@
             this.testJudge()
         },
         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() {
                 if (this.examInfo.subject !== undefined) {
                     this.$store.commit("ToggleLessonTestPopWithSubject", this.examInfo)
@@ -296,12 +418,24 @@
                         code: key[(key.length - 1)],
                         blob: data
                     }
+                    let blob = this.formUrl(code)
+                    code.blob = blob
                     datas = await this.$evTools.getComposeItem(code)
                     return datas
                 } else {
                     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() {
                 let paper = []
                 this.paperData.length = []
@@ -342,13 +476,6 @@
             getCurrentLang() {
                 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() {
                 return Random.integer(70, 96)
             },
@@ -365,32 +492,10 @@
             closeDetail() {
                 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) {
-                if (this.checkedAns.includes("right") == true && this.examInfo.stuScore[index] != 0 && this.examInfo.stuScore[index] != -1 ) {
+                if (this.checkedAns.includes("right") == true && this.examInfo.stuScore[index] == this.paperData[index].score) {
                     return true;
-                } else if (this.checkedAns.includes("wrong") == true && this.examInfo.stuScore[index] == 0 )
+                } else if (this.checkedAns.includes("wrong") == true && this.examInfo.stuScore[index] != -1 && this.examInfo.stuScore[index] != this.paperData[index].score)
                 {
                     return true;
                 } else if (this.checkedAns.includes("noAns") == true && this.examInfo.stuScore[index] == -1) {
@@ -399,32 +504,6 @@
                 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: {
             testScore() {
@@ -448,11 +527,13 @@
                         right: 0,
                         noAns:0
                     }
-                    for (let item of this.examInfo.stuScore) {
-                        if (item !== 0 && item == -1) {
-                            info.noAns++
-                        } else if (item !== 0 && item !== -1) {
-                            info.right++
+                    if (this.paperData[0]!= undefined) {
+                        for (let i = 0; i < this.examInfo.stuScore.length; i++) {
+                            if (this.examInfo.stuScore[i] == -1) {
+                                info.noAns++
+                            } else if (this.examInfo.stuScore[i] == this.paperData[i].score && this.examInfo.stuScore[i] != -1) {
+                                info.right++
+                            }
                         }
                     }
                 }
@@ -629,7 +710,7 @@
     }
 
     .qAnaly .rightAns {
-        color: rgb(20, 114, 199);
+        color: #00ad6c;
     }
 
     .qAnserlist {
@@ -642,7 +723,7 @@
     }
 
     .rightAnsItem {
-        color: rgb(20, 114, 199);
+        color: #00ad6c;
     }
 
     .wrongAnsItem {
@@ -714,23 +795,27 @@
             font-weight: bolder;
         }
 
+        .checkAns input[type="checkbox"]:checked ~ .rightBtn{
+            background-color: #00ad6c !important;
+            border: none;
+        }  
+        
         .checkAns input[type="checkbox"]:checked ~ .noAnsBtn {
             background-color: rgb(183, 183, 183) !important;
             border: none;
         }
 
-        .checkAns input[type="checkbox"]:checked ~ .rightBtn {
+/*        .checkAns input[type="checkbox"]:checked ~ .rightBtn {
             background-color: rgb(20, 114, 199) !important;
             border: none;
-        }
+        }*/
 
         .checkAns input[type="checkbox"]:checked ~ .wrongBtn {
             background-color: rgb(255, 85, 8) !important;
             border: none;
         }
-
-    .noAnsBtn,
     .rightBtn,
+    .noAnsBtn,
     .wrongBtn {
         background-color: #fff;
         position: relative;
@@ -775,11 +860,18 @@
         top: -70%;
         right: -40%;
         font-size: 20px;
-        color: rgba(0, 0, 0, 0.5)
+        color: rgba(0, 0, 0, 0.5);
     }
 
     .vld-overlay {
         outline: none;
-        border: none
+        border: none;
+    }
+    .repair-box{
+        width:100%;
     }
+        .repair-box /deep/ .ivu-list-container{
+            max-height:300px;
+            overflow:scroll;
+        }
 </style>

+ 178 - 80
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReportCharts/StudentScore.vue

@@ -4,22 +4,22 @@
             <div class="stu-info">
                 <ul>
                     <li>
-                        <p><Icon type="ios-home" size="24" />本次考试名称:<span>成都市第三次月考</span></p>
+                        <p><Icon type="ios-home" size="24" />本次考试名称:<span>--</span></p>
                     </li>
                     <li>
-                        <p><Icon type="ios-paper" size="24" />考试类型:<span>正规考</span></p>
+                        <p><Icon type="ios-paper" size="24" />考试类型:<span>--</span></p>
                     </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>
-                        <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>
-                        <p style="margin-top:5px">学号:<span>12345678</span></p>
+                        <p style="margin-top:5px">学号:<span>{{$store.state.userInfo.sub}}</span></p>
                     </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>
                 </ul>
             </div>
@@ -28,35 +28,36 @@
                 <ul>
                     <li style="margin-right:5%;margin-top:15px;margin-left:3%">
                         <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 class="sub-ave">
                         <h2>班级平均分</h2>
-                        <p>472</p>
+                        <p>{{scoreInfo.classAverage}}</p>
                     </li>
                     <li class="sub-ave">
                         <h2>年级平均分</h2>
-                        <p>468</p>
+                        <p>{{scoreInfo.gradeAverage}}</p>
                     </li>
                     <li class="sub-ave">
                         <h2>区级平均分</h2>
-                        <p>457</p>
+                        <p>--</p>
                     </li>
                     <li class="sub-ave">
                         <h2>班级排名</h2>
-                        <p>05<span>/56</span></p>
+                        <p>{{scoreInfo.rankc}}<span>/{{scoreInfo.classCount}}</span></p>
                     </li>
                     <li class="sub-ave">
                         <h2>年级排名</h2>
-                        <p>65<span>/456</span></p>
+                        <p>{{scoreInfo.rankg}}<span>/{{scoreInfo.gradeCount}}</span></p>
                     </li>
                     <li class="sub-ave">
                         <h2>区级排名</h2>
-                        <p>296<span>/1456</span></p>
+                        <!--<p>-<span>/1456</span></p>-->
+                        <p>--</p>
                     </li>
                     <li>
                         <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>
                 </ul>
             </div>
@@ -93,102 +94,105 @@
                         <span>综合难度</span>
                     </li>
                 </ul>
-                <ul v-for="(item,index) in data.examInfo">
+                <ul v-for="(item,index) in scoreInfo.averageMap">
                     <li class="sub-item">
-                        <div class="sub-show"><span>{{item.subject}}</span></div>
+                        <div class="sub-show"><span>{{item.name}}</span></div>
                     </li>
                     <li class="sub-item">
-                        <p>{{item.stuScore}}<span>/{{item.score}}</span></p>
+                        <p>{{item.score}}<span>/{{item.scoreSum}}</span></p>
                     </li>
                     <li class="sub-item">
-                        <p>{{item.classAve}}</p>
+                        <p>{{item.classAverage}}</p>
                     </li>
                     <li class="sub-item">
-                        <p>{{item.gradeAve}}</p>
+                        <p>{{item.gradeAverage}}</p>
                     </li>
                     <li class="sub-item">
-                        <p>{{item.areaAve}}</p>
+                        <p>--</p>
                     </li>
                     <li class="sub-item">
-                        <p>08<span>/56</span></p>
+                        <p>{{item.classRank}}<span>/{{item.classCount}}</span></p>
                     </li>
                     <li class="sub-item">
-                        <p>45<span>/456</span></p>
+                        <p>{{item.gradeRank}}<span>/{{item.gradeCount}}</span></p>
                     </li>
                     <li class="sub-item">
-                        <p>455<span>/1456</span></p>
+                        <p>--<span>/--</span></p>
                     </li>
                     <li class="sub-item">
                         <div class="ans">
                             <div class="obj-ans">
                                 <h5>客观</h5>
-                                <p>36<span>/40</span></p>
+                                <p>{{item.sub.objIndex}}<span>/{{item.sub.objItem.length}}</span></p>
                             </div>
                             <div class="sub-ans">
                                 <h5>主观</h5>
-                                <p>5<span>/6</span></p>
+                                <p>{{item.sub.subIndex}}<span>/{{item.sub.subItem.length}}</span></p>
                             </div>
                         </div>
 
                     </li>
                     <li class="sub-item">
-                        <span>一般</span>
+                        <span>--</span>
                     </li>
                 </ul>
             </div>
             <div class="score-table">
-                <table class="gridtable" v-if="stuScore.length">
-                    <tr>
-                        <th>科目</th>
-                        <th>题号</th>
-                        <th>客观题</th>
-                        <th>主观题</th>
-                    </tr>
-                    <tbody v-for="(que,index) in stuScore" :key="index">
+                <div class="table-list">
+                    <table class="gridtable" v-if="stuScore.length" style="width: 100%; max-width: 100%;margin-bottom: 20px;">
                         <tr>
-                            <td  width="4%" rowspan="4">{{que.name}}</td>
+                            <th>科目</th>
+                            <th>题目</th>
+                            <th>客观题</th>
+                            <th>主观题</th>
                         </tr>
-                        <tr>
-                            <td   width="8%">题号</td>
-                            <td>
-                                <div class="score-box">
-                                    <span v-for="(objQue,obj) in que.item.objItem" :key="obj">{{objQue.paperIndex}}</span>
-                                </div>
-                            </td>
-                            <td>
-                                <div class="score-box">
-                                    <span v-for="(subQue,sub) in que.item.subItem" :key="sub">{{subQue.paperIndex}}</span>
-                                </div>
-                            </td>
-                        </tr>
-                        <tr>
-                            <td  width="8%">标准答案/配分</td>
-                            <td>
-                                <div class="score-box">
-                                    <span v-for="(objAns,obja) in que.item.objItem" :key="obja">{{objAns.answer.length > 1 ? '[?]': objAns.answer[0]}}</span>
-                                </div>
-                            </td>
-                            <td>
-                                <div class="score-box">
-                                    <span v-for="(subAns,suba) in que.item.subItem" :key="suba">{{subAns.score}}</span>
-                                </div>
-                            </td>
-                        </tr>
-                        <tr>
-                            <td width="8%">学生作答/得分</td>
-                            <td>
-                                <div class="score-box">
-                                    <span v-for="(objScore,objs) in que.item.objItem" :key="objs">{{objScore.stuScore == 0 ? objScore.stuAns[0] : '-'}}</span>
-                                </div>
-                            </td>
-                            <td>
-                                <div class="score-box">
-                                    <span v-for="(subScore,subs) in que.item.subItem" :key="subs">{{subScore.stuScore}}</span>
-                                </div>
-                            </td>
-                        </tr>
-                    </tbody>
-                </table>
+                        <tbody v-for="(que,index) in stuScore" :key="index">
+                            <tr>
+                                <td width="4%" rowspan="4">{{que.name}}</td>
+                            </tr>
+                            <tr>
+                                <td width="8%">题号</td>
+                                <td>
+                                    <div class="score-box">
+                                        <span v-for="(objQue,obj) in que.item.objItem" :key="obj">{{objQue.paperIndex}}</span>
+                                    </div>
+                                </td>
+                                <td>
+                                    <div class="score-box">
+                                        <span v-for="(subQue,sub) in que.item.subItem" :key="sub">{{subQue.paperIndex}}</span>
+                                    </div>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td width="8%">标准答案/配分</td>
+                                <td>
+                                    <div class="score-box">
+                                        <span v-for="(objAns,obja) in que.item.objItem" :key="obja">{{objAns.answer.length > 1 ? '[?]': objAns.answer[0]}}</span>
+                                    </div>
+                                </td>
+                                <td>
+                                    <div class="score-box">
+                                        <span v-for="(subAns,suba) in que.item.subItem" :key="suba">{{subAns.score}}</span>
+                                    </div>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td width="8%">学生作答/得分</td>
+                                <td>
+                                    <div class="score-box">
+                                        <span v-for="(objScore,objs) in que.item.objItem" :key="objs">{{objScore.stuScore == 0 ? objScore.stuAns[0] : '-'}}</span>
+                                    </div>
+                                </td>
+                                <td>
+                                    <div class="score-box">
+                                        <span v-for="(subScore,subs) in que.item.subItem" :key="subs">{{subScore.stuScore}}</span>
+                                    </div>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+
             </div>
             <div class="score-table">
                 <p style="color:#24b880">【-】--答对,【#】--未作答,【?】--多选题</p>
@@ -205,6 +209,12 @@
                 default: () => {
                     return {}
                 }
+            },    
+            examData: {
+                type: Array,
+                default: () => {
+                    return []
+                }
             }
         },
         data() {
@@ -266,8 +276,10 @@
                     ]
                 },
                 data10: [],
+
                 testData: [],
-                stuScore:[]
+                stuScore: [],
+                scoreInfo: {}
             }
         },
         methods: {
@@ -277,9 +289,46 @@
                     for (let i = 0; i < this.stuData.papers.length; i++) {
                         let subData = {}
                         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])
                         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) {
@@ -299,15 +348,25 @@
                     let answer = await this.getItem(ans)
                     paper = await this.formPaper(papers)
                     this.testData = paper
+                    let objIndex = 0
+                    let subIndex = 0
                     for (let i = 0; i < paper.length; i++) {
                         paper[i].stuScore = score[i]
                         paper[i].stuAns = answer[i]
                         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])
                         } else {
+                            if (paper[i].stuScore >= (paper[i].score * 0.8).toFixed(2)) {
+                                subIndex++
+                            }
                             item.subItem.push(paper[i])
                         }
                     }
+                    item.subIndex = subIndex
+                    item.objIndex = objIndex
                 }
                 return item
             },
@@ -357,6 +416,7 @@
         },
         mounted() {
             this.getPaperData()
+
         },
         watch: {
             stuData() {
@@ -370,6 +430,35 @@
     }
 </script>
 <style lang="less" scoped>
+    .stu-analyse table {
+        border-collapse: collapse;
+    }
+
+    .stu-analyse th, td {
+        padding: 5px;
+        text-align: center;
+        border: 1px solid #999;
+        min-width: 100px;
+    }
+
+    .stu-analyse th {
+        background-color: #333;
+        color: #fff;
+        position: sticky;
+        top: 0px;
+    }
+
+    .stu-analyse td:first-child {
+        color: #333;
+        position: sticky;
+        left: 0px;
+    }
+
+    .stu-analyse th:first-child {
+        left: 0px;
+    }
+
+
     .stu-analyse table.gridtable {
         /*font-family: verdana,arial,sans-serif;*/
         width: calc(100% - 10px);
@@ -396,11 +485,14 @@
             background-color: #ffffff;
         }
 
+    .stu-analyse .score-table{
+        overflow-x:scroll;
+    }
     .stu-analyse .score-table .gridtable span {
         display: block;
         /*height:100%;*/
-        text-align:center;
-        width:30px;
+        text-align: center;
+        width: 30px;
         /*border-right:1px solid #666666;*/
     }
 
@@ -433,7 +525,7 @@
             }
 
             .stu-analyse .stu-info li {
-                margin-right: 6%;
+                margin-right: 5%;
                 font-weight: 600;
                 font-size: 14px;
             }
@@ -589,5 +681,11 @@
             margin-left: 10px;
             width: calc(100% - 10px);
             padding-bottom: 10px;
+            padding-right: 10px;
+            overflow: hidden;
         }
+    .stu-analyse .score-table .table-list{
+        width:100%;
+        overflow:scroll;
+    }
 </style>

+ 24 - 25
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperTest.vue

@@ -12,34 +12,34 @@
             <div class="messageCard">
                 <!---中途離開測驗之提示框---->
                 <div class="messageCardContent1" v-if="showMessageNum == 1">
-                    <h3>离开测验提示</h3>
+                    <h3>{{$t("studentWeb.exam.testpop.exitQuizhint")}}</h3>
                     <svg-icon icon-class="logoutComfirm" class="logoutComfirmIcon" />
                     <br />
                     <p v-show="closeTest">
-                        系统检测到您尚未「交卷」,如您选择「确定」,
-                        <br />则目前作答将不保存,下次需重新测验。
+                        {{$t("studentWeb.exam.testpop.exitQuizhintDe")}}
+                        <br /> {{$t("studentWeb.exam.testpop.exitQuizhintDes")}}
                     </p>
-                    <button class="messageCardBtn" @click="closeWarmMessage()">取消</button>
-                    <button class="messageCardBtn" @click="quitTest()">确定</button>
+                    <button class="messageCardBtn" @click="closeWarmMessage()">{{$t("studentWeb.exam.testpop.cancel")}}</button>
+                    <button class="messageCardBtn" @click="quitTest()">{{$t("studentWeb.exam.testpop.ok")}}</button>
                 </div>
                 <!---每題都完成到最後一題交卷之提示框---->
                 <div class="messageCardContent2" v-if="showMessageNum == 2">
-                    <h3>交卷提示</h3>
+                    <h3>{{$t("studentWeb.exam.testpop.submitQuizhint")}}</h3>
                     <svg-icon icon-class="finshedTest" class="handOnImg" />
-                    <p>系统检测当前您已全数作答完成,确定交卷吗?</p>
-                    <button class="messageCardBtn" @click="closeWarmMessage()">否,需再检查</button>
-                    <button class="messageCardBtn" @click="closetest()">确定交卷</button>
+                    <p>{{$t("studentWeb.exam.testpop.submitQuizhintDes1")}}</p>
+                    <button class="messageCardBtn" @click="closeWarmMessage()">{{$t("studentWeb.exam.testpop.check")}}</button>
+                    <button class="messageCardBtn" @click="closetest()">{{$t("studentWeb.exam.testpop.okSubmit")}}</button>
                 </div>
                 <!---有題目沒完成就交卷之提示框---->
                 <div class="messageCardContent3" v-if="showMessageNum == 3">
-                    <h3>交卷提示</h3>
+                    <h3>{{$t("studentWeb.exam.testpop.submitQuizhint")}}</h3>
                     <svg-icon icon-class="unfinishedTest" class="handOnImg" />
                     <p>
-                        目前您有
-                        <span style="color:rgb(250, 100, 0);font-weight:900">{{ undo }}题 未作答 (详查答案卡)</span>,请先完成题目作答!
+                        {{$t("studentWeb.exam.testpop.conAnswer0")}}
+                        <span style="color:rgb(250, 100, 0);font-weight:900">{{ undo }}{{$t("studentWeb.exam.testpop.conAnswer1")}}</span>{{$t("studentWeb.exam.testpop.conAnswer2")}}
                     </p>
-                    <button class="messageCardBtn" @click="closeWarmMessage()">继续作答</button>
-                    <button class="messageCardBtn" @click="closetest()">确定交卷</button>
+                    <button class="messageCardBtn" @click="closeWarmMessage()">{{$t("studentWeb.exam.testpop.conAnswer")}}</button>
+                    <button class="messageCardBtn" @click="closetest()">{{$t("studentWeb.exam.testpop.okSubmit")}}</button>
                 </div>
             </div>
         </div>
@@ -48,13 +48,13 @@
             <span class="logoutIcon" @click="openWarmMessage(1)">
                 <svg-icon icon-class="logout" />
             </span>
-            <span class="testTitleText">评量:{{ $store.getters.getItemTitle.name }}</span>
+            <span class="testTitleText">{{$t("studentWeb.home.exam")}}:{{ $store.getters.getItemTitle.name }}</span>
             <div class="myProgressBar">
-                <span class="myTestProgresstitle">完成度</span>
+                <span class="myTestProgresstitle">{{$t("studentWeb.exam.testpop.completion")}}</span>
                 <Progress style="margin-top:15px" :percent="completeRate" />
             </div>
-            <button v-if="closeTest" class="submitBtn" @click="openWarmMessage(2)" :class="{ hintClick:hintHandon() }">交卷</button>
-            <button v-if="!closeTest" class="submitBtn" :class="{ hintClick:hintHandon()  }">已完成</button>
+            <button v-if="closeTest" class="submitBtn" @click="openWarmMessage(2)" :class="{ hintClick:hintHandon() }">{{$t("studentWeb.exam.testpop.submitted")}}</button>
+            <button v-if="!closeTest" class="submitBtn" :class="{ hintClick:hintHandon()  }">{{$t("studentWeb.exam.testpop.finish")}}</button>
         </div>
         <Row :gutter="30">
             <i-col class="questionArea"
@@ -87,7 +87,7 @@
                                     <span>{{getTestType(getQue(queNo).parentInfo.type)}}</span>
                                 </div>
                                 <div class="compose-box">
-                                    <span style="margin-left:10px;font-weight:800;font-size:15px">題目:</span>
+                                    <span style="margin-left:10px;font-weight:800;font-size:15px">{{$t("studentWeb.exam.testpop.queNo")}}</span>
                                     <br />
                                     <div class="compose-item">
                                         <!--<span w>{{ getQue(queNo).parent + 1}}.</span>-->
@@ -104,7 +104,7 @@
                         </div>
                     </div>
                     <div class="answers">
-                        <div class="questionNo">我的作答:</div>
+                        <div class="questionNo">{{$t("studentWeb.exam.testpop.myAns")}}</div>
                         <div class="answers-box">
                             <!--问答题-->
                             <div class="compose-content" v-if="getQue(queNo).type != 'judge' && getQue(queNo).type != 'single'  && getQue(queNo).type != 'multiple'">
@@ -155,10 +155,10 @@
                    :md="6"
                    :lg="4">
                 <div class="checkAnswer">
-                    <span style="margin-top:10px;font-weight:800">我的答题卡</span>
+                    <span style="margin-top:10px;font-weight:800">{{$t("studentWeb.exam.testpop.myAnswerSheet")}}</span>
                     <br />
                     <br />
-                    <span style="margin-top:10px;font-weight:800">题号:</span>
+                    <span style="margin-top:10px;font-weight:800">{{$t("studentWeb.exam.testpop.qNo")}}</span>
                     <div class="que-box">
                         <div v-for="(item,index) in examInfo" :class="[checkers[index].length > 0 ? 'has-ans':'ans-box',index == queNo ?'select-item':'']" @click="gototheQues(index +1)">
                             <span style="padding:5px 5px;cursor:pointer"> {{ item.parent == undefined ? index +1 : item.paperIndex }}</span>
@@ -168,12 +168,12 @@
                 <!--切換頁-->
                 <div class="pageCtl2">
                     <button @click="preQ()" v-show="queNo != 0">
-                        <Icon type="ios-arrow-back" />上一题
+                        <Icon type="ios-arrow-back" />{{$t("studentWeb.exam.testpop.previous")}}
                     </button>
                     <button @click="nextQ()"
                             v-show="queNo != (examInfo.length-1)"
                             :class="{ hintClick:queNo != (examInfo.length-1) && checkers[queNo] != ''}">
-                        下一题
+                        {{$t("studentWeb.exam.testpop.next")}}
                         <Icon type="ios-arrow-forward" />
                     </button>
                 </div>
@@ -401,7 +401,6 @@
             },
             closetest: function () {
                 this.WarmMessageisOpen = false
-                console.log('保存信息')
                 if (this.checkers.length) {
                     this.isLoading = true;
                     let codes = this.$store.getters.getItemTitle.code.split('-')

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

@@ -13,10 +13,10 @@
             </div>
             <EventBasicInfo :paper="paperData" />
             <Tabs :value="selectTab" v-if="paperData.length">
-                <TabPane label="评测内容" name="test">
+                <TabPane :label='$t("studentWeb.exam.examData")' name="test">
                     <div class="title-rect-group">
                         <div class="title-rect" />
-                        <h2 class="title-rect-name">试卷链接</h2>
+                        <h2 class="title-rect-name">{{$t("studentWeb.exam.examLink")}}</h2>
                     </div>
                     <!--多學科試卷-->
                     <div v-if="paperData.length > 0 ">
@@ -26,7 +26,7 @@
                                  :class="['paper-item',item.paperId == chooseData.paperId ? 'paper-choose' : '']"
                                  @click="opentestWithSubject(item)">
                                 <svg-icon icon-class="test" class="title-icon" />
-                                <span style="margin-top:5px">{{ item.subject.name }}{{$store.getters.getItemTitle.scope == 'school' ? '科试卷':''}}</span>
+                                <span style="margin-top:5px">{{ item.subject.name }}{{$store.getters.getItemTitle.scope == 'school' ? $t('studentWeb.exam.isSubject'):''}}</span>
                                 <div :class="{ unfinished: item.stuAns.length == 0 ,finished:item.stuAns.length != 0 }">
                                     <Icon style="margin-top:-10px;margin-left:-8px;" type="ios-checkmark" size="36" />
                                 </div>
@@ -36,19 +36,18 @@
                     <div class="title-rect-group">
                         <div v-if="chooseData.subject !== undefined">
                             <div class="title-rect" />
-                            <h2 class="title-rect-name">当前科目:{{chooseData.subject.name}}</h2>
-                            <!--<span v-show="isExamDown" @click="showTest" style="margin-left: 25px;color: #03966a;cursor:pointer">--><!--试卷详情--><!--</span>-->
+                            <h2 class="title-rect-name">{{$t("studentWeb.exam.subjectNow")}}:{{chooseData.subject.name}}</h2>
                             <LessonTestReport :paperInfo="selectData" :examInfo="chooseData" />
                         </div>
                     </div>
                 </TabPane>
-                <TabPane label="成绩报告" v-if="isTestOver" name="analyse">
+                <TabPane :label="$t('studentWeb.exam.gradeReport')" v-if="isTestOver" name="analyse">
                     <div class="title-rect-group">
                         <div class="title-rect" />
-                        <h2 class="title-rect-name">评测分析</h2>
+                        <h2 class="title-rect-name">{{$t("studentWeb.exam.gradeAnalyse")}}</h2>
                     </div>
-                    <div>
-                        <StudentScore :stuData="stuData"></StudentScore>
+                    <div class="student-score">
+                        <StudentScore :examData="paperData" :stuData="stuData"></StudentScore>
                     </div>
                 </TabPane>
             </Tabs>
@@ -251,4 +250,7 @@
 
 <style scoped>
     @import "~@/assets/student-web/component_styles/paper-view.css";
+    .student-score ::-webkit-scrollbar {
+        width: 0px;
+    } 
 </style>

+ 16 - 5
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/composePaper.vue

@@ -2,10 +2,9 @@
     <div class="content">
         <div id="textArea"> </div>
         <Modal v-model="markStatus" fullscreen title="作答" footer-hide>
-
-            <BaseMyCanvas v-if="markStatus" :bgImg="markBg" @onCloseModal="closeModal" isStudent="markStatus" @onSaveCanvas="saveMark"></BaseMyCanvas>
+            <BaseMyCanvas v-if="markStatus" :bgImg="markBg" @onCloseModal="closeModal" :isStudent="markStatus" @onSaveCanvas="saveMark"></BaseMyCanvas>
         </Modal>
-        <iframe style=" height: 0.1px; border: none;" id="answerIframe" :srcdoc="itemInfo.question"></iframe>
+        <iframe class="frame"id="answerIframe" :srcdoc="itemInfo.question"></iframe>
 
     </div>
 </template>
@@ -106,11 +105,14 @@
                 } 
             },
             markStuAnswer() {
-                let answerIframe = document.getElementById('answerIframe')
-                let markBody = answerIframe.contentWindow.document.body
+                let answerIframe = ''
+                answerIframe = document.getElementById('answerIframe')
+                console.log(answerIframe)
                 answerIframe.contentWindow.document.body.style.width = 'fit-content'
                 answerIframe.contentWindow.document.body.style.minWidth = '600px'
                 answerIframe.contentWindow.document.body.style.backgroundColor = '#f5f5f5'
+                let iframe = document.getElementById('answerIframe').contentWindow.document.getElementsByTagName('p')
+                iframe[1].style.lineHeight = '50px'
                 html2canvas(answerIframe.contentWindow.document.body).then(canvas => {
                     this.markStatus = true
                     this.markBg = canvas.toDataURL("image/png");
@@ -148,4 +150,13 @@
         width: 100%;
         height: 100%;
     }
+    .frame {
+        /*height: 100px;*/
+        border: none;
+        position:fixed;
+        height:0.1px;
+        width: 50%;
+        /*margin-left:10px;*/
+        /*line-height: 50px;*/
+    }
 </style>

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

@@ -11,7 +11,7 @@
                                   :class="{ openSearch: openSearch }" />
                     </div>
                     <div class="search-wrapper" :class="{ openSearch: openSearch }">
-                        <Input type="text" v-model="search" placeholder="搜尋" clearable />
+                        <Input type="text" v-model="search" :placeholder="$t('studentWeb.public.search')" clearable />
                     </div>
                 </div>
                 <!---搜尋--->
@@ -23,23 +23,23 @@
                             <Icon type="ios-arrow-down"></Icon>
                         </a>
                         <DropdownMenu slot="list">
-                            <div @click="sentEventStatus('所有活动状态')">
-                                <DropdownItem>{{ $t("studentWeb.allStatus") }}</DropdownItem>
+                            <div @click="sentEventStatus('all')">
+                                <DropdownItem>{{ $t("studentWeb.event.allStatus") }}</DropdownItem>
                             </div>
-                            <div @click="sentEventStatus('未完成')">
-                                <DropdownItem>{{ $t("studentWeb.unFinished") }}</DropdownItem>
+                            <div @click="sentEventStatus('unFinsish')">
+                                <DropdownItem>{{ $t("studentWeb.event.unFinished") }}</DropdownItem>
                             </div>
-                            <div @click="sentEventStatus('已完成')">
-                                <DropdownItem>{{ $t("studentWeb.Fineshed") }}</DropdownItem>
+                            <div @click="sentEventStatus('finish')">
+                                <DropdownItem>{{ $t("studentWeb.event.Fineshed") }}</DropdownItem>
                             </div>
-                            <div @click="sentEventStatus('已逾时')">
-                                <DropdownItem>{{ $t("studentWeb.Timeout") }}</DropdownItem>
+                            <div @click="sentEventStatus('overTime')">
+                                <DropdownItem>{{ $t("studentWeb.event.Timeout") }}</DropdownItem>
                             </div>
-                            <div @click="sentEventStatus('评测补考')">
-                                <DropdownItem divided>{{ $t("studentWeb.makeupExam") }}</DropdownItem>
+                            <div @click="sentEventStatus('reExam')">
+                                <DropdownItem divided>{{ $t("studentWeb.event.makeupExam") }}</DropdownItem>
                             </div>
-                            <div @click="sentEventStatus('作业补交')">
-                                <DropdownItem>{{ $t("studentWeb.makeupHW") }}</DropdownItem>
+                            <div @click="sentEventStatus('reMake')">
+                                <DropdownItem>{{ $t("studentWeb.event.makeupHw") }}</DropdownItem>
                             </div>
                         </DropdownMenu>
                     </Dropdown>
@@ -94,10 +94,9 @@
                                       icon-class="quesnaire" />
                         </li>
                         <li class="list-item-info"
-                            :class="{'list-item-infonofeedback': isNoFeedback(item) && finishedcondition(item) == false}"
                             v-if="item.eventType == 'exam'">
                             <p class="list-item-title">
-                                <span class="list-item-typeMark">{{item.scope == 'school' ? '校级评测' : '个人评测'}}</span>
+                                <span class="list-item-typeMark">{{item.scope == 'school' ? $t('studentWeb.public.schoolExam'):$t('studentWeb.public.privateExam')}}</span>
                                 <span class="list-item-typeMark"
                                       v-if="getCurrentLang() == 'en'">{{ transTypetoEn(item.eventType) }}</span>
                                 <span>{{ item.name }}</span>
@@ -108,10 +107,10 @@
                         </li>
                             <!--<div>已交卷</div>-->
                         <li class="list-item-unDone" v-show="item.progress == 'going'">
-                            <div class="isAllowRetry">进行中</div>
+                            <div class="isAllowRetry">{{$t("studentWeb.public.going")}}</div>
                         </li>
                         <li class="list-item-unDone" v-show="item.progress == 'finish'">
-                            <div class="isOvertime">已结束</div>
+                            <div class="isOvertime">{{$t("studentWeb.public.finish")}}</div>
                         </li>
                     </ul>
                 </div>
@@ -125,8 +124,6 @@
 
 <script>
     import { Random } from "mockjs";
-    import mockdata from "@/api/newData";
-    import mockdataEn from "@/api/newDataEn";
     import PreviewProgressPie from "../EventView/PreviewProgressPie";
 
 
@@ -177,7 +174,7 @@
                 search: "",
                 alreadyScrolltimes: 0,
                 defaultFirstItem: "",
-                selectedEventStatusNow: "所有活动状态",
+                selectedEventStatusNow: this.$t('studentWeb.event.allStatus'),
                 hideIconbtn: false,
                 isListNoItem: false, //清單為空
                 eventList: []
@@ -248,14 +245,6 @@
                 var D = date.getDate() + ' '
                 return Y + M + D;
             },
-            timeoutCondition(item) {
-                return (
-                    (item.endTime <= "2020.02.10" && item.allowRetryNow == false && item.eventType != "問卷") ||
-                    (item.endTime <= "2020.02.10" && item.eventType == "投票") ||
-                    (item.endTime <= "2020.02.10" && item.eventType == "課前預習")
-
-                );
-            },
             retryCondition(item) {
                 return (
                     item.endTime <= "2020.02.10" &&
@@ -263,40 +252,14 @@
                     item.isDone == false
                 );
             },
-            isNoFeedback(item) {
-                return (
-
-                    !(item.eventType == "課前預習" && item.endTime > "2020.02.10") &&
-                    !(
-                        item.eventType == "評量" &&
-                        item.eventSubject == "綜合學科" &&
-                        item.endTime > "2020.02.10"
-                    ) &&
-                    item.isDone == false &&
-                    item.endTime > "2020.02.10"
-                );
-            },
             getCurrentLang() {
                 return localStorage.getItem("lang");
             },
-            createMockdata: function () {
-                if (localStorage.getItem("lang") == "en") {
-                    this.mockdata = mockdataEn.eventList;
-                } else this.mockdata = mockdata.eventList
-            },
-            transStatustoEn(status) {
-                if (status == "所有活動狀態") return "All Status";
-                else if (status == "未完成") return "Unfinished";
-                else if (status == "已完成") return "Fineshed";
-                else if (status == "已逾時") return "Timeout";
-                else if (status == "評量補考") return "Make up Exam";
-                else if (status == "作業補交") return "Make up Homework";
-            },
             transTypetoEn(type) {
-                if (type == "投票") return "Vote";
-                else if (type == "評量") return "Exam";
-                else if (type == "作業") return "Homework";
-                else if (type == "課前預習") return "Preview";
+                if (type == "vote") return "Vote";
+                else if (type == "exam") return "Exam";
+                else if (type == "homework") return "Homework";
+                else if (type == "preview") return "Preview";
             },
             //取得目前滑鼠座標
             getCursorPosition() {
@@ -347,7 +310,7 @@
                 return Random.integer(70, 96);
             },
             sentEventStatus(status) {
-                if (status == "作業補交" || status == "評量補考") {
+                if (status == "reMake" || status == "reExam") {
                     this.eventTypeCheckers = [];
                 }
                 this.selectedEventStatusNow = status;
@@ -401,31 +364,31 @@
                 } else this.isListNoItem = true; //清單空值樣式配置
             },
             dropDownShowCondition(status, item) {
-                if (status == "作業補交") {
+                if (status == "reMake") {
                     this.hideIconbtn = true;
 
                     return (
                         item.endTime <= "2020.02.10" &&
-                        item.eventType == "作業" &&
+                        item.eventType == "homework" &&
                         item.allowRetryNow == true &&
                         item.isDone == false
                     );
-                } else if (status == "評量補考") {
+                } else if (status == "reExam") {
                     this.hideIconbtn = true;
 
                     return (
                         item.endTime <= "2020.02.10" &&
-                        item.eventType == "評量" &&
+                        item.eventType == "exam" &&
                         item.allowRetryNow == true &&
                         item.isDone == false
                     );
-                } else if (status == "未完成") {
+                } else if (status == "unFinish") {
                     this.hideIconbtn = false;
                     return item.isDone == false;
-                } else if (status == "已完成") {
+                } else if (status == "finish") {
                     this.hideIconbtn = false;
                     return item.isDone == true;
-                } else if (status == "已逾時") {
+                } else if (status == "overTime") {
                     this.hideIconbtn = false;
                     return (
                         (item.isDone == false &&
@@ -433,10 +396,10 @@
                             item.allowRetryNow == false) ||
                         (item.isDone == false &&
                             item.endTime <= "2020.02.10" &&
-                            item.eventType == "投票") ||
+                            item.eventType == "vote") ||
                         (item.isDone == false &&
                             item.endTime <= "2020.02.10" &&
-                            item.eventType == "課前預習")
+                            item.eventType == "preview")
                     );
                 } else {
                     this.hideIconbtn = false;
@@ -450,62 +413,8 @@
             showSearch() {
                 this.openSearch = !this.openSearch;
             },
-            showSelected: function (item) {
-
-                if (this.eventTypeCheckers == "") {
-                    if (this.search) {
-                        if ("評量".includes(this.search)) {
-                            this.isListNoItem = false;
-                            return item.eventType == "評量";
-                        } else if ("投票".includes(this.search)) {
-                            this.isListNoItem = false;
-                            return item.eventType == "投票";
-                        } else if ("作業".includes(this.search)) {
-                            this.isListNoItem = false;
-                            return item.eventType == "作業";
-                        } else if ("課前預習".includes(this.search)) {
-                            this.isListNoItem = false;
-                            return item.eventType == "課前預習";
-                        } else if ("問卷".includes(this.search)) {
-                            this.isListNoItem = false;
-                            return item.eventType == "問卷";
-                        } else return item.eventName.includes(this.search);
-                    } else {
-                        this.isListNoItem = false;
-                        return true;
-                    }
-                }
-                if (this.eventTypeCheckers.includes(item.eventType)) {
-                    if (this.search) {
-                        if ("評量".includes(this.search)) {
-                            this.isListNoItem = false;
-                            return item.eventType == "評量";
-                        } else if ("投票".includes(this.search)) {
-                            this.isListNoItem = false;
-                            return item.eventType == "投票";
-                        } else if ("作業".includes(this.search)) {
-                            this.isListNoItem = false;
-                            return item.eventType == "作業";
-                        } else if ("課前預習".includes(this.search)) {
-                            this.isListNoItem = false;
-                            return item.eventType == "課前預習";
-                        } else if ("問卷".includes(this.search)) {
-                            this.isListNoItem = false;
-                            return item.eventType == "問卷";
-                        } else {
-                            this.isListNoItem = false;
-                            return item.eventName.includes(this.search);
-                        }
-                    } else {
-                        this.isListNoItem = false;
-                        return true;
-                    }
-                } else return false;
-            },
-            sentEvenType: function (eventype) {
-
+            sentEvenType(eventype) {
                 this.$store.commit("ChangeFilterType", eventype);
-
                 if (this.$store.getters.getFilterType == "all") {
                     let filterListFinished = [],
                         filterListUnFinished = [];
@@ -570,9 +479,8 @@
             scrollListfromInfoPop() {
                 if (this.$store.getters.getisFromInfoPoptoScroll == true) {
                     //當從通知操作進行捲動時,將篩選條件清空
-                    this.selectedEventStatusNow = "所有活動狀態";
+                    this.selectedEventStatusNow = this.$t('studentWeb.event.allStatus');
                     this.eventTypeCheckers = [];
-
                     let targetItem = document.getElementById(
                         `event${this.$store.getters.getItemTitle.eventID}`
                     );
@@ -642,7 +550,6 @@
                 } else return false;
             },
             finishedItemtime(item) {
-                //this.$store.getters.getFinishedItemTime
                 if (this.$store.getters.getFinishedItem.includes(item.eventID) == true) {
                     let timeIndex = this.$store.getters.getFinishedItem.indexOf(
                         item.eventID

+ 0 - 2
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventOverView/EventFinishedNumChart.vue

@@ -1,8 +1,6 @@
 <template>
   <div class="event-finished-num-chart">
-    
       <LineChart :option="option" />
-   
   </div>
 </template>
 

+ 0 - 19
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventOverView/EventLatest.vue

@@ -7,9 +7,7 @@
     </h2>
     <div class="new-event-item-list ">
       <Row :gutter="20">
-      
         <i-col
-          
           :xs="24"
           :sm="24"
           :md="12"
@@ -18,7 +16,6 @@
           :key="index"
           v-show=" eventPageType.includes(item.eventType) == true && item.isDone == false && index < 20 "
           ><!--item.isOverEndTime == false -->
-          
           <ul
             class="new-event-item list-item"
             @click="sentSelectedEventTitle(item)"
@@ -47,7 +44,6 @@
                 {{ item.startTime }} ~ {{ item.endTime }}
               </p>
             </li>
-            
           </ul>
         </i-col>
       </Row>
@@ -57,15 +53,9 @@
 </template>
 
 <script>
-//import EventTypeNotFinishedChart from "../EventOverView/EventTypeNotFinishedChart";
-//import EventFinishedNumChart from "../EventOverView/EventFinishedNumChart";
 import mockdata from "@/api/newData";
 export default {
   name: "EventLatest",
-  components: {
-    //EventFinishedNumChart,
-    //EventTypeNotFinishedChart,
-  },
   data() {
     return {
       //倒入資料
@@ -113,13 +103,4 @@ export default {
 
 <style scoped>
 @import "~@/assets/student-web/component_styles/event-latest.css";
-/* 活動進度條圖表Icon
-@keyframes born {
-  from {
-    width: 0;
-  }
-  to {
-    width: MyEventData + "%";
-  }
-}*/
 </style>

+ 2 - 15
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventView.vue

@@ -10,8 +10,6 @@
     import CommentList from "./CommentList.vue";
     import EventList from "./EventList";
     import EventContentArea from "./EventContentArea.vue";
-    import mockdata from "@/api/newData";
-    import mockdataEn from "@/api/newDataEn";
     export default {
         name: "EventView",
         components: {
@@ -24,17 +22,10 @@
                 MyNo: "4", //接收NavBar 選定的那一頁icon標示
                 MyName: "",
                 mockdata: "",
-                eventPageType: ["課前預習", "評量", "作業", "投票", "問卷"] //本頁出現的類型
+                eventPageType: ["preview", "exam", "homework", "vote", "quesnaire"] //本頁出現的類型
             };
         },
         created() {
-            //發送本頁target 跟名字給App.Vue 的navBar
-            if (localStorage.getItem("lang") == "") {
-                this.mockdata = mockdata.eventList;
-            }
-            if (localStorage.getItem("lang") == "tw") {
-                this.mockdata = mockdata.eventList;
-            } else this.mockdata = mockdataEn.eventList;
             this.MyName = this.$t("studentWeb.eventView-title");
             this.$emit("onNavNo", this.MyNo);
             this.$emit("onNavName", this.MyName);
@@ -46,8 +37,6 @@
                 //當從通知操作進行捲動時,將篩選條件清空
                 this.selectedEventStatusNow = "所有活動狀態";
                 this.eventTypeCheckers = [];
-                console.log("收到從下一個按鈕切換項目");
-
                 let targetItem = document.getElementById(
                     `event${this.$store.getters.getItemTitle.eventID}`
                 );
@@ -71,11 +60,9 @@
                 let nextItems = [];
                 for (let i = 0; i <= this.mockdata.length; i++) {
                     if (this.$store.getters.getItemTitle == this.mockdata[i]) {
-                        console.log("目前:" + i, this.mockdata[i].eventName);
                         let j = i + 1;
                         if (
-                            j < this.mockdata.length &&
-                            this.eventPageType.includes(this.mockdata[j].eventType)
+                            j < this.mockdata.length && this.eventPageType.includes(this.mockdata[j].eventType)
                         ) {
                             nextItems.push(this.mockdata[j]);
                         } else {

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

@@ -22,13 +22,13 @@ export default {
   methods: {
     finishedValue() {
       if (this.$store.getters.getItemTitle.eventID == this.itemID) {
-        if (this.$store.getters.getItemTitle.eventType == "課前預習") {
+        if (this.$store.getters.getItemTitle.eventType == "preview") {
           this.option.series[0].data[0].value =
             this.$store.getters.getCurrentPassPhaseTest * 33;
           this.option.series[0].data[1].value =
             100 - this.$store.getters.getCurrentPassPhaseTest * 33;
         }
-        else if(this.$store.getters.getItemTitle.eventType == "評量"){
+        else if(this.$store.getters.getItemTitle.eventType == "exam"){
           console.log(this.$store.getters.getCurrentfinishedSubject.length*33)
            this.option.series[0].data[0].value = this.$store.getters.getCurrentfinishedSubject.length*33;
             this.option.series[0].data[1].value =
@@ -50,7 +50,7 @@ export default {
         },
         series: [
           {
-            name: "访问来源",
+            //name: "访问来源",
             type: "pie",
             radius: ["50%", "70%"],
             avoidLabelOverlap: false,

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

@@ -1,11 +1,7 @@
 <template>
   <div class="courselist-view">
-   
     <CourseList :class="{ 'hide-sidebar': this.$store.getters.getSidebarisOpen == false}" />
     <CourseContent :class="{'course-content-span': this.$store.getters.getSidebarisOpen == false}"/>
-
-    
-   
   </div>
 </template>
 

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

@@ -34,28 +34,23 @@
                                     v-show="eventPageType.includes(item.eventType) == true &&item.isDone == false && index < 8 ">
                                     <ul>
                                         <li class="list-item-icon">
-                                            <svg-icon v-if="item.eventType == '作業'"
+                                            <svg-icon v-if="item.eventType == 'homework'"
                                                       icon-class="doc" />
-                                            <svg-icon v-if="item.eventType == '課前預習'"
+                                            <svg-icon v-if="item.eventType == 'preview'"
                                                       icon-class="selflearninginTime" />
-                                            <svg-icon v-if="item.eventType == '評量'"
+                                            <svg-icon v-if="item.eventType == 'exam'"
                                                       icon-class="test"
                                                       class="reset-testIcon" />
-                                            <svg-icon v-if="item.eventType == '投票'"
+                                            <svg-icon v-if="item.eventType == 'vote'"
                                                       icon-class="vote" />
-                                            <svg-icon v-if="item.eventType == '問卷'"
+                                            <svg-icon v-if="item.eventType == 'quesnaire'"
                                                       icon-class="quesnaire" />
                                         </li>
                                         <li class="list-item-info">
                                             <p class="list-item-title"
-                                               :class="{
-                            'list-item-titleEn': getCurrentLang() == 'en',
-                          }">
-                                                <span class="list-item-typeMark"
-                                                      v-if="getCurrentLang() == 'tw'">{{ item.eventType }}</span>
-                                                <span class="list-item-typeMark"
-                                                      v-if="getCurrentLang() == 'en'">{{ transTypetoEn(item.eventType) }}</span>
-
+                                               :class="{ 'list-item-titleEn': getCurrentLang() == 'en', }"
+                                               >
+                                                <span class="list-item-typeMark">{{ item.eventType }}</span>
                                                 <span>{{ item.eventName }}</span>
                                             </p>
                                             <p class="list-item-time">
@@ -115,7 +110,6 @@
                     </div>
                 </Card>
                 <!--<router-link to="/studentWeb/eventView">
-
                 </router-link>-->
                 <br />
                 <Card class="bar-card" @click.native="noData">
@@ -135,7 +129,6 @@
                     </div>
                 </Card>
                 <!--<router-link to="/studentWeb/studyView">
-
                 <!--</router-link>-->
             </i-col>
         </Row>
@@ -204,7 +197,7 @@
 
         data() {
             return {
-                eventPageType: ["課前預習", "評量", "作業", "投票", "問卷"], //本頁出現的類型
+                eventPageType: ["preview", "exam", "homework", "vote", "quesnaire"], //本頁出現的類型
                 MyNo: "1", //接收NavBar 選定的那一頁icon標示
                 MyName: "",
                 mockdata: [
@@ -270,19 +263,6 @@
             setSpanCharts() {
                 this.spanCharts = !this.spanCharts;
             },
-            //createMockdata: function () {
-            //  if (localStorage.getItem("lang") == "en") {
-            //    this.mockdata = mockdataEn.eventList.slice(0, 39);
-            //    } else this.mockdata = mockdata.eventList.slice(0, 39);
-            //    console.log('mock')
-            //    console.log(JSON.stringify(this.mockdata))
-            //},
-            transTypetoEn(type) {
-                if (type == "投票") return "Vote";
-                else if (type == "評量") return "Exam";
-                else if (type == "作業") return "Homework";
-                else if (type == "課前預習") return "Preview";
-            },
         },
 
         created() {

+ 14 - 37
TEAMModelOS/ClientApp/src/components/student-web/HomeView/MissionListCard.vue

@@ -15,29 +15,26 @@
                     @click="sentSelectedEventTitle(item)"
                     v-for="(item, index) in testData" :key="index">
                     <ul>
-                        <!--v-show=" eventPageType.includes(item.eventType) == true && item.isDone == false && item.endTime > '2020.02.10'"-->
                         <li class="list-item-icon">
-                            <svg-icon v-if="item.eventType == '作業'" icon-class="doc" />
-                            <svg-icon v-if="item.eventType == '課前預習'"
+                            <svg-icon v-if="item.eventType == 'homework'" icon-class="doc" />
+                            <svg-icon v-if="item.eventType == 'preview'"
                                       icon-class="selflearninginTime" />
                             <svg-icon v-if="  item.eventType == 'exam'"
                                       icon-class="test"
                                       class="reset-testIcon" />
-                            <!--<svg-icon v-if=" item.eventType == 'exam' && item.eventSubject == '綜合學科' "
-                                      icon-class="multiTest" />-->
-                            <svg-icon v-if="item.eventType == '投票'" icon-class="vote" />
-                            <svg-icon v-if="item.eventType == '問卷'" icon-class="quesnaire" />
+                            <svg-icon v-if="item.eventType == 'vote'" icon-class="vote" />
+                            <svg-icon v-if="item.eventType == 'quesnaire'" icon-class="quesnaire" />
                         </li>
                         <li class="list-item-info" :class="{ 'list-item-infonoPie': isNoPie(item) }">
                             <p class="list-item-title" :class="{ 'list-item-titleEn': getCurrentLang() == 'en' }">
-                                <span class="list-item-typeMark">{{item.scope == 'school'? '校级评测':'个人评测'}}</span>
+                                <span class="list-item-typeMark">{{item.scope == 'school'? $t('studentWeb.public.schoolExam'):$t('studentWeb.public.privateExam')}}</span>
                                 <span>{{ item.name }}</span>
                                 <div style="float:right;margin-top:-20px">
                                     <div class="list-item-unDone" v-show="item.progress == 'going'">
-                                        <span class="isAllowRetry">进行中</span>
+                                        <span class="isAllowRetry">{{$t("studentWeb.public.going")}}</span>
                                     </div>
                                     <div class="list-item-unDone" v-show="item.progress == 'finish'">
-                                        <span class="isOvertime">已结束</span>
+                                        <span class="isOvertime">{{$t("studentWeb.public.finish")}}</span>
                                     </div>
                                 </div>
                             </p>
@@ -45,11 +42,11 @@
                                 {{ dateFormat(item.startTime) }} ~ {{ dateFormat(item.endTime) }}
                             </p>
                         </li>
-                <li class="list-item-unDone">
-                    <PreviewProgressPie v-if=" item.eventType == '課前預習' && item.endTime > '2020.02.10' "></PreviewProgressPie>
+                <!--<li class="list-item-unDone">
+                    <PreviewProgressPie v-if=" item.eventType == 'preview'"></PreviewProgressPie>
                     <PreviewProgressPie :itemID="item.eventID"
-                                        v-if=" item.eventType == '評量' && item.eventSubject == '綜合學科' && item.endTime > '2020.02.10' "></PreviewProgressPie>
-                </li>
+                                        v-if="item.eventType == 'exam'"></PreviewProgressPie>
+                </li>-->
                 </ul>
                 </div>
             </Scroll>
@@ -59,7 +56,6 @@
 </template>
 
 <script>
-    //import { Random } from "mockjs";
     import PreviewProgressPie from "../EventView/PreviewProgressPie";
     export default {
         name: "MissionListCard",
@@ -73,7 +69,7 @@
                 mockdata: "",
                 testData: [],
                 templistArray: [],
-                eventPageType: ["課前預習", "評量", "作業", "投票", "問卷"] //本頁出現的類型
+                eventPageType: ["preview", "exam", "homework", "vote", "questionnare"] //本頁出現的類型
             };
         },
         created() {
@@ -131,9 +127,9 @@
             },
             isNoPie(item) {
                 return (
-                    !(item.eventType == "課前預習" && item.endTime > "2020.02.10") &&
+                    !(item.eventType == "preview" && item.endTime > "2020.02.10") &&
                     !(
-                        item.eventType == "評量" &&
+                        item.eventType == "exam" &&
                         item.eventSubject == "綜合學科" &&
                         item.endTime > "2020.02.10"
                     )
@@ -142,23 +138,6 @@
             getCurrentLang() {
                 return localStorage.getItem("lang");
             },
-            createMockdataOriginal: function () {
-                if (localStorage.getItem("lang") == "en") {
-                    this.mockdataOriginal = mockdataEn.eventList;
-                } else this.mockdataOriginal = mockdata.eventList;
-            },
-            createMockdata: function () {
-                if (localStorage.getItem("lang") == "en") {
-                    this.mockdata = mockdataEn.eventList.slice(0, 39);
-                } else this.mockdata = mockdata.eventList.slice(0, 39);
-            },
-
-            transTypetoEn(type) {
-                if (type == "投票") return "Vote";
-                else if (type == "評量") return "Exam";
-                else if (type == "作業") return "Homework";
-                else if (type == "課前預習") return "Preview";
-            },
             handleReachBottom() {
                 return new Promise((resolve) => {
                     setTimeout(() => {
@@ -168,7 +147,6 @@
                             i++
                         ) {
                             //小於原始資料總長度在加入空陣列
-
                             this.mockdata.push(this.mockdataOriginal[this.mockdata.length + 1]);
                         }
                         resolve();
@@ -200,7 +178,6 @@
                 if (document.getElementById(`event${item.eventID}`).offsetTop > 600) {
                     let scrollvalue = document.getElementById(`event${item.eventID}`)
                         .offsetTop;
-                    console.log("選項在清單可視範圍外!!");
                     this.$store.commit("scrollList", scrollvalue);
                 }
             },

+ 15 - 0
TEAMModelOS/ClientApp/src/css/site.css

@@ -177,4 +177,19 @@ html[white]{ /*白色主題*/
 		left: 0;
 		right: 0;
 		bottom: 0;
+	}
+	
+	/*横向垂直水平居中*/
+	.flex-row-center {
+	    display: flex;
+	    flex-direction: row;
+	    justify-content: center;
+	    align-items: center;
+	}
+	/*向垂直水平居中*/
+	.flex-col-center {
+	    display: flex;
+	    flex-direction: column;
+	    justify-content: center;
+	    align-items: center;
 	}

+ 2 - 4
TEAMModelOS/ClientApp/src/locale/index.js

@@ -18,12 +18,10 @@ ElementLocale.i18n((key, value) => i18n.t(key, value))
 Vue.use(VueI18n)
 
 // 自动根据浏览器系统语言设置语言
-const navLang = navigator.language.toLowerCase()
-console.log('lang', navLang)
+const curLang  = localStorage.getItem('cloudSetting') ? JSON.parse(localStorage.getItem('cloudSetting')).curLang : null
+const navLang = curLang || navigator.language.toLowerCase()
 const localLang = (navLang === 'zh' || navLang === 'zh-tw' || navLang === 'zh-cn' || navLang === 'zh-hk') ? navLang : false
 let lang = localLang || 'en-us'
-
-console.log(lang)
 localStorage.setItem('local', lang)
 Vue.config.lang = lang
 

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

@@ -0,0 +1,5 @@
+export default{
+    examType1:'期中考试',
+    examType2:'期末考试',
+    examType3:'模拟考试'
+}

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

@@ -17,8 +17,10 @@ import regist from './regist'
 import forgotPW from './forgotPW'
 import studentWeb from './studentWeb'
 import settings from './settings'
-import seviceDriveAuth from './seviceDriveAuth'
+import serviceDriveAuth from './serviceDriveAuth'
 import elui from './elui'
+import global from './global'
+import system from './system'
 export default {
   schoolBaseInfo,
   schoolMgmt,
@@ -39,9 +41,11 @@ export default {
   forgotPW,
   studentWeb,
   settings,
-  seviceDriveAuth,
+  serviceDriveAuth,
   test: 'test',
   elui,
+  global,
+  system,
   formConfigP: {
     input: 'Please Enter ',
     select: 'Please Sele',

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

@@ -0,0 +1,182 @@
+export default{
+    //MgtSchoolEva.vue
+    mgtScEv:{
+        listLabel:'评测列表',
+        period:'学段:',
+        create:'新建',
+        delete:'删除',
+        edit:'编辑',
+        createTime:'施测时间:',
+        pending:'待发布',
+        going:'进行中',
+        finish:'已结束',
+        endTime:'结束时间:',
+        stop:'立即结束',
+        evType:'测试类型:',
+        stuCount:'施测人数:',
+        nodata:'暂无评测',
+        tab1:'评测数据',
+        tab2:'评测试卷',
+        autoTips1:'此功能仅用于展示情景快速模拟学生作答数据,且学生作答为随机生成,仅供参考!',
+        autoTips2:'此功能仅用于展示情景快速模拟教师评分数据,且分数为随机生成,仅供参考!',
+        autoScore:'一键评分',
+        autoAnswer:'一键作答',
+        evSubject:'测试科目:',
+        returnTop:'返回顶部',
+        mockOk:'模拟成功',
+        mockErr:'模拟失败',
+        stopTitle:'结束评测',
+        stopContent:'结束后学生将不能继续作答,是否立即结束',
+        stopOk:'评测已结束!',
+        deleteTitle:'删除评测',
+        deleteContent:'是否确认删除',
+        deleteOk:'删除成功',
+        deleteErr:'删除失败',
+        noJoin:'此账号暂未加入任何学校!'
+    },
+
+    //创建评测校本/个人
+    createEv:{
+        createLabel:'创建评测',
+        publishEv:'发布评测',
+        return:'返回上级',
+        baseInfo:'基础信息',
+        evName:'评测名称',
+        evPeriod:'测试学段',
+        evMode:'评测模式',
+        evType:'评测类型',
+        examType:'考试类别',
+        courseType:'课程类别',
+        cusLabel1:'校本课程',
+        cusLabel2:'个人课程',
+        evTarget:'施测对象',
+        publishType:'发布方式',
+        startTime:'开始时间',
+        sTimeHolder:'请选择开始时间',
+        endTime:'结束时间',
+        eTimeHolder:'请选择结束时间',
+        addSubject:'添加学科',
+        noSubject:'暂无科目,请添加科目',
+        noSubject1:'* 请先选择测试学段',
+        papersLabel:'试卷库',
+        perviewLabel:'试卷预览',
+        importLabel:'导入说明',
+        answerPreview:'作答预览',
+        errTips1:'评测名称不能为空!',
+        errTips2:'测试类型不能为空!',
+        errTips3:'评量模式不能为空!',
+        errTips4:'请设置类别!',
+        errTips5:'请设置测试类型!',
+        errTips6:'请设置测试对象!',
+        errTips7:'请设置发布方式!',
+        errTips8:'请设置发布时间!',
+        errTips9:'请设置结束时间!',
+        errTips10:'请设置测试学段!',
+        stPaperTitle:'挑选试卷',
+        stPaperContent:'是否确认挑选',
+        inDev:'功能正在开发中,敬请期待!',
+        formWarning:'请先完善评测基础信息!',
+        paperWarning:'请挑选或导入试卷!',
+        paperWarning1:'还没有试卷,请挑选或导入试卷!',
+        pdWarning:'请添加测试科目!',
+        publishOk:'评测发布成功!',
+        togglePeriod:'切换学段',
+        togglePdTip1:'您已添加',
+        togglePdTip2:'的测试科目,如果现在切换学段会清空已选科目,确定切换学段吗?',
+        toggleOkText:'切换',
+        delPdTitle:'删除科目',
+        delPdContent:'是否确认删除',
+        delOk:'删除成功',
+        pdTips:'请先选择测试学段!',
+        defaultPaper:'(请先挑选或导入试卷)',
+    },
+    // ManualPaper.vue
+    manual:{
+        source:'来源:',
+        sourceP:'个人试卷库',
+        sourceS:'校本试卷库',
+        pdLabel:'学段:',
+        subjectLabel:'学科:',
+        gradeLabel:'年级:',
+        fitPd:'适用学段:',
+        fitSubject:'适用科目:',
+        quCount:'题量:',
+        useCount:'使用次数:',
+        stdPaper:'已选试卷',
+        stPaper:'选择试卷',
+        previewPaper:'预览试卷',
+        noPaper:'暂无对应的试卷',
+        noPaper1:'暂无试卷'
+    },
+    // PaperScore.vue、Scoring.vue
+    score:{
+        stuName:'学生姓名:',
+        score:'总分:',
+        scoreUnit:'分',
+        saveScore:'保存打分',
+        showAns:'显示答案',
+        hideAns:'隐藏答案',
+        showQu:'显示题干',
+        hideQu:'隐藏题干',
+        quIndex:'题号:',
+        quIndex1:'题号',
+        fullScore:'满分',
+        zeroScore:'零分',
+        zeroScore1:'0分',
+        stuAns:'【学 生 作 答】',
+        mark:'批注',
+        quAns:'【答ㅤ案】',
+        noAnswer:'未设置答案',
+        anaLabel:'【解ㅤ析】',
+        noAna:'暂无解析',
+        kdLabel:'【知识点】',
+        noKd:'暂未绑定知识点',
+        sQuLabel1:'【小题',
+        sQuLabel2:'】',
+        quIndexLabel:'【题号',
+        nextStu:'下一位学生>>>',
+        markOk:'批注成功!',
+        markErr:'批注失败!',
+        isFullTips:'已经是小题满分了',
+        isZeroTips:'已经是零分了',
+        saveScoreOk:'成绩保存成功!',
+        saveSocreErr:'成绩保存失败!',
+        zero:'零',
+        one:'一',
+        two:'二',
+        three:'三',
+        four:'四',
+        five:'五',
+        six:'六',
+        seven:'七',
+        eight:'八',
+        nine:'九',
+        ten:'十',
+        hundred:'百',
+        thousand:'千',
+        tenThd:'万',
+        hMillion:'亿',
+        noStuAns:'未作答',
+        noStuAns1:'暂未作答',
+        trueAns:'正确',
+        falseAns:'错误',
+        //Scoring.vue
+        subjectLabel:'学科:',
+        gradeLabel:'年级:',
+        classLabel:'班级:',
+        stuLabel:'学生:',
+        scoreView:'分数概览',
+        scoring:'试卷评分',
+        classNoStu:'班级暂无学生',
+        status1:'暂未作答',
+        status2:'前往评分',
+        status3:'查看分数',
+        column1:'姓名',
+        column2:'总分',
+        column3:'状态',
+        finishScore:'已完成所有学生作答的评分!',
+        unableScore:'学生尚未作答,无法评分',
+        stStuWarning:'请先选择学生!'
+    }
+
+}

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

@@ -86,5 +86,15 @@ export default {
   '3222NIYD': 'ezStation 2',
   'J223IZ6M': 'HiTeach STD',
   '3222C6D2': 'HiTeach TBL',
-  'J223IZAM': 'HiTeach PRO'
+  'J223IZAM': 'HiTeach PRO',
+  addStuBtn: '添加學生',
+  delStuBtn: '移除學生',
+  editSeat: '修改座號',
+  removeTile: '移除提醒',
+  removeContent: '是否確認移除',
+  removeOk: '移除成功',
+  removeErr: '移除失敗',
+  deLink: '解除关联',
+  link: '关联',
+  confirmDelink:'请问您确定要解除关联'
 }

+ 181 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/serviceDriveAuth.js

@@ -0,0 +1,181 @@
+export default {
+  //ServiceList.vue
+  AEGMCPLY: 'AClass One',
+  RYGVCPLY: 'AClass One',
+  IPALYEIY: 'Smart Teaching Service Space',
+  '6BOPC6MD': 'Teaching and learning big data management services',
+  ON6MBDOP: 'Smart School Big Data Management Service',
+  服務授權列表: 'Service authorization list',
+  智慧教室授權管理: 'Smart classroom authorization management',
+  未購買: 'not purchased',
+  已購買: 'purchased',
+  '服務啟用 / 到期日:': 'Service activation / expiration date:',
+  剩餘: 'Remaining',
+  天: 'days',
+  無週期授權數量: 'No periodic authorization quantity',
+  有週期授權數量: 'Periodic authorization quantity',
+  固定分配數: 'Fixed allocation',
+  動態分配數: 'Dynamic allocation number',
+  剩餘分配數: 'Remain allocation',
+  總使用率: 'Total usage',
+  詳細服務內容: 'Detailed service content',
+  管理AClassOne授權: 'Manage AClassOne authorization',
+
+  //HiteachAuthList.vue
+  確定解除授權: 'Confirm deauthorization',
+  當前您所選中的PC: 'The currently selected PC',
+  ',確定解除授權?': ', are you sure to deauthorize?',
+  '解除授權後,可在教室中的電腦再次進行綁定授權。': 'After the authorization is cancelled, the binding authorization can be performed again on the computer in the classroom.',
+  取消: 'Cancel',
+  確定: 'OK',
+  Hiteach序號數: 'Hiteach serial number',
+  大量: 'Multi',
+  單一: 'Single',
+  授權: 'Authorization',
+  可啟用裝置數: 'Number of devices that can be activated',
+  已啟用裝置數: 'Number of activated devices',
+  管理Hiteach教室: 'Manage Hiteach classroom',
+  暂无数据: 'No data',
+  序號到期日: 'Serial number expiration date: ',
+  無到期日: 'No expiration date',
+  已到期: 'Expired',
+  序號使用狀況: 'Serial number usage status: ',
+  未命名機台: 'Unnamed machine',
+  解除授權: 'Deauthorize',
+  顯示全部: 'Show all serial numbers',
+  '僅顯示HiTeach STD序號': 'Display HiTeach STD serial number only',
+  '僅顯示HiTeach PRO序號': 'Display HiTeach PRO serial number only',
+  '僅顯示HiTeach TBL序號': 'Display HiTeach TBL serial number only',
+  僅顯示已完成綁定的序號: 'Only display the serial number of the completed binding',
+  僅顯示已到期序號: 'Show only expired serial numbers',
+  已成功解除授權: 'Successfully deauthorized',
+
+  //SpaceStatus.vue
+  智慧教學服務空間狀態: 'Space status',
+  分配教學空間: 'Allocate teaching space',
+  空間總數: 'Total space',
+  已使用空間總數: 'Total used space',
+  空間使用狀況: 'Space usage status',
+  未使用空間數: 'Unused space',
+  未使用空間比率: 'Ratio',
+  可使用空間數: 'Usable spaces',
+  可使用空間比率: 'Ratio',
+  當前空間到期日: 'Expiration date: ',
+  '基本 1GB 永久授權': 'Basic 1GB perpetual license',
+  '到期後將變更為IES基本空間,超出基本空間值將被收回': 'After the expiration, it will be changed to the IES basic space.',
+  購買記錄: 'Purchase record',
+  醍摩豆智慧教學服務空間: 'TeamModel Space',
+  訂單日期: 'Order Date: ',
+  到期日: 'Expiry date:',
+  添購其他服務: 'Add other services',
+  '空間已到期,超過僅供檢視': 'Space has expired, more than is only for viewing',
+
+  //SpaceChart.vue
+  文件: 'File',
+  永久授權: 'Permanent authorization',
+  影片: 'Video',
+  圖片: 'Image',
+  題目與試卷: 'Questions and examinations',
+  其他: 'Others',
+  學生使用: 'Student use',
+  已分配至教師: 'Assigned to teacher',
+  未使用: 'Unused',
+  空間: '&nbsp;Space',
+  空間數: '&nbsp;Spaces',
+  空間比率: '&nbsp;Ratio',
+
+  //學生帳號頁面的授權管理控件 student-account / AclassOneAuth.vue
+  確定收回所有授權: 'Make sure to reclaim all authorizations',
+  '收回授權後使用數會直接設置為0,如欲給予授權可針對目標對象進行套用。': 'After the authorization is withdrawn, the number of uses will be directly set to 0. If you want to grant authorization, you can apply it to the target object.',
+  服務授權管理: 'Service authorization management',
+  AClassONE智慧學伴服務授權: 'AClassONE Authorization',
+  '賦予持有該服務授權的學生TEAM Modal ID使用AClassONE智慧學伴App的權限': 'Grant the TEAM Modal ID of the student who holds the service authorization to use the AClassONE Smart Learning Companion App',
+  總授權數: 'Total number of authorizations',
+  本次套用數: 'Number of applications this time',
+  已使用數: 'Used number',
+  授權總覽: 'Authorization overview',
+  授權管理: 'Authorization management',
+  已購授權總數: 'Total Purchased :',
+  note: 'The authorization of fixed allocation is set by the school uniformly. Users should set the authorization object in the authorization management page. The dynamic access authorization will be automatically recycled at 23:59:59 every day, and students can activate it again the next day.',
+  快速套用授權: 'Quickly apply authorization',
+  套用至所有當前勾選項目: 'Apply to all checked items',
+  套用: 'Apply',
+  套用至: 'Apply to',
+  套用至當前勾選目標第: 'Apply to the checked item',
+  項至第: 'to',
+  項: 'item',
+  所有項目: 'all items',
+  未关联班级: 'Unlinked class',
+  套用至全校所有項目: 'Apply to all items in the school',
+  共: 'total',
+  個: '',
+  '大於總授權數,無法使用': 'Greater than the total number of authorizations, can not be used',
+  添購其他授權: 'Add other licenses',
+  收回所有授權: 'Recover all authorizations',
+  保存所有變更: 'Save all changes',
+  選擇班級: 'class',
+
+  //下方method區塊
+  固定分配授權數: 'Fixed allocation',
+  今日動態取用數: 'Dynamic access number',
+  今日可用授權數: 'Available',
+  '請先選擇套用,再按保存': 'Please select apply first, then press save',
+  '保存成功,本次尚無新增授權數量': 'Save successfully, there is no new authorization number this time',
+  '保存成功,本次新增': 'Save successfully, add this time',
+  個固定分配: 'Fixed allocation',
+  '保存失敗,超過可用授權數!': 'Save failed, the number of available authorizations exceeded!',
+  全部收回成功: 'All recovered successfully',
+  請先勾選欲授權之學生: 'Please check the students who want to authorize',
+  '請設定有效的目標項 !': 'Please set a valid target item!',
+  '目前所選學制人數為 0 人!': 'The number of students currently selected for the school system is 0!',
+  '請先選學制!': 'Please choose the school system first!',
+  '目前所選學級人數為 0 人!': 'The number of students currently selected is 0!',
+  '請先選學級!': 'Please choose the grade first!',
+  '目前所選班級人數為 0 人!': 'The number of currently selected class is 0!',
+  '請先選班級!': 'Please choose a class first!',
+  '全校人數超過所購買授權數,無法使用': 'The number of people in the school exceeds the number of licenses purchased and cannot be used',
+  全部收回成功: 'All recovered successfully',
+
+  //老師帳號分配空間授權控件  teachermgmt/index.vue 空間欄位部分
+  空間分配: 'Space allocation',
+  確定收回所有空間: 'Confirm to reclaim all space',
+  '確定後全部每位教師都直接設置為0GB。': 'After confirming, all teachers are directly set to 0GB.',
+  保存提醒: 'Save reminder',
+  '当前空間数据尚未保存。如果關閉,修改的数据将不会保存!': 'The current spatial data has not been saved. If closed, the modified data will not be saved!',
+  回收空間: 'Reclaimed space',
+  保存變更: 'Save changes',
+  空間分配狀態: 'Space allocation status',
+  總空間量: 'Total space:',
+  單人固定容量分配: 'Single fixed capacity allocation',
+  目前可被分配總量: 'The total amount currently available for distribution',
+  至: ' to',
+  每人分配: 'Allocation per person',
+  當前勾選之教師帳號: 'Teacher account currently checked',
+  所有: 'all',
+  進階權限: ' Advanced permissions',
+  一般權限: ' General permissions',
+  之教師帳號: ' teacher account',
+  職稱為: 'Job title',
+  的教師帳號: 'teacher account',
+  所有教師帳號: 'All teacher accounts',
+
+  //下方method區塊
+  '請手動輸入數字!': 'Please enter the numbers manually!',
+  '輸入了開頭為0的數字,請重新輸入!': 'Enter a number that starts with 0, please re-enter!',
+  回收成功: 'Successful recovery',
+  更新成功: 'Successful update',
+  超出該校使用空間: 'Exceeding the space used by the school',
+  有不存在老師的ID: 'There is no teacher ID',
+  保存失敗: 'Save failed',
+  '您未進行任何個別變更或批次套用,無需保存': 'You have not made any individual changes or batch application, no need to save',
+  '超出剩餘空間量,套用失敗': 'Exceeding the amount of remaining space, application failed',
+  '套用完成,記得按保存': 'Apply complete, remember to press save',
+  '先輸入有效數字,再進行套用': 'Enter a valid number first, then apply it',
+  套用完成: 'Application complete',
+  '先輸入有效數字,並進行勾選,再套用': 'Enter a valid number first, then check it, then apply',
+
+  //store/spaceAuth.js
+  學校已使用空間:'School used space',
+  已分配給教師空間:'Allocated to teacher space',
+  剩餘空間:'Remaining space'
+}

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

@@ -1,8 +0,0 @@
-export default {
-    //授權管理服務清單
-    "AEGMCPLY":"AClass One 週期",
-    'RYGVCPLY':'AClass One 無週期',
-    'IPALYEIY':'智慧教學服務空間',
-    '6BOPC6MD':'教與學大數據管理服務',
-    'ON6MBDOP':'智慧學校大數據管理服務'
-    }

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

@@ -1,311 +1,360 @@
 export default {
-    "settingView-title": "Setting",
+    "home": {
+        "teacher": "teacher",
+        "student": "student",
+        "setting": "Personal Settings",
+        "logout": "Logout",
+        "joinClass": "Join Class",
+        "exam": "evaluation",
+    },
+    "public": {
+        "going": "In progress",
+        "finish": "Finished",
+        "schoolExam": "School Evaluation",
+        "privateExam": "Personal Evaluation",
+        "search": "Please enter search content..."
+    },
+    "event": {
+        "allStatus": "All Activity Status",
+        "unFinished": "Unfinished",
+        "Fineshed": "Finished",
+        "Timeout": "Timeout",
+        "makeupExam": "Makeup Exam",
+        "makeupHw": "Makeup available",
+        "selectActivity": "Please select an activity from the list"
+    },
+    "settingView-title": "Personal Settings",
     "teammodel-account-management": {
         "page-title": "TeamModel Account Management",
         "name": "Name",
         "account": "Account",
         "password": "Password",
-        "phone": "Phone",
+        "phone": "Mobile Number",
         "e-mail": "E-mail",
-        "binding": "Third Party Account Binding",
-        "isbind": "Binding",
-        "unbind": "Unbinding",
-        "save": "Save"
+        "binding": "Binding Management",
+        "isbind": "Bind",
+        "unbind": "Unbind",
+        "save": "Save settings"
     },
     "preference": {
-        "page-title": "Preference",
-        "UI-theme": "UI Theme",
-        "language": "Language"
+        "page-title": "Preferences",
+        "UI-theme": "Interface Style Settings",
+        "language": "Language Setting"
     },
     "change-school": {
-        "page-title": "Change School",
-        "current-data-school": "Current School Data Source",
+        "page-title": "Switch school",
+        "current-data-school": "Current data source school",
         "Habook-smart-school": "Habook Smart School"
     },
-    "homeView-title": "Overview",
-    "calenderCardTitle": "Calender",
-    "recentClass": "Recent Class",
-    "defaultRecentClass": "Inroduction to Embedded System Basic and Applications",
-    "defaultClassTime": "Wed. 13:30 - 16:30 (7th - 9th)",
-    "defaultClassPlace": "Building No.5 Room F504",
-    "todaydeadlineList": "Due Today Tasks",
-    "endsTodayTime": "Ends today at 23:59",
-    "coursesCardTitle": "My Courses List",
-    "newAddCourse": "New added Course:Advanced Mathematics II ",
-    "missionListCardTitle": "Tasks in progress ",
+    "homeView-title": "Homepage Information Overview",
+    "calenderCardTitle": "Calendar",
+    "recentClass": "Recent Class Reminder",
+    "defaultRecentClass": "Introduction to Microprocessor Basics and Applications",
+    "defaultClassTime": "Wednesday 13:30-16:30 (Sections 7-9)",
+    "defaultClassPlace": "F504 Classroom in the Fifth Teaching Building",
+    "todaydeadlineList": "Today Deadline Event Reminder",
+    "endsTodayTime": "Ends Today at 23:59",
+    "coursesCardTitle": "My Course List",
+    "newAddCourse": "The latest addition: Elective Mathematics (2)",
+    "missionListCardTitle": "Activity Task List",
     "missionListCardLoading": "Loading",
-    "missionListCardReachBottom": "Reached Page Bottom!",
+    "missionListCardReachBottom": "It's the bottom, no activity!",
     "myProgressBar": {
-        "tasksCompletionRate": "Tasks Completion Rate",
-        "selfStudyClickRate": "Self Study Tutorial Reading Rate"
+        "tasksCompletionRate": "Activity task completion rate",
+        "selfStudyClickRate": "Self-study textbook click rate"
     },
     "chartNames": [
-        "Time of Learning Online",
-        "Hours of Learning Online Each Month",
-        "Comparison of Tasks Participation",
-        "Comparison the Time of Learning Online",
-        "Proportion of participation time by task type this month",
-        "Heat Map of Learning Online"
+        "Average self-study time",
+        "Monthly self-study hour curve for this semester",
+        "Comparison of the number of activity participation between me and my grade last month",
+        "Comparison chart of average daily self-study time and the whole year level",
+        "Percentage of participation time of various activities and tasks this month",
+        "Self-study activity"
     ],
     "studyTimeChart": {
-        "averageTime": " min / day",
+        "averageTime": "Minutes/Day",
         "xAxisData": [
-            "Sun",
-            "Mon",
-            "Tue",
-            "Wed",
-            "Thu",
-            "Fri",
-            "Sat"
+            "day",
+            "One",
+            "two",
+            "three",
+            "four",
+            "Fives",
+            "six"
         ]
     },
     "splineSreaChart": {
         "xAxisData": [
-            "Feb",
-            "Mar",
-            "Apr",
+            "February",
+            "March",
+            "April",
             "May",
-            "Jun"
+            "June"
         ]
     },
     "stackBarChart": {
         "chartMon": "May",
         "yAxisData": [
-            "Me(3rd Grade)",
-            "3rd Grade",
-            "2nd Grade",
-            "1st Grade "
+            "I (third grade)",
+            "Third grade",
+            "second grade",
+            "ㄧ Grade"
         ],
         "stackType": [
-            "Homework",
-            "Exam",
-            "Preview",
-            "Vote"
+            "operation",
+            "Assessment",
+            "Pre-Class Preview",
+            "vote"
         ]
     },
     "twoLineChart": {
         "xAxisData": [
-            "Sun",
-            "Mon",
-            "Tue",
-            "Wed",
-            "Thu",
-            "Fri",
-            "Sat"
+            "day",
+            "",
+            "two",
+            "three",
+            "four",
+            "Fives",
+            "six"
         ]
     },
     "eventPieChart": {
         "partType": [
-            "Homework",
-            "Exam",
-            "Preview",
-            "Vote"
+            "operation",
+            "Assessment",
+            "Pre-Class Preview",
+            "vote"
         ]
     },
     "studyHeatMap": {
-        "tutorials": "tutorials",
         "xAxisData": [
-            "Mon",
-            "Tue",
-            "Wed",
-            "Thu",
-            "Fri"
+            "",
+            "two",
+            "three",
+            "four",
+            "Fives"
         ]
     },
-    "latestNotification": "Latest Notifications",
-    "postAt": "posted at",
-    "setting": "Setting",
-    "logout": "Log out",
+    "latestNotification": "Latest Notification",
+    "postAt": "Post At",
     "______________": "______________",
-    "eventView-title": "Tasks",
-    "nextTask": "Next task",
-    "allStatus": "All Status",
+    "eventView-title": "Activity Task",
+    "nextTask": "Next Task",
+    "allStatus": "All Activity Status",
     "unFinished": "Unfinished",
-    "Fineshed": "Fineshed",
+    "Fineshed": "Finished",
     "Timeout": "Timeout",
-    "makeupExam": "Make up Exam",
-    "makeupHW": "Make up Homework",
-    "empty": "No tasks yet!",
+    "makeupExam": "Makeup Exam",
+    "makeupHW": "Makeup available",
+    "empty": "There is currently no data ~",
     "baseInfo": {
         "subject": "Subject:",
         "teacher": "Teacher:",
-        "period": "Period:",
-        "postTime": "Posted Time:",
-        "classTime": "Class time",
+        "period": "Activity period:",
+        "postTime": "Post Time:",
+        "classTime": "Class Time",
         "unFinished": "Unfinished",
-        "Fineshed": "Fineshed",
+        "Fineshed": "Finished",
         "Closed": "Closed"
     },
     "billboard": {
         "description": "Description",
-        "referlink": "referlink",
+        "referlink": "referlink data",
         "attachment": "Attachment",
-        "reference": "Reference"
+        "reference": "reference"
     },
     "preview": {
-        "checkpoint": "Checkpoint",
-        "tutorial": "Tutorial",
-        "multiQues": "multi-Ques",
+        "checkpoint": "Activity Task",
+        "tutorial": "Programming Textbook",
+        "multiQues": "Multi-question pass module",
         "previewContent": {
-            "tutorial": "Tutorial",
-            "Des": "Description:",
-            "Unit": "Unit ",
-            "quiz": "Quiz"
+            "tutorial": "Textbook",
+            "Des": "Content",
+            "Unit": "Unit",
+            "quiz": "Examination in the classroom"
         },
-        "previous": "Previous",
-        "next": "Next",
-        "sentAns": "Submit",
-        "tryAgain": "Read and Try again",
+        "previous": "Previous Question",
+        "next": "Next Question",
+        "sentAns": "Sent Ans",
+        "tryAgain": "Read the textbook carefully, try again",
         "nextUnit": "Next Unit",
-        "goHome": "go to Overview",
-        "quizRetries": "Number of Quiz Retries",
-        "crossUnitHint": "The previous unit quizzes has not been completed yet. You should finish previous unit first and current unit could be unlock.",
-        "timeoutHint": "The preview task time has ended. You still could read and practice the task. If it is not completed before the end time, relevant scores may be affected."
+        "goHome": "Go Home",
+        "quizRetries": "Quiz Retries",
+        "crossUnitHint": "The last unit test has not been completed. Please complete it before proceeding to this unit test",
+        "timeoutHint": "The pre-class preview activity time has ended, and textbook reading and practice can still be carried out. If it is not completed before the end time, relevant results may be affected."
     },
     "vote": {
-        "bollotbox": "Bollot Box",
-        "submit": "Submit",
-        "reVote": "Submit Again",
-        "voteSuccess": "Finished !",
-        "voteDes": "After the event is over, you can view the voting results.",
-        "timeoutHint": "The voting time has ended. Please wait the voting result!",
-        "voteResult": "The voting result is: ",
-        "voteDesDefault": "Please select a plan you prefer:"
+        "bollotbox": "Voting Area",
+        "submit": "OK to submit",
+        "reVote": "Vote again",
+        "voteSuccess": "Vote successful",
+        "voteDes": "After the event is over, you can view everyone's voting results",
+        "timeoutHint": "The voting time has passed, and no more voting is possible. Please pay attention to the teacher's release of the voting results!",
+        "voteResult": "The result of this vote is:",
+        "voteDesDefault": "Please select a desired plan:"
     },
     "homework": {
-        "homeworkUpload": "Homework Upload",
-        "homeworkUoloadBtn": "Upload",
-        "homeworkReUoloadBtn": "Reupload",
-        "CommentClassmatesHomeworkBtn": "Reference and comment classmates homework",
-        "uploadSuccess": "Upload Success",
-        "uploadDes": "After the task is over, you can view the homework feedback by teacher and classmates.",
-        "timeoutHint": "The homework task time has ended and you have not uploaded, so your score of the homework will be 0 or wait for making up homework.",
-        "contentPage": "Description",
-        "scorePage": "Score and Comment",
-        "score": "Score",
-        "classmatesComments": "Classmates Comments",
-        "comment": "Comment: "
+        "homeworkUpload": "Homework Upload Area",
+        "homeworkUoloadBtn": "Upload job",
+        "homeworkReUoloadBtn": "Re-upload",
+        "CommentClassmatesHomeworkBtn": "CommentClassmatesHomeworkBtn",
+        "uploadSuccess": "Upload successful",
+        "uploadDes": "After the activity is over, you can view the assignment score comments",
+        "timeoutHint": "The time for uploading the homework has ended. The grade of this homework will be calculated as 0 points, or waiting for the teacher to open it up.",
+        "contentPage": "Job Content",
+        "scorePage": "Score Comment",
+        "score": "Teacher Score",
+        "classmatesComments": "Classmates Comment",
+        "comment": "Give comment: "
     },
     "classmatesComment": {
-        "title": "Reference and comment classmates homework",
-        "seatNo": "No.",
+        "title": "Classmates' work observation and mutual evaluation",
+        "seatNo": "seatNo",
         "name": "Name",
         "star": "Star",
-        "comment": "Comment",
-        "preview": "Preview: File Name",
-        "unPreview": "The format of this file could not be previewed now",
-        "download": "Download",
-        "submitted": "submitted",
-        "inputSomething": "Type Something",
+        "comment": "Give comment",
+        "preview": "Job Preview: File Name",
+        "unPreview": "This file format does not currently provide preview",
+        "download": "Download File",
+        "submitted": "Submitted",
+        "inputSomething": "Input comments and other suggestions",
         "previous": "Previous",
         "next": "Next",
         "submitBtn": "Submit"
     },
     "exam": {
         "examLink": "Exam Link",
-        "timeoutHint": "The exam task time has ended and you have not finished, so your score of the exam will be 0 or wait for making up exam.",
-        "contentPage": "Description",
+        "isSubject": "",
+        "subjectNow": "Current Subject",
+        "examData": "Evaluation Content",
+        "gradeReport": "Grade Report",
+        "gradeAnalyse": "Grade Analysis",
+        "testpop": {
+            "title": "assessment",
+            "completion": "Completion Degree",
+            "practiceMode": "Practice Mode",
+            "all": "Practice all",
+            "onlywrong": "Only practice answering wrong answers",
+            "questions": "Questions",
+            "submitted": "Submitted",
+            "finish": "Finished",
+            "showAns": "Show Answers",
+            "hideAns": "Hide the answer",
+            "hint": "Key Tips",
+            "previous": "Previous Question",
+            "next": "Next Question",
+            "myAnswerSheet": "My Answer Sheet",
+            "exitQuizhint": "Exit Quizhint",
+            "exitQuizhintDe": "The system has detected that you have not yet 'submitted', if you choose 'OK',",
+            "exitQuizhintDes": "The current answer will not be saved, and the test will be re-tested next time",
+            "cancel": "Cancel",
+            "ok": "OK",
+            "submitQuizhint": "Submit Quizhint",
+            "submitQuizhintDes1": "The system test has been completed so far. Are you sure to submit the paper?",
+            "check": "No, need to check again",
+            "conAnswer0": "Currently you have",
+            "conAnswer1": "The question has not been answered (check the answer card in detail)",
+            "conAnswer2": ", please complete the question first!",
+            "conAnswer": "Continue to answer",
+            "okSubmit": "Confirm to submit the paper",
+            "qNo": "Question Number:",
+            "myAns": "Answer",
+            "correction": "正解",
+            "queNo": "Title:",
+            "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.",
+        "contentPage": "Review Content",
         "scorePage": "Score Report",
-        "practiceHint": "The exam task time has ended and you still can click the link to practice.",
-        "performance": "Performance",
-        "reviewAnswers": "Review of Answers",
-        "Chinese": "Chinise",
-        "Math": "Math",
-        "English": "English",
+        "practiceHint": "The assessment activity time has ended, you can still click on the test paper link to continue practicing.",
+        "performance": "performance",
+        "reviewAnswers": "Review of answering status",
+        "Chinese": "国文",
+        "Math": "Mathematics",
+        "English": "英文",
         "score": "Score",
-        "difficulty": "Difficulty",
+        "difficulty": "Comprehensive difficulty of examination questions",
         "average": "Class average score",
-        "rightNum": "Number of correct answers",
-        "smartComment": "AI Suggestion",
-        "keypoint": "Review keypoint:",
+        "rightNum": "The number of my correct answers",
+        "smartComment": "Smart Comment",
+        "keypoint": "Recommended knowledge points for review:",
         "chart": {
-            "scoreDistribution": "Score Distribution",
-            "participant": "participant:",
-            "student": "students",
-            "keyPointPerformance": "KeyPoint Performance",
-            "me": "Me",
-            "participantAverage": "Participants' average",
-            "recognizePerformance": "Recognize Performance"
+            "scoreDistribution": "Score Distribution Chart",
+            "participant": "Number of candidates:",
+            "student": "person",
+            "keyPointPerformance": "Knowledge Point Performance Radar Chart",
+            "me": "Individual",
+            "participantAverage": "The whole school",
+            "recognizePerformance": "Recognition Level Radar Chart"
         },
-        "correctAnswer": "Correct",
-        "wrongAnswer": "Wrong",
+        "correctAnswer": "correctAnswer",
+        "wrongAnswer": "Wrong Answer",
         "unAnswered": "Unanswered",
         "solution": "Solution",
         "analysis": "Analysis",
-        "correctRate": "Correct rate",
-        "relatedAQues": "Related Question",
-        "testpop": {
-            "title": "Exam",
-            "completion": "Completion rate",
-            "practiceMode": "Practice Mode",
-            "all": "All",
-            "onlywrong": "Only wrong",
-            "questions": "questions",
-            "submitted": "submit",
-            "showAns": "Show Answer",
-            "hideAns": "Hide Answer",
-            "hint": "keypoint hint",
-            "previous": "Previous",
-            "next": "Next",
-            "myAnswerSheet": "MyAnswerSheet",
-            "exitQuizhint": "Exit Quiz",
-            "exitQuizhintDes": "The system detects that you have not yet 'submitted', if you choose 'OK', the current answer will not be saved, and you need to retest next time",
-            "cancel": "Cancel",
-            "ok": "OK",
-            "submitQuizhint": "Submit Quiz",
-            "submitQuizhintDes1": "The system detects that you finished all question, are you sure to submmit ?",
-            "check": "No, Check Again",
-            "okSubmit": "OK",
-            "qNo": "No.",
-            "myAns": "My Answer",
-            "correction": "Correction"
-        }
+        "correctRate": "correct rate",
+        "relatedAQues": "Related Questions",
+
     },
-    "informview-title": "Notifications",
-    "view": "view",
-    "read": "read",
-    "studyview-title": "Self-study",
-    "hiteachview-title": "HiTeach Note",
+    "informview-title": "Notification Overview",
+    "view": "Go to view",
+    "read": "Read",
+    "studyview-title": "self-study",
+    "hiteachview-title": "HiTeach Class Record",
     "hiteachNote": {
-        "material": "Material",
-        "classInteractionRecord": "Interaction Record",
-        "qA": "QA",
-        "qAMulti": "QA(Multi)",
-        "reference": "Reference Answer",
-        "correct": "Correct",
-        "groupQAMulti": "Group QA(Multi)",
-        "poImg": "Teacher sent a picture from Hitach:",
-        "link": "Link"
+        "material": "Class Content",
+        "classInteractionRecord": "Class Interaction Record",
+        "qA": "Question and Answer",
+        "qAMulti": "Question and Answer (Multiple Choice)",
+        "reference": "reference answer",
+        "correct": "The answer is correct",
+        "groupQAMulti": "Group QAMulti (multiple choice)",
+        "poImg": "The teacher pushed a picture from Hitach:",
+        "link": "Share Link"
     },
-    "courseList-title": "Course List",
-    "defaultClass": "Default",
-    "tempClass": "Additional",
+    "courseList-title": "My Course List",
+    "defaultClass": "Specify a class",
+    "tempClass": "Temporary Class",
     "courseContent": {
-        "baseInfo": "Infomation",
-        "description": "Description",
-        "classmates": "Classmates",
-        "classID": "Class ID",
-        "classTime": "Class time",
+        "baseInfo": "Basic Information",
+        "description": "Course Overview",
+        "classmates": "Classmates List",
+        "classID": "Course Code",
+        "classTime": "Class Time",
         "classroom": "Classroom",
         "teacher": "Teacher",
-        "co-teacher": "Co-teachers",
-        "addedTime": "Added time",
-        "syllabus": "Syllabus",
-        "seatNo": "No.",
+        "co-teacher": "Co-teacher",
+        "addedTime": "Added Course Date",
+        "syllabus": "Syllabus Overview",
+        "seatNo": "seatNo",
         "name": "Name",
         "group": "Group"
     },
-    "calendar-title": "Calendar - 2020 Semester II",
-    "today":"Today",
-    "importEvent":"Important Event of Class or Campus",
-    "deadlineTasks":"Tasks Ended of the day",
-    "schedule":"Schedule",
-    "des":"Description",
-    "time":"Time",
-    "place":"Place",
-    "course":"Course",
-    "mockcourses":["Reading and Writing", "English Presentation", "Special Experiments on Electronic Circuits", "Introduction to Computers", "Microprocessor Experiments"],
-    "importEventTitle":"Important Events",
-    "Thatday":"That day",
-    "deadlineTasksTitle":"Unfinished Tasks Ended That Day"
+    "calendar-title": "Calendar-Second Semester of 109 School Year",
+    "today": "Today",
+    "importEvent": "Campus Class Important Events",
+    "deadlineTasks": "Deadline Tasks",
+    "schedule": "Schedule Schedule",
+    "des": "Description",
+    "time": "Time",
+    "place": "Location",
+    "course": "course",
+    "mockcourses": ["Reading and Writing", "English Presentation", "Special Experiments on Electronic Circuits", "Introduction to Computers", "Microprocessor Experiments"],
+    "importEventTitle": "Campus Class Important Events",
+    "Thatday": "Thatday",
+    "deadlineTasksTitle": "DeadlineTasksTitle"
 }

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

@@ -0,0 +1,38 @@
+export default {
+    menu:{
+        smartSc:'智慧校园',
+        baseSetting:'基础设置',
+        teacherMgt:'教师管理',
+        stuMgt:'学生管理',
+        classMgt:'教室管理',
+        cusSetting:'课程设置',
+        cusPlanMgt:'排课管理',
+        authMgt:'授权管理',
+        preview:'预览',
+        scSyllabus:'校本课纲',
+        scContent:'校本内容',
+        scQuBack:'校本题库',
+        kdBack:'知识点库',
+        staAna:'统计分析',
+        evAna:'学情分析',
+        scAna:'校园分析',
+        scAc:'校园活动',
+        scEv:'评量测验',
+        scVote:'投票活动',
+        scQu:'问卷调查',
+        classCus:'班级课程',
+        myClass:'我的班级',
+        myCus:'我的课程',
+        cusContent:'课程教材',
+        prtSyllabus:'个人课纲',
+        prtContent:'个人内容',
+        prtQuBack:'个人题库',
+        stuAc:'学习活动',
+        prtEv:'个人评测',
+        prtVote:'个人投票',
+        prtQu:'个人问卷',
+        selfLearn:'自主学习',
+        homework:'作业活动',
+        acRecord:'活动记录'
+    }
+}

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

@@ -29,7 +29,7 @@ export default {
     ti_text4: 'number of grades',
     ti_text5: 'number of classes',
     ti_text12: 'evaluate all',
-    ti_text6: 'weekly test',
+    ti_text6: 'formal examination',
     ti_text7: 'opening examination',
     ti_text8: 'midterm exam',
     ti_text9: 'final exam',

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

@@ -73,6 +73,7 @@ export default {
         studentTableC4: '年级',
         studentTableC5: '组别',
         studentTableC6: '组名',
+        studentTableC7: '账号',
         addClassroomProp1: '选择预设教室',
         addClassroomProp2: '新建个人教室',
         chooseClassroom: '请选择系统的教室',

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

@@ -0,0 +1,229 @@
+export default {
+    index:{
+		item:'试题',
+		paper:'试卷',
+		addExercise:'新建习题',
+		openAll:'全部展开',
+		collapseAll:'全部折叠',
+		autoCreate:'智能组卷',
+		manualCreate:'挑题组卷',
+		importCreate:'导题组卷',
+		backList:'返回列表'
+	},
+	filter:{
+		origin:'来源',
+		schoolBank:'校本题库',
+		privateBank:'个人题库',
+		all:'全部',
+		diff:'难度',
+		level:'层次',
+		type:'题型',
+		period:'学段',
+		grade:'年级',
+		subject:'科目',
+		sort:'排序',
+		createTime:'新增时间',
+		useCount:'使用次数'
+	},
+	single:'单选题',
+	multiple:'多选题',
+	judge:'判断题',
+	complete:'填空题',
+	subjective:'问答题',
+	connector:'连线题',
+	correct:'改错题',
+	compose:'综合题',
+	diff1:'容易',
+	diff2:'较易',
+	diff3:'一般',
+	diff4:'较难',
+	diff5:'困难',
+	level1:'知识',
+	level2:'理解',
+	level3:'应用',
+	level4:'分析',
+	level5:'综合',
+	level6:'评鉴',
+	noData:'暂无数据',
+	answer:'答案',
+	noAnswer:'未设置答案',
+	explain:'解析',
+	noExplain:'暂无解析',
+	knowledgePoints:'知识点',
+	noPoints:'暂未绑定知识点',
+	updateTime:'更新时间',
+	isTrue:'正确',
+	isFalse:'错误',
+	deleteItem:'删除',
+	editItem:'编辑',
+	confirm:'确认',
+	cancel:'取消',
+	deleteSuc:'删除成功',
+	deleteFail:'删除失败',
+	editSuc:'修改成功',
+	backToTop:'返回顶部',
+	newExercise:{
+		newSchoolItem:'新建校本题目',
+		newPrivateItem:'新建个人题目',
+		backToBank:'返回题库',
+		choosePeriod:'选择学段',
+		chooseGrade:'选择年级',
+		chooseSubject:'选择科目',
+		gradePlaceholder:'不选择则默认选中全部年级',
+		diff:'题目难度',
+		field:'关联认知层次', 
+		knowledge:'关联知识点',
+		choosePoint:'选择知识点',
+		modify:'修改',
+		type:'选择题型',
+		stem:'题干',
+		option:'选项',
+		singleOption:'单选选项',
+		multipleOption:'多选选项',
+		trueAnswer:'正确答案',
+		setAnswer:'设为答案',
+		addOption:'添加选项',
+		repair:'补救资源',
+		outRepair:'外部资源',
+		innerRepair:'站内资源',
+		addLink:'添加链接',
+		chooseContent:'选择内容',
+		normalResource:'一般资源',
+		mediaResource:'影片资源',
+		linkTip:'请输入正确的链接地址(如:https://www.baidu.com)',
+		childList:'小题列表',
+		addChild:'添加小题',
+		save:'保存',
+		cancel:'取消',
+		composeTip:'综合题的知识点请绑定在小题上!',
+		noSchoolTip:'您当前未加入学校,无法选择知识点!',
+		uploadErrorTip:'试题文件上传失败,请稍后重试!',
+		unCompleteTip:'请将题目填写完整!',
+		typeChangeTip:'暂不支持更换题型!',
+		modalTip:'温馨提示',
+		unSaveTip:'确认放弃保存当前试题并前往?',
+		answerTitle:'参考答案',
+		contentRelate:'内容关联'
+	},
+	exerciseList:{
+		confirmDelete:'确认删除该试题吗?',
+		setAnswer:'设置答案',
+		typeScore:'题型配分',
+		totalScore:'试卷总分',
+		alreadyScore:'已分配总分',
+		waitScore:'待分配分数',
+		itemNums:'道题,总分配',
+		multipleRule:'多选题(包括综合题的小题)配分规则',
+		rule1:'默认全对得满分',
+		rule2:'少选得一半分数,错选或者不选不得分',
+		rule3:'少选按个数得分,错选或者不选不得分',
+		rule4:'依照(选项数 - 2 * 错选数)/ 选项数,负分则不得分',
+		overScoreTip:'配分已超试卷总分,请重新分配!',
+		editExercise:'编辑习题',
+		editChild:'编辑子题',
+		moveUp:'上移',
+		moveDown:'下移',
+		noAnswerTip:'请为当前客观题设置正确答案!',
+		noOptionTip:'试题题干或选项信息有误,请删除或者重新导入正确文档!'
+	},
+	paperList:{
+		usePeriod:'适用学段',
+		useGrade:'适用年级',
+		itemCount:'题量',
+		paperAnalysis:'试卷分析',
+		totalScore:'总分',
+		score:'分',
+		paperErrorTip:'获取试卷数据失败!',
+		confirmDelete:'确认删除该试卷吗?',
+		editPaper:'编辑试卷',
+		backToBank:'返回试卷库',
+		baseInfo:'基础信息',
+		paperType:'试卷类型',
+		schoolBank:'学校公有库',
+		praviteBank:'个人试卷库',
+		paperName:'试卷名称',
+		paperScore:'试卷总分',
+		alreadyScore:'已配分数',
+		saveRule1:'温馨提示:当前试卷将以题目顺序方式保存',
+		saveRule2:'温馨提示:当前试卷将以题型顺序方式保存',
+		tab1:'组题条件',
+		tab2:'备选题目',
+		tab3:'重新导入',
+		tab4:'导入试题',
+		tab5:'试题预览',
+		tab6:'学生作答预览',
+		isSaving:'保存中',
+		savePaper:'保存试卷',
+		editSuc:'编辑成功',
+		saveSuc:'保存成功',
+		saveFail:'保存失败',
+		defaultName:'预设试卷名称',
+		saveItemsFailTip:'试卷试题数据保存失败!',
+		emptyNameTip:'试卷名称不能为空!',
+		noSpaceTip:'空间已满!',
+		noItemTip:'未选择任何试题!',
+		isExistPaperTip:'试卷库已存在重复名称试卷,是否继续保存覆盖原试卷?',
+		cancelSaveTip:'取消保存试卷!',
+		hasNoScoreTip:'存在未配分的题目,请配分后再保存!',
+		noCompleteScoreTip:'保存前请确认试卷配分是否与试卷总分一致!',
+		hasErrorItemTip:'存在异常试题,请修改或者重新导入!',
+		cleanItems:'清空试题',
+		orderByList:'顺序排列',
+		orderByType:'题型排列',
+		paperDetails:'试卷详情',
+		paperAnalysis:'试卷分析',
+		setPaperScore:'设置试卷总分'
+	},
+	importFile:{
+		uploadSuc:'文件上传解析成功!',
+		analysisFail:'对不起,文档解析失败!',
+		templateDownload:'模板下载',
+		downloadDetails:'下载模板制作详情说明',
+		importTips:'导入注意事项',
+		tips1:'点击上方上传图标选择文件',
+		tips2:'只支持".docx"格式的文件导入,请按照模板格式导入',
+		tips3:'导入题型暂时只支持单选、多选、判断、填空、问答以及综合题型',
+		tips4:'请保持模板语言与当前浏览器语言一致',
+		tips5:'更多注意事项请查看模板制作详情说明',
+		warningTips1:'上传格式仅支持 docx,请重新上传!',
+		warningTips2:'最大上传大小为10M,请重新上传!',
+		warningTips3:'试题数据读取完成!',
+		warningTips4:'未解析出符合条件的试题,请检查导入格式是否按照模板文件修改!',
+		warningTips5:'抱歉,文档解析失败!',
+	},
+	createPaper:{
+		setAutoConditions:'设置自动出题条件',
+		origin:'题目来源',
+		schoolRate:'校本占比',
+		rateTip:'默认相同比例校本优先',
+		doAutoCreate:'开始组题',
+		random:'随机',
+		average:'平均分配',
+		noItemTip:'题目数量不能为空!',
+		noResultTip:'未能匹配满足条件的题目!',
+		total:'共',
+		nums:'道题',
+		spc:'道',
+		goDetails:'查看详情',
+		noOriginTips:'请先选择题目来源'
+	},
+	points:{
+		addPoint:'新增知识点',
+		searchPoint:'搜索知识点',
+		noPoint:'当前科目下暂无知识点',
+		checkedPoint:'已选知识点',
+		pointName:'知识点名称',
+		inputNewPoint:'输入新知识点名称',
+		noNameTips:'请输入新知识点名称!',
+		addSuc:'添加成功!',
+		addFail:'添加失败!',
+		numMax1:'最多绑定',
+		numMax2:'个知识点'
+	},
+	echarts:{
+		pointPie:'试卷知识点分析图',
+		typePie:'试卷题型分析图',
+		diffPie:'试卷难度分析图',
+		objectivePie:'试卷主客观分析图'
+	}
+}

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

@@ -0,0 +1,13 @@
+export default{
+    examType1:'期中考试',
+    examType2:'期末考试',
+    examType3:'模拟考试',
+    evType1:'正规考',
+    evType2:'模拟考',
+    evType3:'普通考',
+    evMode1:'线上评量',
+    evMode2:'课中评量',
+    evMode3:'阅卷评量',
+    publishType1:'立即发布',
+    publishType2:'定时发布',
+}

+ 10 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/index.js

@@ -17,8 +17,12 @@ import regist from './regist'
 import forgotPW from './forgotPW'
 import studentWeb from './studentWeb'
 import settings from './settings'
-import seviceDriveAuth from './seviceDriveAuth'
+import serviceDriveAuth from './serviceDriveAuth'
 import elui from './elui'
+import evaluation from './evaluation'
+import learnActivity from './learnActivity'
+import global from './global'
+import system from './system'
 export default {
   schoolBaseInfo,
   classMgmt,
@@ -39,8 +43,12 @@ export default {
   forgotPW,
   studentWeb,
   settings,
-  seviceDriveAuth,
+  serviceDriveAuth,
   elui,
+  evaluation,
+  learnActivity,
+  global,
+  system,
   test: '测试',
   formConfigP: {
     input: '请输入',

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

@@ -0,0 +1,182 @@
+export default{
+    //MgtSchoolEva.vue
+    mgtScEv:{
+        listLabel:'评测列表',
+        period:'学段:',
+        create:'新建',
+        delete:'删除',
+        edit:'编辑',
+        createTime:'施测时间:',
+        pending:'待发布',
+        going:'进行中',
+        finish:'已结束',
+        endTime:'结束时间:',
+        stop:'立即结束',
+        evType:'测试类型:',
+        stuCount:'施测人数:',
+        nodata:'暂无评测',
+        tab1:'评测数据',
+        tab2:'评测试卷',
+        autoTips1:'此功能仅用于展示情景快速模拟学生作答数据,且学生作答为随机生成,仅供参考!',
+        autoTips2:'此功能仅用于展示情景快速模拟教师评分数据,且分数为随机生成,仅供参考!',
+        autoScore:'一键评分',
+        autoAnswer:'一键作答',
+        evSubject:'测试科目:',
+        returnTop:'返回顶部',
+        mockOk:'模拟成功',
+        mockErr:'模拟失败',
+        stopTitle:'结束评测',
+        stopContent:'结束后学生将不能继续作答,是否立即结束',
+        stopOk:'评测已结束!',
+        deleteTitle:'删除评测',
+        deleteContent:'是否确认删除',
+        deleteOk:'删除成功',
+        deleteErr:'删除失败',
+        noJoin:'此账号暂未加入任何学校!'
+    },
+
+    //创建评测校本/个人
+    createEv:{
+        createLabel:'创建评测',
+        publishEv:'发布评测',
+        return:'返回上级',
+        baseInfo:'基础信息',
+        evName:'评测名称',
+        evPeriod:'测试学段',
+        evMode:'评测模式',
+        evType:'评测类型',
+        examType:'考试类别',
+        courseType:'课程类别',
+        cusLabel1:'校本课程',
+        cusLabel2:'个人课程',
+        evTarget:'施测对象',
+        publishType:'发布方式',
+        startTime:'开始时间',
+        sTimeHolder:'请选择开始时间',
+        endTime:'结束时间',
+        eTimeHolder:'请选择结束时间',
+        addSubject:'添加学科',
+        noSubject:'暂无科目,请添加科目',
+        noSubject1:'* 请先选择测试学段',
+        papersLabel:'试卷库',
+        perviewLabel:'试卷预览',
+        importLabel:'导入说明',
+        answerPreview:'作答预览',
+        errTips1:'评测名称不能为空!',
+        errTips2:'测试类型不能为空!',
+        errTips3:'评量模式不能为空!',
+        errTips4:'请设置类别!',
+        errTips5:'请设置测试类型!',
+        errTips6:'请设置测试对象!',
+        errTips7:'请设置发布方式!',
+        errTips8:'请设置发布时间!',
+        errTips9:'请设置结束时间!',
+        errTips10:'请设置测试学段!',
+        stPaperTitle:'挑选试卷',
+        stPaperContent:'是否确认挑选',
+        inDev:'功能正在开发中,敬请期待!',
+        formWarning:'请先完善评测基础信息!',
+        paperWarning:'请挑选或导入试卷!',
+        paperWarning1:'还没有试卷,请挑选或导入试卷!',
+        pdWarning:'请添加测试科目!',
+        publishOk:'评测发布成功!',
+        togglePeriod:'切换学段',
+        togglePdTip1:'您已添加',
+        togglePdTip2:'的测试科目,如果现在切换学段会清空已选科目,确定切换学段吗?',
+        toggleOkText:'切换',
+        delPdTitle:'删除科目',
+        delPdContent:'是否确认删除',
+        delOk:'删除成功',
+        pdTips:'请先选择测试学段!',
+        defaultPaper:'(请先挑选或导入试卷)',
+    },
+    // ManualPaper.vue
+    manual:{
+        source:'来源:',
+        sourceP:'个人试卷库',
+        sourceS:'校本试卷库',
+        pdLabel:'学段:',
+        subjectLabel:'学科:',
+        gradeLabel:'年级:',
+        fitPd:'适用学段:',
+        fitSubject:'适用科目:',
+        quCount:'题量:',
+        useCount:'使用次数:',
+        stdPaper:'已选试卷',
+        stPaper:'选择试卷',
+        previewPaper:'预览试卷',
+        noPaper:'暂无对应的试卷',
+        noPaper1:'暂无试卷'
+    },
+    // PaperScore.vue、Scoring.vue
+    score:{
+        stuName:'学生姓名:',
+        score:'总分:',
+        scoreUnit:'分',
+        saveScore:'保存打分',
+        showAns:'显示答案',
+        hideAns:'隐藏答案',
+        showQu:'显示题干',
+        hideQu:'隐藏题干',
+        quIndex:'题号:',
+        quIndex1:'题号',
+        fullScore:'满分',
+        zeroScore:'零分',
+        zeroScore1:'0分',
+        stuAns:'【学 生 作 答】',
+        mark:'批注',
+        quAns:'【答ㅤ案】',
+        noAnswer:'未设置答案',
+        anaLabel:'【解ㅤ析】',
+        noAna:'暂无解析',
+        kdLabel:'【知识点】',
+        noKd:'暂未绑定知识点',
+        sQuLabel1:'【小题',
+        sQuLabel2:'】',
+        quIndexLabel:'【题号',
+        nextStu:'下一位学生>>>',
+        markOk:'批注成功!',
+        markErr:'批注失败!',
+        isFullTips:'已经是小题满分了',
+        isZeroTips:'已经是零分了',
+        saveScoreOk:'成绩保存成功!',
+        saveSocreErr:'成绩保存失败!',
+        zero:'零',
+        one:'一',
+        two:'二',
+        three:'三',
+        four:'四',
+        five:'五',
+        six:'六',
+        seven:'七',
+        eight:'八',
+        nine:'九',
+        ten:'十',
+        hundred:'百',
+        thousand:'千',
+        tenThd:'万',
+        hMillion:'亿',
+        noStuAns:'未作答',
+        noStuAns1:'暂未作答',
+        trueAns:'正确',
+        falseAns:'错误',
+        //Scoring.vue
+        subjectLabel:'学科:',
+        gradeLabel:'年级:',
+        classLabel:'班级:',
+        stuLabel:'学生:',
+        scoreView:'分数概览',
+        scoring:'试卷评分',
+        classNoStu:'班级暂无学生',
+        status1:'暂未作答',
+        status2:'前往评分',
+        status3:'查看分数',
+        column1:'姓名',
+        column2:'总分',
+        column3:'状态',
+        finishScore:'已完成所有学生作答的评分!',
+        unableScore:'学生尚未作答,无法评分',
+        stStuWarning:'请先选择学生!'
+    }
+
+}

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

@@ -36,10 +36,44 @@ export default {
   presetSubject1: '语文',
   presetSubject2: '数学',
   presetSubject3: '英语',
+  pdHolder:'设置学段...',
+  tmzLabel:'时区设置:',
+  tmzHolder:'请设置时区...',
+  campusHolder:'请设置校区',
+  setCampus:'请设置校区',
+  smHolder:'设置学期...',
+  subjectHolder:'设置学科...',
+  noSubject:'暂无学科',
+  anaLabel:'学情设置',
+  exTypeLabel:'考试类型:',
+  examHolder:'设置考试类型...',
+  noExam:'暂无考试类型',
+  eugenicsLabel:'优生率:',
+  eugenicsTips:'优生率计算方式',
+  incomeLable:'进线率:',
+  incomeTips:'(进线人数)/(报名人数)×100%',
+  touchLabel:'踩线生:',
+  touchTips:'踩线生计算方式',
+  scoreUnit:'分',
+  delExamTitle:'删除考试类型',
+  delGradeTitle:'删除年级',
+  delSubjectTitle:'删除学科',
+  delPdTitle:'删除学段',
+  delCampusTitle:'删除校区',
+  delSmTitle:'删除学期',
+  delContent:'后与之关联的数据将不能查询,确认删除吗?',
+  campusWarning:'对不起,校区数量已到系统授权最多数量!',
+  authWarning:'您暂无此操作权限!',
+  saveErr:'保存失败!',
+  saveWarning:'保存提醒',
+  leaveText:'离开',
 
   // ClassroomSetting.vue
   classroomList: '教室列表',
+  pdLabel:'学段:',
   listOrder: '依创建时间排序',
+  listOrder1: '依教室编号排序',
+  listOrder2: '依智慧教室排序',
   classroomAttr: '教室属性',
   classroomCode: '教室编码',
   classroomName: '教室名称',
@@ -82,5 +116,49 @@ export default {
   '3222NIYD': 'ezStation 2',
   'J223IZ6M': 'HiTeach STD',
   '3222C6D2': 'HiTeach TBL',
-  'J223IZAM': 'HiTeach PRO'
+  'J223IZAM': 'HiTeach PRO',
+  tmdClass:'TEAM Model 智慧教室',
+  normalClass:'普通教室',
+  dClass:'专科教室',
+  tab1:'基础信息',
+  tab2:'学生名单',
+  tab3:'位置设定',
+  tab4: '关联Hiteach',
+  classAttr:'教室属性',
+  relationHi:'关联Hiteach设备',
+  hiFilter1:'显示所有版本的Hiteach',
+  hiFilter2:'仅显示Hiteach Standard版本',
+  hiFilter3:'仅显示Hiteach Pro版本',
+  hiFilter4:'仅显示Hiteach TBL版本',
+  single:'单一',
+  mach:'大量',
+  expireLabel:'序号到期日',
+  related:'已被關聯',
+  noEnable:'此序号尚未启用',
+  onClassStu:'专科教室没有固定学生名单!',
+  classNoErr:'教室编码不能为空!',
+  classNoErr1:'教室编码只能由字母和数字组成!',
+  classAttr1:'常规教室(有固定学生)',
+  classAttr2:'专科教室(无固定学生)',
+  nameWarning:'请输入教室名称',
+  typeWarning:'请设置教室属性',
+  gradeWarning:'请设置年级',
+  expireLabel1:'已到期',
+  expireLabel2:'无限期',
+  findStuErr:'查询班级学生名单失败!',
+  noStdClass:'当前班级未选中,不能移动!',
+  formWarning:'请先完善班级信息再保存!',
+  bindingErr:'Hiteach 绑定失败!',
+  delClass:'删除班级',
+  saveClassWarning:'当前教室数据尚未保存。如果离开,修改的数据将不会保存!',
+  addStuBtn:'添加学生',
+  delStuBtn:'移除学生',
+  editSeat:'修改座号',
+  removeTile:'移除提醒',
+  removeContent:'是否确认移除',
+  removeOk:'移除成功',
+  removeErr:'移除失败',
+  deLink: '解除关联',
+  link: '关联',
+  confirmDelink:'请问您确定要解除关联'
 }

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

@@ -0,0 +1,181 @@
+export default {
+  //ServiceList.vue
+  AEGMCPLY: 'AClass One', //AClass One 周期
+  RYGVCPLY: 'AClass One', //AClass One 无周期
+  IPALYEIY: '智慧教学服务空间',
+  '6BOPC6MD': '教与学大数据管理服务',
+  ON6MBDOP: '智慧学校大数据管理服务',
+  服務授權列表: '服务授权列表',
+  智慧教室授權管理: '智慧教室授权管理',
+  未購買: '未购买',
+  已購買: '已购买',
+  '服務啟用 / 到期日:': '服务启用 / 到期日:',
+  剩餘: '剩余',
+  天: '天',
+  無週期授權數量: '无周期授权数量',
+  有週期授權數量: '有周期授权数量',
+  固定分配數: '固定分配数',
+  動態分配數: '动态分配数',
+  剩餘分配數: '剩餘分配數',
+  總使用率: '总使用率',
+  詳細服務內容: '详细服务内容',
+  管理AClassOne授權: '管理AClassOne授权',
+
+  //HiteachAuthList.vue
+  確定解除授權: '确定解除授权',
+  當前您所選中的PC: '当前您所选中的PC',
+  ',確定解除授權?': ',确定解除授权?',
+  '解除授權後,可在教室中的電腦再次進行綁定授權。': '解除授权后,可在教室中的电脑再次进行绑定授权。',
+  取消: '取消',
+  確定: '确定',
+  Hiteach序號數: 'Hiteach序号数',
+  大量: '大量',
+  單一: '单一',
+  授權: '授权',
+  可啟用裝置數: '可启用装置数',
+  已啟用裝置數: '已启用装置数',
+  管理Hiteach教室: '管理Hiteach教室',
+  暂无数据: '暂无数据',
+  序號到期日: '序号到期日:',
+  無到期日: '无到期日',
+  已到期: '已到期',
+  序號使用狀況: '序号使用状况:',
+  未命名機台: '未命名机台',
+  解除授權: '解除授权',
+  顯示全部: '顯示全部',
+  '僅顯示HiTeach STD序號': '仅显示HiTeach STD序号',
+  '僅顯示HiTeach PRO序號': '仅显示HiTeach PRO序号',
+  '僅顯示HiTeach TBL序號': '仅显示HiTeach TBL序号',
+  僅顯示已完成綁定的序號: '仅显示已完成绑定的序号',
+  僅顯示已到期序號: '仅显示已到期序号',
+  已成功解除授權: '已成功解除授權',
+
+  //SpaceStatus.vue
+  智慧教學服務空間狀態: '智慧教学服务空间状态',
+  分配教學空間: '分配教学空间',
+  空間總數: '空间总数',
+  已使用空間總數: '已使用空间总数',
+  空間使用狀況: '空间使用状况',
+  未使用空間數: '未使用空间数',
+  未使用空間比率: '未使用空间比率',
+  可使用空間數: '可使用空间数',
+  可使用空間比率: '可使用空间比率',
+  當前空間到期日: '当前空间到期日',
+  '基本 1GB 永久授權': '基本 1GB 永久授权',
+  '到期後將變更為IES基本空間,超出基本空間值將被收回': '到期后将变更为IES基本空间,超出基本空间值将被收回',
+  購買記錄: '购买记录',
+  醍摩豆智慧教學服務空間: '醍摩豆智慧教学服务空间',
+  訂單日期: '订单日期:',
+  到期日: '到期日:',
+  添購其他服務: '添购其他服务',
+  '空間已到期,超過僅供檢視': '空間已到期,超過僅供檢視',
+
+  //SpaceChart.vue
+  文件: '文件',
+  永久授權: '永久授权',
+  影片: '影片',
+  圖片: '图片',
+  題目與試卷: '题目与试卷',
+  其他: '其他',
+  學生使用: '学生使用',
+  已分配至教師: '已分配至教师',
+  未使用: '未使用',
+  空間: '空間',
+  空間數: '空間數',
+  空間比率: '空間比率',
+
+  //學生帳號頁面的授權管理控件 student-account / AclassOneAuth.vue
+  確定收回所有授權: '確定收回所有授權',
+  '收回授權後使用數會直接設置為0,如欲給予授權可針對目標對象進行套用。': '收回授权后使用数会直接设置为0,如欲给予授权可针对目标对象进行套用。',
+  服務授權管理: '服务授权管理',
+  AClassONE智慧學伴服務授權: 'AClassONE智慧学伴服务授权',
+  '賦予持有該服務授權的學生TEAM Modal ID使用AClassONE智慧學伴App的權限': '赋予持有该服务授权的学生TEAM Modal ID使用AClassONE智慧学伴App的权限',
+  總授權數: '总授权数',
+  本次套用數: '本次套用数',
+  已使用數: '已使用数',
+  授權總覽: '授权总览',
+  授權管理: '授权管理',
+  已購授權總數: '已购授权总数:',
+  note: '固定分配之授权由校方统一设置,使用者请于授权管理分页进行授权对象的设定。动态取用之授权每日23:59:59将自动回收,学生可于次日再次启用。',
+  快速套用授權: '快速套用授权',
+  套用至所有當前勾選項目: '套用至所有当前勾选项目',
+  套用: '套用',
+  套用至: '套用至',
+  套用至當前勾選目標第: '套用至当前勾选目标第',
+  項至第: '项至第',
+  項: '项',
+  所有項目: '所有项目',
+  未关联班级: '未关联班级',
+  套用至全校所有項目: '套用至全校所有项目',
+  共: '共',
+  個: '个',
+  '大於總授權數,無法使用': '大于总授权数,无法使用',
+  添購其他授權: '添购其他授权',
+  收回所有授權: '收回所有授权',
+  保存所有變更: '保存所有变更',
+  選擇班級: '選擇班級',
+
+  //下方method區塊
+  固定分配授權數: '固定分配授权数',
+  今日動態取用數: '今日动态取用数',
+  今日可用授權數: '今日可用授权数',
+  '請先選擇套用,再按保存': '请先选择套用,再按保存',
+  '保存成功,本次尚無新增授權數量': '保存成功,本次尚无新增授权数量',
+  '保存成功,本次新增': '保存成功,本次新增',
+  個固定分配: '个固定分配',
+  '保存失敗,超過可用授權數!': '保存失败,超过可用授权数! ',
+  全部收回成功: '全部收回成功',
+  請先勾選欲授權之學生: '请先勾选欲授权之学生',
+  '請設定有效的目標項 !': '请设定有效的目标项 !',
+  '目前所選學制人數為 0 人!': '目前所选学制人数为 0 人!',
+  '請先選學制!': '请先选学制!',
+  '目前所選學級人數為 0 人!': '目前所选学级人数为 0 人!',
+  '請先選學級!': '请先选学级!',
+  '目前所選班級人數為 0 人!': '目前所选班级人数为 0 人!',
+  '請先選班級!': '请先选学级!',
+  '全校人數超過所購買授權數,無法使用': '全校人数超过所购买授权数,无法使用',
+  全部收回成功: '全部收回成功',
+
+  //老師帳號分配空間授權控件teachermgmt/index.vue 空間欄位部分
+  空間分配:'空间分配',
+  確定收回所有空間:'确定收回所有空间',
+  '確定後全部每位教師都直接設置為0GB。':'确定后全部每位教师都直接设置为0GB。',
+  保存提醒:'保存提醒',
+  '当前空間数据尚未保存。如果關閉,修改的数据将不会保存!':'当前空間数据尚未保存。如果關閉,修改的数据将不会保存!',
+  回收空間:'回收空间',
+  保存變更:'保存变更',
+  空間分配狀態:'空间分配状态',
+  總空間量:'总空间量:',
+  單人固定容量分配:'单人固定容量分配',
+  目前可被分配總量:'目前可被分配总量',
+  至:'至',
+  每人分配:'每人分配',
+  當前勾選之教師帳號:'当前勾选之教师帐号',
+  所有:'所有',
+  進階權限:'进阶权限',
+  一般權限:'一般权限',
+  之教師帳號:'之教师帐号',
+  職稱為:'职称为',
+  的教師帳號:'的教师帐号',
+  所有教師帳號:'所有教师帐号',
+
+  //下方method區塊
+  '請手動輸入數字!': '请手动输入数字!',
+  '輸入了開頭為0的數字,請重新輸入!': '输入了开头为0的数字,请重新输入!',
+  回收成功: '回收成功',
+  更新成功: '更新成功',
+  超出該校使用空間: '超出该校使用空间',
+  有不存在老師的ID: '有不存在老师的ID',
+  保存失敗: '保存失败',
+  '您未進行任何個別變更或批次套用,無需保存': '您未进行任何个别变更或批次套用,无需保存',
+  '超出剩餘空間量,套用失敗': '超出剩余空间量,套用失败',
+  '套用完成,記得按保存': '套用完成,记得按保存',
+  '先輸入有效數字,再進行套用': '先输入有效数字,再进行套用',
+  套用完成: '套用完成',
+  '先輸入有效數字,並進行勾選,再套用': '先输入有效数字,并进行勾选,再套用',
+
+  //store/spaceAuth.js
+  學校已使用空間:'学校已使用空间',
+  已分配給教師空間:'已分配给教师空间',
+  剩餘空間:'剩余空间'
+}

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

@@ -1,5 +1,41 @@
 export default {
     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:'申请中',
+	
 }

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

@@ -1,8 +0,0 @@
-export default {
-    //授權管理服務清單
-    "AEGMCPLY":"AClass One 週期",
-    'RYGVCPLY':'AClass One 無週期',
-    'IPALYEIY':'智慧教學服務空間',
-    '6BOPC6MD':'教與學大數據管理服務',
-    'ON6MBDOP':'智慧學校大數據管理服務'
-    }

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

@@ -1,4 +1,28 @@
 export default {
+    "home": {
+        "teacher": "教师",
+        "student": "学生",
+        "setting": "个人设定",
+        "logout": "登出",
+        "joinClass": "加入课程",
+        "exam": "评量",
+    },
+    "public": {
+        "going": "进行中",
+        "finish": "已结束",
+        "schoolExam": "校级评测",
+        "privateExam": "个人评测",
+        "search":"请输入查询内容..."
+    },
+    "event": {
+        "allStatus": "所有活动状态",
+        "unFinished": "未完成",
+        "Fineshed": "已完成",
+        "Timeout": "已逾时",
+        "makeupExam": "可补考",
+        "makeupHw": "可补交",
+        "selectActivity":"请从列表挑选一个活动"
+    },
     "settingView-title": "个人设定",
     "teammodel-account-management": {
         "page-title": "TeamModel 帐号管理",
@@ -25,7 +49,6 @@ export default {
     "homeView-title": "首页资讯总览",
     "calenderCardTitle": "行事历",
     "recentClass": "近期上课提醒",
-
     "defaultRecentClass": "微处理机基础与应用概论",
     "defaultClassTime": "星期三 13:30 - 16:30 (第7-9节)",
     "defaultClassPlace": "第五教学楼 F504 教室",
@@ -114,8 +137,8 @@ export default {
     },
     "latestNotification": "最新通知",
     "postAt": "发布于",
-    "setting": "个人设定",
-    "logout": "登出",
+
+
     "______________": "______________",
     "eventView-title": "活动任务",
     "nextTask": "下个活动",
@@ -203,6 +226,59 @@ export default {
     },
     "exam": {
         "examLink": "试卷连结",
+        "isSubject": "科试卷",
+        "subjectNow": "当前科目",
+        "examData": "评测内容",
+        "gradeReport": "成绩报告",
+        "gradeAnalyse": "成绩分析",
+        "testpop": {
+            "title": "评量",
+            "completion": "完成度",
+            "practiceMode": "练习模式",
+            "all": "练习全部",
+            "onlywrong": "只练习答错",
+            "questions": "的题目",
+            "submitted": "交卷",
+            "finish":"已完成",
+            "showAns": "显示答案",
+            "hideAns": "隐藏答案",
+            "hint": "重点提示",
+            "previous": "上一题",
+            "next": "下一题",
+            "myAnswerSheet": "我的答题卡",
+            "exitQuizhint": "离开测验提示",
+            "exitQuizhintDe": "系统检测您尚未「交卷」,如您选择「确定」,",
+            "exitQuizhintDes": "则目前作答将不保存,下次需重新测验",
+            "cancel": "取消",
+            "ok": "确定",
+            "submitQuizhint": "交卷提示",
+            "submitQuizhintDes1": "系统检测目前您已全数作答完成,确定交卷吗?",
+            "check": "否,需再检查",
+            "conAnswer0": "目前您有",
+            "conAnswer1": "题 未作答 (详查答案卡)",
+            "conAnswer2":",请先完成题目作答!",
+            "conAnswer":"继续作答",
+            "okSubmit": "确定交卷",
+            "qNo": "题号:",
+            "myAns": "作答",
+            "correction": "正解",
+            "queNo": "题目:",
+            "myAns":"我的作答:"
+        },
+        "report": {
+            "anwser": "前往作答",
+            "noRes": "成绩尚未结算",
+            "getScore": "得分题目数",
+            "answerBack": "评测作答回顾",
+            "right": "答对",
+            "wrong": "答错",
+            "noScore": "未评分",
+            "ansRes": "作答结果",
+            "testAns": "参考答案",
+            "testAnalyse": "解析",
+            "repairSource": "补救资源",
+            "noAnalyse":"暂无解析"
+        },
         "timeoutHint": "评量活动时间已结束,逾时将以0分计算,或等待教师开放补考。",
         "contentPage": "评量内容",
         "scorePage": "成绩报告",
@@ -213,11 +289,13 @@ export default {
         "Math": "数学",
         "English": "英文",
         "score": "得分",
-        "difficulty": "考题综合难易度",
+        "difficulty": "考题综合难易度", 
         "average": "班平均分数",
         "rightNum": "我的答对题数",
         "smartComment": "智能点评",
         "keypoint": "建议复习知识点:",
+
+
         "chart": {
             "scoreDistribution": "评量成绩分布图",
             "participant": "应考人数:",
@@ -234,32 +312,7 @@ export default {
         "analysis": "解析",
         "correctRate": "答对率",
         "relatedAQues": "关联题目",
-        "testpop": {
-            "title": "评量",
-            "completion": "完成度",
-            "practiceMode": "练习模式",
-            "all": "练习全部",
-            "onlywrong": "只练习答错",
-            "questions": "的题目",
-            "submitted": "交卷",
-            "showAns": "显示答案",
-            "hideAns": "隐藏答案",
-            "hint": "重点提示",
-            "previous": "上一题",
-            "next": "下一题",
-            "myAnswerSheet": "我的答案卡",
-            "exitQuizhint": "离开测验提示",
-            "exitQuizhintDes": "系统检测您尚未「交卷」,如您选择「确定」,则目前作答将不保存,下次需重新测验",
-            "cancel": "取消",
-            "ok": "确定",
-            "submitQuizhint": "交卷提示",
-            "submitQuizhintDes1": "系统检测目前您已全数作答完成,确定交卷吗?",
-            "check": "否,需再检查",
-            "okSubmit": "确定交卷",
-            "qNo": "题号",
-            "myAns": "作答",
-            "correction": "正解"
-        }
+       
     },
     "informview-title": "通知总览",
     "view": "前往检视",

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

@@ -0,0 +1,38 @@
+export default {
+    menu:{
+        smartSc:'智慧校园',
+        baseSetting:'基础设置',
+        teacherMgt:'教师管理',
+        stuMgt:'学生管理',
+        classMgt:'教室管理',
+        cusSetting:'课程设置',
+        cusPlanMgt:'排课管理',
+        authMgt:'授权管理',
+        preview:'预览',
+        scSyllabus:'校本课纲',
+        scContent:'校本内容',
+        scQuBack:'校本题库',
+        kdBack:'知识点库',
+        staAna:'统计分析',
+        evAna:'学情分析',
+        scAna:'校园分析',
+        scAc:'校园活动',
+        scEv:'评量测验',
+        scVote:'投票活动',
+        scQu:'问卷调查',
+        classCus:'班级课程',
+        myClass:'我的班级',
+        myCus:'我的课程',
+        cusContent:'课程教材',
+        prtSyllabus:'个人课纲',
+        prtContent:'个人内容',
+        prtQuBack:'个人题库',
+        stuAc:'学习活动',
+        prtEv:'个人评测',
+        prtVote:'个人投票',
+        prtQu:'个人问卷',
+        selfLearn:'自主学习',
+        homework:'作业活动',
+        acRecord:'活动记录'
+    }
+}

+ 6 - 4
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/totalAnalysis.js

@@ -29,9 +29,9 @@ export default {
     ti_text4: '年级数',
     ti_text5: '班级数',
     ti_text12: '全部评测',
-    ti_text6: '考',
-    ti_text7: '考',
-    ti_text8: '平常考',
+    ti_text6: '正规考',
+    ti_text7: '模拟考',
+    ti_text8: '普通考',
     ti_text9: '其它',
     ti_text10: '模拟测验',
     ti_text11: '诊断测验',
@@ -234,6 +234,8 @@ export default {
     ql_text10: '查看数据分析',
     ql_text11: '参考答案',
     ql_text12: '答题解析',
-    ql_text13: '返回'
+    ql_text13: '返回',
+    ql_text14: '连线题',
+    ql_text15: '改错题',
 
 }

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

@@ -0,0 +1,229 @@
+export default {
+	index: {
+		item: '試題',
+		paper: '試卷',
+		addExercise: '新建習題',
+		openAll: '全部展開',
+		collapseAll: '全部折疊',
+		autoCreate: '智慧組卷',
+		manualCreate: '挑題組卷',
+		importCreate: '導題組卷',
+		backList: '返回列表'
+	},
+	filter: {
+		origin: '來源',
+		schoolBank: '校本題庫',
+		privateBank: '個人題庫',
+		all: '全部',
+		diff: '難度',
+		level: '層次',
+		type: '題型',
+		period: '學段',
+		grade: '年級',
+		subject: '科目',
+		sort: '排序',
+		createTime: '新增時間',
+		useCount: '使用次數'
+	},
+	single: '單選題',
+	multiple: '复选题',
+	judge: '判斷題',
+	complete: '填空題',
+	subjective: '問答題',
+	connector: '連線題',
+	correct: '改錯題',
+	compose: '綜合題',
+	diff1: '容易',
+	diff2: '較易',
+	diff3: '一般',
+	diff4: '較難',
+	diff5: '困難',
+	level1: '知識',
+	level2: '理解',
+	level3: '應用',
+	level4: '分析',
+	level5: '綜合',
+	level6: '評鑒',
+	noData: '暫無數據',
+	answer: '答案',
+	noAnswer: '未設定答案',
+	explain: '解析',
+	noExplain: '暫無解析',
+	knowledgePoints: '知識點',
+	noPoints: '暫未綁定知識點',
+	updateTime: '更新時間',
+	isTrue: '正確',
+	isFalse: '錯誤',
+	deleteItem: '删除',
+	editItem: '編輯',
+	confirm: '確認',
+	cancel: '取消',
+	deleteSuc: '删除成功',
+	deleteFail: '删除失敗',
+	editSuc: '修改成功',
+	backToTop: '返回頂部',
+	newExercise: {
+		newSchoolItem: '新建校本題目',
+		newPrivateItem: '新建個人題目',
+		backToBank: '返回題庫',
+		choosePeriod: '選擇學段',
+		chooseGrade: '選擇年級',
+		chooseSubject: '選擇科目',
+		gradePlaceholder: '不選擇則默認選中全部年級',
+		diff: '題目難度',
+		field: '關聯認知層次',
+		knowledge: '關聯知識點',
+		choosePoint: '選擇知識點',
+		modify:'修改',
+		type: '選擇題型',
+		stem: '題幹',
+		option: '選項',
+		singleOption: '單選選項',
+		multipleOption: '多選選項',
+		trueAnswer: '正確答案',
+		setAnswer: '設為答案',
+		addOption: '添加選項',
+		repair: '補救資源',
+		outRepair: '外部資源',
+		innerRepair: '站內資源',
+		addLink: '添加連結',
+		chooseContent: '選擇內容',
+		normalResource: '一般資源',
+		mediaResource: '影片資源',
+		linkTip: '請輸入正確的連結位址(如:https://www.baidu.com)',
+		childList: '小題清單',
+		addChild: '添加小題',
+		save: '保存',
+		cancel: '取消',
+		composeTip: '綜合題的知識點請綁定在小題上!',
+		noSchoolTip: '您當前未加入學校,無法選擇知識點!',
+		uploadErrorTip: '試題文件上傳失敗,請稍後重試!',
+		unCompleteTip: '請將題目填寫完整!',
+		typeChangeTip: '暫不支持更換題型!',
+		modalTip: '溫馨提示',
+		unSaveTip: '確認放弃保存當前試題並前往?',
+		answerTitle: '參考答案',
+		contentRelate: '內容關聯'
+	},
+	exerciseList: {
+		confirmDelete: '確認删除該試題嗎?',
+		setAnswer: '設定答案',
+		typeScore: '題型配分',
+		totalScore: '試卷總分',
+		alreadyScore: '已分配總分',
+		waitScore: '待分配分數',
+		itemNums: '道題,總分配',
+		multipleRule: '复选题(包括綜合題的小題)配分規則',
+		rule1: '默認全對得滿分',
+		rule2: '少選得一半分數,錯選或者不選不得分',
+		rule3: '少選按個數得分,錯選或者不選不得分',
+		rule4: '依照(選項數- 2 *錯選數)/選項數,負分則不得分',
+		overScoreTip: '配分已超試卷總分,請重新分配!',
+		editExercise: '編輯習題',
+		editChild: '編輯子題',
+		moveUp: '上移',
+		moveDown: '下移',
+		noAnswerTip: '請為當前客觀題設定正確答案!',
+		noOptionTip: '試題題幹或選項資訊有誤,請删除或者重新導入正確檔案!'
+	},
+	paperList: {
+		usePeriod: '適用學段',
+		useGrade: '適用年級',
+		itemCount: '題量',
+		paperAnalysis: '試卷分析',
+		totalScore: '總分',
+		score: '分',
+		paperErrorTip: '獲取試卷數據失敗!',
+		confirmDelete: '確認删除該試卷嗎?',
+		editPaper: '編輯試卷',
+		backToBank: '返回試卷庫',
+		baseInfo: '基礎資訊',
+		paperType: '試卷類型',
+		schoolBank: '學校公有庫',
+		praviteBank: '個人試卷庫',
+		paperName: '試卷名稱',
+		paperScore: '試卷總分',
+		alreadyScore: '已配分數',
+		saveRule1: '溫馨提示:當前試卷將以題目順序管道保存',
+		saveRule2: '溫馨提示:當前試卷將以題型順序管道保存',
+		tab1: '組題條件',
+		tab2: '備選題目',
+		tab3: '重新導入',
+		tab4: '導入試題',
+		tab5: '試題預覽',
+		tab6: '學生作答預覽',
+		isSaving: '保存中',
+		savePaper: '保存試卷',
+		editSuc: '編輯成功',
+		saveSuc: '保存成功',
+		saveFail: '保存失敗',
+		defaultName: '預設試卷名稱',
+		saveItemsFailTip: '試卷試題數據保存失敗!',
+		emptyNameTip: '試卷名稱不能為空!',
+		noSpaceTip: '空間已滿!',
+		noItemTip: '未選擇任何試題!',
+		isExistPaperTip: '試卷庫已存在重複名稱試卷,是否繼續保存覆蓋原試卷?',
+		cancelSaveTip: '取消保存試卷!',
+		hasNoScoreTip: '存在未配分的題目,請配分後再保存!',
+		noCompleteScoreTip: '保存前請確認試卷配分是否與試卷總分一致!',
+		hasErrorItemTip: '存在异常試題,請修改或者重新導入!',
+		cleanItems: '清空試題',
+		orderByList: '順序排列',
+		orderByType: '題型排列',
+		paperDetails: '試卷詳情',
+		paperAnalysis: '試卷分析',
+		setPaperScore: '設定試卷總分'
+	},
+	importFile: {
+		uploadSuc: '文件上傳解析成功!',
+		analysisFail: '對不起,檔案解析失敗!',
+		templateDownload: '範本下載',
+		downloadDetails: '下載範本製作詳情說明',
+		importTips: '導入注意事項',
+		tips1: '點擊上方上傳圖標選擇檔案',
+		tips2: '只支持“.docx”格式的檔案導入,請按照範本格式導入',
+		tips3: '導入題型暫時只支持單選、多選、判斷、填空、問答以及綜合題型',
+		tips4: '請保持範本語言與當前瀏覽器語言一致',
+		tips5: '更多注意事項請查看範本製作詳情說明',
+		warningTips1: '上傳格式僅支持docx,請重新上傳!',
+		warningTips2: '最大上傳大小為10M,請重新上傳!',
+		warningTips3: '試題數據讀取完成!',
+		warningTips4: '未解析出符合條件的試題,請檢查導入格式是否按照範本檔案修改!',
+		warningTips5: '抱歉,檔案解析失敗!',
+	},
+	createPaper: {
+		setAutoConditions: '設定自動出題條件',
+		origin: '題目來源',
+		schoolRate: '校本占比',
+		rateTip: '默認相同比例校本優先',
+		doAutoCreate: '開始組題',
+		random: '隨機',
+		average: '平均分配',
+		noItemTip: '題目數量不能為空!',
+		noResultTip: '未能匹配滿足條件的題目!',
+		total: '共',
+		nums: '道題',
+		spc: '道',
+		goDetails: '查看詳情',
+		noOriginTips: '請先選擇題目來源'
+	},
+	points: {
+		addPoint: '新增知識點',
+		searchPoint: '蒐索知識點',
+		noPoint: '當前科目下暫無知識點',
+		checkedPoint: '已選知識點',
+		pointName: '知識點名稱',
+		inputNewPoint: '輸入新知識點名稱',
+		noNameTips: '請輸入新知識點名稱!',
+		addSuc: '添加成功!',
+		addFail: '添加失敗!',
+		numMax1: '最多綁定',
+		numMax2: '個知識點'
+	},
+	echarts: {
+		pointPie: '試卷知識點分析圖',
+		typePie: '試卷題型分析圖',
+		diffPie: '試卷難度分析圖',
+		objectivePie: '試卷主客觀分析圖'
+	}
+}

+ 5 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/global.js

@@ -0,0 +1,5 @@
+export default{
+    examType1:'期中考試',
+    examType2:'期末考試',
+    examType3:'模擬考試'
+}

+ 6 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/index.js

@@ -19,6 +19,9 @@ import studentWeb from './studentWeb'
 import settings from './settings'
 import serviceDriveAuth from './serviceDriveAuth'
 import elui from './elui'
+import evaluation from './evaluation'
+import global from './global'
+import system from './system'
 
 export default {
   
@@ -43,6 +46,9 @@ export default {
   settings,
   serviceDriveAuth, //授權管理頁面
   elui,
+  evaluation,
+  global,
+  system,
   test: '測試',
   formConfigP: {
     input: '請輸入',

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

@@ -0,0 +1,187 @@
+export default {
+    //MgtSchoolEva.vue
+    mgtScEv: {
+        listLabel: '評測清單',
+        period: '學段:',
+        create: '新建',
+        delete: '删除',
+        edit: '編輯',
+        createTime: '施測時間:',
+        pending: '待發佈',
+        going: '進行中',
+        finish: '已結束',
+        endTime: '結束時間:',
+        stop: '立即結束',
+        evType: '測試類型:',
+        stuCount: '施測人數:',
+        nodata: '暫無評測',
+        tab1: '評測數據',
+        tab2: '評測試卷',
+        autoTips1: '此功能僅用於展示情景快速類比學生作答數據,且學生作答為隨機生成,僅供參考!',
+        autoTips2: '此功能僅用於展示情景快速類比教師評分數據,且分數為隨機生成,僅供參考!',
+        autoScore: '一鍵評分',
+        autoAnswer: '一鍵作答',
+        evSubject: '測試科目:',
+        returnTop: '返回頂部',
+        mockOk: '類比成功',
+        mockErr: '類比失敗',
+        stopTitle: '結束評測',
+        stopContent: '結束後學生將不能繼續作答,是否立即結束',
+        stopOk: '評測已結束!',
+        deleteTitle: '删除評測',
+        deleteContent: '是否確認删除',
+        deleteOk: '删除成功',
+        deleteErr: '删除失敗',
+        noJoin: '此帳號暫未加入任何學校!'
+
+    },
+
+    //創建評測校本/個人
+    createEv: {
+        createLabel: '創建評測',
+        publishEv: '發佈評測',
+        return: '返回上級',
+        baseInfo: '基礎資訊',
+        evName: '評測名稱',
+        evPeriod: '測試學段',
+        evMode: '評測模式',
+        evType: '評測類型',
+        examType: '考試類別',
+        courseType: '課程類別',
+        cusLabel1: '校本課程',
+        cusLabel2: '個人課程',
+        evTarget: '施測對象',
+        publishType: '發佈管道',
+        startTime: '開始時間',
+        sTimeHolder: '請選擇開始時間',
+        endTime: '結束時間',
+        eTimeHolder: '請選擇結束時間',
+        addSubject: '添加學科',
+        noSubject: '暫無科目,請添加科目',
+        noSubject1: '*請先選擇測試學段',
+        papersLabel: '試卷庫',
+        perviewLabel: '試卷預覽',
+        importLabel: '導入說明',
+        answerPreview: '作答預覽',
+        errTips1: '評測名稱不能為空!',
+        errTips2: '測試類型不能為空!',
+        errTips3: '評量模式不能為空!',
+        errTips4: '請設定類別!',
+        errTips5: '請設定測試類型!',
+        errTips6: '請設定測試對象!',
+        errTips7: '請設定發佈管道!',
+        errTips8: '請設定發佈時間!',
+        errTips9: '請設定結束時間!',
+        errTips10: '請設定測試學段!',
+        stPaperTitle: '挑選試卷',
+        stPaperContent: '是否確認挑選',
+        inDev: '功能正在開發中,敬請期待!',
+        formWarning: '請先完善評測基礎資訊!',
+        paperWarning: '請挑選或導入試卷!',
+        paperWarning1: '還沒有試卷,請挑選或導入試卷!',
+        pdWarning: '請添加測試科目!',
+        publishOk: '評測發佈成功!',
+        togglePeriod: '切換學段',
+        togglePdTip1: '您已添加',
+        togglePdTip2: '的測試科目,如果現在切換學段會清空已選科目,確定切換學段嗎?',
+        toggleOkText: '切換',
+        delPdTitle: '删除科目',
+        delPdContent: '是否確認删除',
+        delOk: '删除成功',
+        pdTips: '請先選擇測試學段!',
+        defaultPaper: '(請先挑選或導入試卷)',
+    },
+    //ManualPaper.vue
+
+    manual: {
+        source: '來源:',
+        sourceP: '個人試卷庫',
+        sourceS: '校本試卷庫',
+        pdLabel: '學段:',
+        subjectLabel: '學科:',
+        gradeLabel: '年級:',
+        fitPd: '適用學段:',
+        fitSubject: '適用科目:',
+        quCount: '題量:',
+        useCount: '使用次數:',
+        stdPaper: '已選試卷',
+        stPaper: '選擇試卷',
+        previewPaper: '預覽試卷',
+        noPaper: '暫無對應的試卷',
+        noPaper1: '暫無試卷'
+
+    },
+    //PaperScore.vue、Scoring.vue
+
+    score: {
+        stuName: '學生姓名:',
+        score: '總分:',
+        scoreUnit: '分',
+        saveScore: '保存打分',
+        showAns: '顯示答案',
+        hideAns: '隱藏答案',
+        showQu: '顯示題幹',
+        hideQu: '隱藏題幹',
+        quIndex: '題號:',
+        quIndex1: '題號',
+        fullScore: '滿分',
+        zeroScore: '零分',
+        zeroScore1: '0分',
+        stuAns: '【學生作答】',
+        mark: '批註',
+        quAns: '【答ㅤ案】',
+        noAnswer: '未設定答案',
+        anaLabel: '【解ㅤ析】',
+        noAna: '暫無解析',
+        kdLabel: '【知識點】',
+        noKd: '暫未綁定知識點',
+        sQuLabel1: '【小題',
+        sQuLabel2: '】',
+        quIndexLabel: '【題號',
+        nextStu: '下一位學生>>>',
+        markOk: '批註成功!',
+        markErr: '批註失敗!',
+        isFullTips: '已經是小題滿分了',
+        isZeroTips: '已經是零分了',
+        saveScoreOk: '成績保存成功!',
+        saveSocreErr: '成績保存失敗!',
+        zero: '零',
+        one: '一',
+        two: '二',
+        three: '三',
+        four: '四',
+        five: '五',
+        six: '六',
+        seven: '七',
+        eight: '八',
+        nine: '九',
+        ten: '十',
+        hundred: '百',
+        thousand: '千',
+        tenThd: '萬',
+        hMillion: '億',
+        noStuAns: '未作答',
+        noStuAns1: '暫未作答',
+        trueAns: '正確',
+        falseAns: '錯誤',
+        //Scoring.vue
+
+        subjectLabel: '學科:',
+        gradeLabel: '年級:',
+        classLabel: '班級:',
+        stuLabel: '學生:',
+        scoreView: '分數概覽',
+        scoring: '試卷評分',
+        classNoStu: '班級暫無學生',
+        status1: '暫未作答',
+        status2: '前往評分',
+        status3: '查看分數',
+        column1: '姓名',
+        column2: '總分',
+        column3: '狀態',
+        finishScore: '已完成所有學生作答的評分!',
+        unableScore: '學生尚未作答,無法評分',
+        stStuWarning: '請先選擇學生!'
+    }
+
+}

+ 96 - 15
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/schoolBaseInfo.js

@@ -1,5 +1,5 @@
 export default {
-  // SystemSetting.vue
+  //SystemSetting.vue
   schoolNameLabel: '學校名稱:',
   periodSettingLabel: '學制設定',
   order: '依建立時間排序',
@@ -20,7 +20,7 @@ export default {
   delete: '删除',
   ssTips1: '點擊設定名稱',
   ssTips2: '至少需要保留一項!',
-  ssTips3: '保存/ 修改資訊成功!',
+  ssTips3: '保存/修改資訊成功!',
   ssTips4: '已有相同的名字,請重新設定名字!',
   ssTips5: '學科數已達上限!',
   ssTips6: '年級數已達上限!',
@@ -36,14 +36,50 @@ export default {
   presetSubject1: '語文',
   presetSubject2: '數學',
   presetSubject3: '英語',
+  pdHolder: '設定學段…',
+  tmzLabel: '時區設定:',
+  tmzHolder: '請設定時區…',
+  campusHolder: '請設定校區',
+  setCampus: '請設定校區',
+  smHolder: '設定學期…',
+  subjectHolder: '設定學科…',
+  noSubject: '暫無學科',
+  anaLabel: '學情設定',
+  exTypeLabel: '考試類型:',
+  examHolder: '設定考試類型…',
+  noExam: '暫無考試類型',
+  eugenicsLabel: '優生率:',
+  eugenicsTips: '優生率計算管道',
+  incomeLable: '進線率:',
+  incomeTips: '(進線人數)/(報名人數)×100%',
+  touchLabel: '踩線生:',
+  touchTips: '踩線生計算管道',
+  scoreUnit: '分',
+  delExamTitle: '删除考試類型',
+  delGradeTitle: '删除年級',
+  delSubjectTitle: '删除學科',
+  delPdTitle: '删除學段',
+  delCampusTitle: '删除校區',
+  delSmTitle: '删除學期',
+  delContent: '後與之關聯的數據將不能査詢,確認删除嗎?',
+  campusWarning: '對不起,校區數量已到系統授權最多數量!',
+  authWarning: '您暫無此操作許可權!',
+  saveErr: '保存失敗!',
+  saveWarning: '保存提醒',
+  leaveText: '離開',
+
+
+  //ClassroomSetting.vue
 
-  // ClassroomSetting.vue
   classroomList: '教室清單',
+  pdLabel: '學段:',
   listOrder: '依創建時間排序',
+  listOrder1: '依教室編號排序',
+  listOrder2: '依智慧教室排序',
   classroomAttr: '教室内容',
   classroomCode: '教室編碼',
   classroomName: '教室名稱',
-  headmaster: '班主任',
+  headmaster: '班主任',
   setPeriod: '選擇教室學段',
   setGrade: '設定教室年級',
   setHiteachCode: 'HiTeach軟件序號',
@@ -52,9 +88,9 @@ export default {
   uploadPlan: '上傳平面圖',
   hiteachList: 'HiTeach序號清單',
   codeSearchHolder: '請輸入關鍵字蒐索',
-  classroomCodeHolder: '請輸入教室編碼…',
-  classroomNameHolder: '請輸入教室名稱…',
-  headmasterHolder: '請指定教師名稱…',
+  classroomCodeHolder: 'eg: HBCN0101',
+  classroomNameHolder: 'eg:一年級一班',
+  headmasterHolder: '可通過名字蒐索…',
   hiTeachHolder: '請在右側清單選擇可用序號…',
   noHiTeachTips: '沒有可用序號',
   suportCanvas: '當前瀏覽器不支持Canvas,請更換瀏覽器再試試。',
@@ -63,23 +99,68 @@ export default {
   moreAuth: '大量授權',
   yes: '是',
   no: '否',
+  hiTeach: 'HiTeach序號',
   csTips1: '已放大至最大倍數!',
   csTips2: '已縮小至最小倍數!',
   csTips3: '保存成功!',
   csTips4: '至少需要保留一項!',
   csTips5: '上傳成功!',
   csTips6: '此序號已綁定到教室!',
-  csTips7: '除成功!',
+  csTips7: '除成功!',
   presetClassroomName: '教室',
   presetHeadmaster: '未指定班主任',
-  sokapp:'蘇格拉底議課',
-  remotcls:'遠距教室服務',
-  sokdesk:'蘇格拉底桌面',
-  sokrpt:'蘇格拉底報告',
-  sokvdo:'蘇格拉底影片',
-  ezs:'錄播系統',
+  sokapp: '蘇格拉底議課',
+  remotcls: '遠距教室服務',
+  sokdesk: '蘇格拉底案頭',
+  sokrpt: '蘇格拉底報告',
+  sokvdo: '蘇格拉底影片',
+  ezs: '錄播系統',
   '3222NIYD': 'ezStation 2',
   'J223IZ6M': 'HiTeach STD',
   '3222C6D2': 'HiTeach TBL',
-  'J223IZAM': 'HiTeach PRO'
+  'J223IZAM': 'HiTeach PRO',
+  tmdClass: 'TEAM Model智慧教室',
+  normalClass: '普通教室',
+  dClass: '專科教室',
+  tab1: '基礎資訊',
+  tab2: '學生名單',
+  tab3: '位置設定',
+  tab4: '關聯Hiteach',
+  classAttr: '教室内容',
+  relationHi: '關聯Hiteach設備',
+  hiFilter1: '顯示所有版本的Hiteach',
+  hiFilter2: '僅顯示Hiteach Standard版本',
+  hiFilter3: '僅顯示Hiteach Pro版本',
+  hiFilter4: '僅顯示Hiteach TBL版本',
+  single: '單一',
+  mach: '大量',
+  expireLabel: '序號到期日',
+  related: '已被關聯',
+  noEnable: '此序號尚未啟用',
+  onClassStu: '專科教室沒有固定學生名單!',
+  classNoErr: '教室編碼不能為空!',
+  classNoErr1: '教室編碼只能由字母和數位組成!',
+  classAttr1: '常規教室(有固定學生)',
+  classAttr2: '專科教室(無固定學生)',
+  nameWarning: '請輸入教室名稱',
+  typeWarning: '請設定教室内容',
+  gradeWarning: '請設定年級',
+  expireLabel1: '已到期',
+  expireLabel2: '無限期',
+  findStuErr: '査詢班級學生名單失敗!',
+  noStdClass: '當前班級未選中,不能移動!',
+  formWarning: '請先完善班級資訊再保存!',
+  bindingErr: 'Hiteach綁定失敗!',
+  delClass: '删除班級',
+  saveClassWarning: '當前教室數據尚未保存。如果離開,修改的數據將不會保存!',
+  addStuBtn: '添加學生',
+  delStuBtn: '移除學生',
+  editSeat: '修改座號',
+  removeTile: '移除提醒',
+  removeContent: '是否確認移除',
+  removeOk: '移除成功',
+  removeErr: '移除失敗',
+  deLink: '解除關聯',
+  link: '關聯',
+  confirmDelink:'請問您確定要解除關聯'
 }

+ 182 - 7
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/serviceDriveAuth.js

@@ -1,8 +1,183 @@
 export default {
-//授權管理服務清單
-"AEGMCPLY":"AClass One 週期",
-'RYGVCPLY':'AClass One 無週期',
-'IPALYEIY':'智慧教學服務空間',
-'6BOPC6MD':'教與學大數據管理服務',
-'ON6MBDOP':'智慧學校大數據管理服務'
-}
+  //ServiceList.vue
+  AEGMCPLY: 'AClass One',
+  RYGVCPLY: 'AClass One',
+  IPALYEIY: '智慧教學服務空間',
+  '6BOPC6MD': '教與學大數據管理服務',
+  ON6MBDOP: '智慧學校大數據管理服務',
+  服務授權列表: '服務授權列表',
+  智慧教室授權管理: '智慧教室授權管理',
+  未購買: '未購買',
+  已購買: '已購買',
+  '服務啟用 / 到期日:': '服務啟用 / 到期日:',
+  剩餘: '剩餘',
+  天: '天',
+  無週期授權數量: '無週期授權數量',
+  有週期授權數量: '有週期授權數量',
+  固定分配數: '固定分配數',
+  動態分配數: '動態分配數',
+  剩餘分配數: '剩餘分配數',
+  總使用率: '總使用率',
+  詳細服務內容: '詳細服務內容',
+  管理AClassOne授權: '管理AClassOne授權',
+
+  //HiteachAuthList.vue
+  確定解除授權: '確定解除授權',
+  當前您所選中的PC: '當前您所選中的PC',
+  ',確定解除授權?': ',確定解除授權?',
+  '解除授權後,可在教室中的電腦再次進行綁定授權。': '解除授權後,可在教室中的電腦再次進行綁定授權。',
+  取消: '取消',
+  確定: '確定',
+  Hiteach序號數: 'Hiteach序號數',
+  大量: '大量',
+  單一: '單一',
+  授權: '授權',
+  可啟用裝置數: '可啟用裝置數',
+  已啟用裝置數: '已啟用裝置數',
+  管理Hiteach教室: '管理Hiteach教室',
+  暂无数据: '暂无数据',
+  序號到期日: '序號到期日:',
+  無到期日: '無到期日',
+  已到期: '已到期',
+  序號使用狀況: '序號使用狀況:',
+  未命名機台: '未命名機台',
+  解除授權: '解除授權',
+  顯示全部: '顯示全部',
+  '僅顯示HiTeach STD序號': '僅顯示HiTeach STD序號',
+  '僅顯示HiTeach PRO序號': '僅顯示HiTeach PRO序號',
+  '僅顯示HiTeach TBL序號': '僅顯示HiTeach TBL序號',
+  僅顯示已完成綁定的序號: '僅顯示已完成綁定的序號',
+  僅顯示已到期序號: '僅顯示已到期序號',
+  已成功解除授權: '已成功解除授權',
+
+  //SpaceStatus.vue
+  智慧教學服務空間狀態: '智慧教學服務空間狀態',
+  分配教學空間: '分配教學空間',
+  空間總數: '空間總數',
+  已使用空間總數: '已使用空間總數',
+  空間使用狀況: '空間使用狀況',
+  未使用空間數: '未使用空間數',
+  未使用空間比率: '未使用空間比率',
+  可使用空間數: '可使用空間數',
+  可使用空間比率: '可使用空間比率',
+  當前空間到期日: '當前空間到期日',
+  '基本 1GB 永久授權': '基本 1GB 永久授權',
+  '到期後將變更為IES基本空間,超出基本空間值將被收回': '到期後將變更為IES基本空間,超出基本空間值將被收回',
+  購買記錄: '購買記錄',
+  醍摩豆智慧教學服務空間: '醍摩豆智慧教學服務空間',
+  訂單日期: '訂單日期:',
+  到期日: '到期日:',
+  添購其他服務: '添購其他服務',
+  '空間已到期,超過僅供檢視': '空間已到期,超過僅供檢視',
+
+  //SpaceChart.vue
+  文件: '文件',
+  永久授權: '永久授權',
+  影片: '影片',
+  圖片: '圖片',
+  題目與試卷: '題目與試卷',
+  其他: '其他',
+  學生使用: '學生使用',
+  已分配至教師: '已分配至教師',
+  未使用: '未使用',
+  空間比率: '空間比率',
+  空間: '空間',
+  空間數: '空間數:',
+  空間比率: '空間比率:',
+
+  //學生帳號頁面的授權管理控件 student-account / AclassOneAuth.vue
+  確定收回所有授權: '確定收回所有授權',
+  '收回授權後使用數會直接設置為0,如欲給予授權可針對目標對象進行套用。': '收回授權後使用數會直接設置為0,如欲給予授權可針對目標對象進行套用。',
+  服務授權管理: '服務授權管理',
+  AClassONE智慧學伴服務授權: 'AClassONE智慧學伴服務授權',
+  '賦予持有該服務授權的學生TEAM Modal ID使用AClassONE智慧學伴App的權限': '賦予持有該服務授權的學生TEAM Modal ID使用AClassONE智慧學伴App的權限',
+  總授權數: '總授權數',
+  本次套用數: '本次套用數',
+  已使用數: '已使用數',
+  授權總覽: '授權總覽',
+  授權管理: '授權管理',
+  已購授權總數: '已購授權總數:',
+  note: '固定分配之授權由校方統一設置,使用者請於授權管理分頁進行授權對象的設定。動態取用之授權每日23:59:59將自動回收,學生可於次日再次啟用。',
+  快速套用授權: '快速套用授權',
+  套用至所有當前勾選項目: '套用至所有當前勾選項目',
+  套用: '套用',
+  套用至: '套用至',
+  套用至當前勾選目標第: '套用至當前勾選目標第',
+  項至第: '項至第',
+  項: '項',
+  所有項目: '所有項目',
+  未关联班级: '未关联班级',
+  套用至全校所有項目: '套用至全校所有項目',
+  共: '共',
+  個: '個',
+  '大於總授權數,無法使用': '大於總授權數,無法使用',
+  添購其他授權: '添購其他授權',
+  收回所有授權: '收回所有授權',
+  保存所有變更: '保存所有變更',
+  選擇班級: '選擇班級',
+
+  //下方method區塊
+  固定分配授權數: '固定分配授權數',
+  今日動態取用數: '今日動態取用數',
+  今日可用授權數: '今日可用授權數',
+  '請先選擇套用,再按保存': '請先選擇套用,再按保存',
+  '保存成功,本次尚無新增授權數量': '保存成功,本次尚無新增授權數量',
+  '保存成功,本次新增': '保存成功,本次新增',
+  個固定分配: '個固定分配',
+  '保存失敗,超過可用授權數!': '保存失敗,超過可用授權數!',
+  全部收回成功: '全部收回成功',
+  請先勾選欲授權之學生: '請先勾選欲授權之學生',
+  '請設定有效的目標項 !': '請設定有效的目標項 !',
+  '目前所選學制人數為 0 人!': '目前所選學制人數為 0 人!',
+  '請先選學制!': '請先選學制!',
+  '目前所選學級人數為 0 人!': '目前所選學級人數為 0 人!',
+  '請先選學級!': '請先選學級!',
+  '目前所選班級人數為 0 人!': '目前所選班級人數為 0 人!',
+  '請先選班級!': '請先選班級!',
+  '全校人數超過所購買授權數,無法使用': '全校人數超過所購買授權數,無法使用',
+  全部收回成功: '全部收回成功',
+
+  //老師帳號分配空間授權控件  teachermgmt/index.vue 空間欄位部分
+  空間分配: '空間分配',
+  確定收回所有空間: '確定收回所有空間',
+  '確定後全部每位教師都直接設置為0GB。': '確定後全部每位教師都直接設置為0GB。',
+  保存提醒: '保存提醒',
+  '当前空間数据尚未保存。如果關閉,修改的数据将不会保存!': '当前空間数据尚未保存。如果關閉,修改的数据将不会保存!',
+  回收空間: '回收空間',
+  保存變更: '保存變更',
+  空間分配狀態: '空間分配狀態',
+  總空間量: '總空間量:',
+  單人固定容量分配: '單人固定容量分配',
+  目前可被分配總量: '目前可被分配總量',
+  至: '至',
+
+  每人分配: '每人分配',
+  當前勾選之教師帳號: '當前勾選之教師帳號',
+  所有: '所有',
+  進階權限: '進階權限',
+  一般權限: '一般權限',
+  之教師帳號: '之教師帳號',
+  職稱為: '職稱為',
+  的教師帳號: '的教師帳號',
+  所有教師帳號: '所有教師帳號',
+
+  //下方method區塊
+  '請手動輸入數字!': '請手動輸入數字!',
+  '輸入了開頭為0的數字,請重新輸入!': '輸入了開頭為0的數字,請重新輸入!',
+  回收成功: '回收成功',
+  更新成功: '更新成功',
+  超出該校使用空間: '超出該校使用空間',
+  有不存在老師的ID: '有不存在老師的ID',
+  保存失敗: '保存失敗',
+  '您未進行任何個別變更或批次套用,無需保存': '您未進行任何個別變更或批次套用,無需保存',
+  '超出剩餘空間量,套用失敗': '超出剩餘空間量,套用失敗',
+  '套用完成,記得按保存': '套用完成,記得按保存',
+  '先輸入有效數字,再進行套用': '先輸入有效數字,再進行套用',
+  套用完成: '套用完成',
+  '先輸入有效數字,並進行勾選,再套用': '先輸入有效數字,並進行勾選,再套用',
+
+  //store/spaceAuth.js
+  學校已使用空間:'學校已使用空間',
+  已分配給教師空間:'已分配給教師空間',
+  剩餘空間:'剩餘空間'
+}

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

@@ -1,5 +1,40 @@
 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: '申請中',
 }

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

@@ -1,4 +1,28 @@
 export default {
+    "home": {
+        "teacher": "教師",
+        "student": "學生",
+        "setting": "個人設定",
+        "logout": "登出",
+        "joinClass": "加入課程",
+        "exam": "評量",
+    },
+    "public": {
+        "going": "進行中",
+        "finish": "已結束",
+        "schoolExam": "校級評測",
+        "privateExam": "個人評測",
+        "search": "請輸入查詢內容..."
+    },
+    "event": {
+        "allStatus": "所有活動狀態",
+        "unFinished": "未完成",
+        "Fineshed": "已完成",
+        "Timeout": "已逾時",
+        "makeupExam": "可補考",
+        "makeupHw": "可補交",
+        "selectActivity": "請從列表挑選一個活動"
+    },
     "settingView-title": "個人設定",
     "teammodel-account-management": {
         "page-title": "TeamModel 帳號管理",
@@ -23,7 +47,7 @@ export default {
         "Habook-smart-school": "Habook智慧校園"
     },
     "homeView-title": "首頁資訊總覽",
-    "calenderCardTitle": "行事",
+    "calenderCardTitle": "行事",
     "recentClass": "近期上課提醒",
     "defaultRecentClass": "微處理機基礎與應用概論",
     "defaultClassTime": "星期三 13:30 - 16:30 (第7-9節)",
@@ -113,8 +137,6 @@ export default {
     },
     "latestNotification": "最新通知",
     "postAt": "發佈於",
-    "setting": "個人設定",
-    "logout": "登出",
     "______________": "______________",
     "eventView-title": "活動任務",
     "nextTask": "下個活動",
@@ -167,7 +189,7 @@ export default {
         "reVote": "再次投票",
         "voteSuccess": "投票成功",
         "voteDes": "活動結束後,即可檢視大家的投票結果",
-        "timeoutHint": "投票時間已過,無法再進行投票,敬請留意教師發投票結果!",
+        "timeoutHint": "投票時間已過,無法再進行投票,敬請留意教師發投票結果!",
         "voteResult": "本次投票結果為:",
         "voteDesDefault": "請選擇一個想要的方案:"
     },
@@ -202,6 +224,59 @@ export default {
     },
     "exam": {
         "examLink": "試卷連結",
+        "isSubject": "科試卷",
+        "subjectNow": "當前科目",
+        "examData": "評測內容",
+        "gradeReport": "成績報告",
+        "gradeAnalyse": "成績分析",
+        "testpop": {
+            "title": "評量",
+            "completion": "完成度",
+            "practiceMode": "練習模式",
+            "all": "練習全部",
+            "onlywrong": "只練習答錯",
+            "questions": "的題目",
+            "submitted": "交卷",
+            "finish": "已完成",
+            "showAns": "顯示答案",
+            "hideAns": "隱藏答案",
+            "hint": "重點提示",
+            "previous": "上一題",
+            "next": "下一題",
+            "myAnswerSheet": "我的答題卡",
+            "exitQuizhint": "離開測驗提示",
+            "exitQuizhintDe": "系統檢測您尚未「交卷」,如您選擇「確定」,",
+            "exitQuizhintDes": "則目前作答將不保存,下次需重新測驗",
+            "cancel": "取消",
+            "ok": "確定",
+            "submitQuizhint": "交卷提示",
+            "submitQuizhintDes1": "系統檢測目前您已全數作答完成,確定交卷嗎?",
+            "check": "否,需再檢查",
+            "conAnswer0": "目前您有",
+            "conAnswer1": "題 未作答 (詳查答案卡)",
+            "conAnswer2": ",請先完成題目作答!",
+            "conAnswer": "繼續作答",
+            "okSubmit": "確定交卷",
+            "qNo": "題號:",
+            "myAns": "作答",
+            "correction": "正解",
+            "queNo": "題目:",
+            "myAns": "我的作答:"
+        },
+        "report": {
+            "anwser": "前往作答",
+            "noRes": "成績尚未結算",
+            "getScore": "得分題目數",
+            "answerBack": "評測作答回顧",
+            "right": "答對",
+            "wrong": "答錯",
+            "noScore": "未評分",
+            "ansRes": "作答結果",
+            "testAns": "參考答案",
+            "testAnalyse": "解析",
+            "repairSource": "補救資源",
+            "noAnalyse": "暫無解析"
+        },
         "timeoutHint": "評量活動時間已結束,逾時將以0分計算,或等待教師開放補考。",
         "contentPage": "評量內容",
         "scorePage": "成績報告",
@@ -217,6 +292,8 @@ export default {
         "rightNum": "我的答對題數",
         "smartComment": "智能點評",
         "keypoint": "建議複習知識點:",
+
+
         "chart": {
             "scoreDistribution": "評量成績分佈圖",
             "participant": "應考人數:",
@@ -233,32 +310,7 @@ export default {
         "analysis": "解析",
         "correctRate": "答對率",
         "relatedAQues": "關聯題目",
-        "testpop": {
-            "title": "評量",
-            "completion": "完成度",
-            "practiceMode": "練習模式",
-            "all": "練習全部",
-            "onlywrong": "只練習答錯",
-            "questions": "的題目",
-            "submitted": "交卷",
-            "showAns": "顯示答案",
-            "hideAns": "隱藏答案",
-            "hint": "重點提示",
-            "previous": "上一題",
-            "next": "下一題",
-            "myAnswerSheet": "我的答案卡",
-            "exitQuizhint": "離開測驗提示",
-            "exitQuizhintDes": "系統檢測您尚未「交卷」,如您選擇「確定」,則目前作答將不保存,下次需重新測驗",
-            "cancel": "取消",
-            "ok": "確定",
-            "submitQuizhint": "交卷提示",
-            "submitQuizhintDes1": "系統檢測目前您已全數作答完成,確定交卷嗎?",
-            "check": "否,需再檢查",
-            "okSubmit": "確定交卷",
-            "qNo": "題號",
-            "myAns": "作答",
-            "correction": "正解"
-        }
+
     },
     "informview-title": "通知總覽",
     "view": "前往檢視",
@@ -294,18 +346,17 @@ export default {
         "name": "姓名",
         "group": "組別"
     },
-    "calendar-title": "行事曆 - 109學年度第二學期",
-    "today":"今天",
-    "importEvent":"校園班級要事",
-   
-    "deadlineTasks":"截止活動任務",
-    "schedule":"表定課表",
-    "des":"描述",
-    "time":"時間",
-    "place":"地點",
-    "course":"課程",
-    "mockcourses":["閱讀與寫作","英文簡報","電子電路專題實驗","計算機概論","微處理機實驗"],
-    "importEventTitle":"校園班級要事",
-    "Thatday":"當日",
-    "deadlineTasksTitle":"當日截止未完成活動任務"
+    "calendar-title": "行事歷 - 109學年度第二學期",
+    "today": "今天",
+    "importEvent": "校園班級要事",
+    "deadlineTasks": "截止活動任務",
+    "schedule": "表定課表",
+    "des": "描述",
+    "time": "時間",
+    "place": "地點",
+    "course": "課程",
+    "mockcourses": ["閱讀與寫作", "英文簡報", "電子電路專題實驗", "計算機概論", "微處理機實驗"],
+    "importEventTitle": "校園班級要事",
+    "Thatday": "當日",
+    "deadlineTasksTitle": "當日截止未完成活動任務"
 }

+ 38 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/system.js

@@ -0,0 +1,38 @@
+export default {
+    menu: {
+        smartSc: '智慧校園',
+        baseSetting: '基礎設定',
+        teacherMgt: '教師管理',
+        stuMgt: '學生管理',
+        classMgt: '教室管理',
+        cusSetting: '課程設置',
+        cusPlanMgt: '排課管理',
+        authMgt: '授權管理',
+        preview: '預覽',
+        scSyllabus: '校本課綱',
+        scContent: '校本內容',
+        scQuBack: '校本題庫',
+        kdBack: '知識點庫',
+        staAna: '統計分析',
+        evAna: '學情分析',
+        scAna: '校園分析',
+        scAc: '校園活動',
+        scEv: '評量測驗',
+        scVote: '投票活動',
+        scQu: '問卷調查',
+        classCus: '班級課程',
+        myClass: '我的班級',
+        myCus: '我的課程',
+        cusContent: '課程教材',
+        prtSyllabus: '個人課綱',
+        prtContent: '個人內容',
+        prtQuBack: '個人題庫',
+        stuAc: '學習活動',
+        prtEv: '個人評測',
+        prtVote: '個人投票',
+        prtQu: '個人問卷',
+        selfLearn: '自主學習',
+        homework: '工作活動',
+        acRecord: '活動記錄'
+    }
+}

+ 231 - 231
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/totalAnalysis.js

@@ -1,239 +1,239 @@
 export default {
-    // EvaluationList.vue
-    text1: '歷次考試匯總',
-    text2: '次數',
-    text3: '更多篩選',
-    text4: '輸入考試名稱...',
-    text5: '當前篩選條件',
-    text6: '當前條數',
-    text7: '參與人數',
-    text8: '考試日期',
-    text9: '無',
-    condition1: '關註學段',
-    condition2: '關註年級',
-    condition3: '學年期',
-    condition4: '考試類型',
-    condition5: '考試範圍',
-    condition6: '評測來源',
-    condition7: '考試學科',
-
-    // totalIndex.vue
-    ti_title1: '基本資料統計',
-    ti_title2: '評測資料統計',
-    ti_title3: '學科對比統計',
-    ti_title4: '年級優生率統計',
-    ti_title5: '評測清單數據',
-    ti_text1: '教師人數',
-    ti_text2: '學生人數',
-    ti_text3: '學段數',
-    ti_text4: '年級數',
+	// EvaluationList.vue
+	text1: '歷次考試匯總',
+	text2: '次數',
+	text3: '更多篩選',
+	text4: '輸入考試名稱...',
+	text5: '當前篩選條件',
+	text6: '當前條數',
+	text7: '參與人數',
+	text8: '考試日期',
+	text9: '無',
+	condition1: '關註學段',
+	condition2: '關註年級',
+	condition3: '學年期',
+	condition4: '考試類型',
+	condition5: '考試範圍',
+	condition6: '評測來源',
+	condition7: '考試學科',
+
+	// totalIndex.vue
+	ti_title1: '基本資料統計',
+	ti_title2: '評測資料統計',
+	ti_title3: '學科對比統計',
+	ti_title4: '年級優生率統計',
+	ti_title5: '評測清單數據',
+	ti_text1: '教師人數',
+	ti_text2: '學生人數',
+	ti_text3: '學段數',
+	ti_text4: '年級數',
 	ti_text5: '班級數',
 	ti_text12: '全部評測',
-	ti_text6: '考',
-	ti_text7: '考',
-	ti_text8: '平常考',
+	ti_text6: '正規考',
+	ti_text7: '模擬考',
+	ti_text8: '普通考',
 	ti_text9: '其它',
 	ti_text10: '模擬測驗',
 	ti_text11: '診斷測驗',
-    echarts_text1: '最高值',
-    echarts_text2: '最低值',
-    echarts_text3: '平均值',
-    echarts_text4: '班級平均',
-    echarts_text5: '年級平均',
-    echarts_text6: '班級總人數',
-    echarts_text7: '進線總人數',
-    echarts_text8: '進線率',
-    echarts_text9: '當前年級',
-    echarts_text10: '篩選',
-    echarts_text11: '施測時間',
-    echarts_text12: '應參與人數',
-    echarts_text13: '實際參與人數',
-    echarts_text14: '參與率',
-    echarts_text15: '平均分',
-    echarts_text16: '成就指數',
-    echarts_text17: '優生率',
-    echarts_text18: '優生人數',
-
-    // Base Info
-    base_name: '姓名',
-    base_class: '班级',
-    base_id: '座號',
-    base_score: '分數',
-
-    // ExamList.vue
-    newest: '最新測驗',
-    more: '查看更多',
-
-    // index.vue
-    module1: '成績分析',
-    module2: '落点分析',
-    module3: '試題分析',
-    module4: '知識点掌握',
-    module5: '認知層次掌握',
-    exportTable: '匯出表格',
-    currentSubject: '當前科目',
-
-    // AchievementAnalysis.vue
-    ach_title1: '及格率統計',
-    ach_title2: '均分分析',
-    ach_title3: '進線人數統計',
-    ach_title4: '進線情况統計',
-    ach_title5: '進線率統計',
-    ach_title6: '預警統計',
-    ach_title7: '排名統計',
-    ach_title8: '均分分析',
-    ach_text1: '及格率',
-    ach_text2: '年级',
-    ach_text3: '區級',
-    ach_text4: '班級平均分',
-    ach_text5: '校級平均分',
-    ach_text6: '區級平均分',
-    ach_text7: '班級總人數',
-    ach_text8: '進線總人數',
-    ach_text9: '進線率',
-    ach_text10: '當前班級',
-    ach_text11: '總人數',
-    ach_text12: '返回',
-
-    ach_table_text1: '年級排名',
-    ach_table_text2: '總分',
-    ach_table_text3: '平均分',
-    ach_table_text4: '標準差',
-    ach_table_text5: '超均率',
-    ach_table_text6: '進線',
-    ach_table_text7: '踩線',
-    ach_table_text8: '班級排名',
-    ach_table_text9: '年級排名',
-    ach_table_text10: '區級排名',
-    ach_table_text11: '班級PR排名',
-    ach_table_text12: '年級PR排名',
-    ach_table_text13: '區級PR排名',
-    ach_table_text14: '進步班級',
-    ach_table_text15: '退步班級',
-    ach_table_text16: '穩定班級',
-
-    ach_chart_text1: '排序方式',
-    ach_chart_text2: '默認排序',
-    ach_chart_text3: '分數從高到低',
-    ach_chart_text4: '分數從低到高',
-
-    // ScatterAnalysis.vue
-    sca_title1: '學生學習力分佈',
-    sca_title2: '學生穩定度統計表',
-    sca_text1: '區域',
-    sca_text2: '區域特性',
-    sca_text3: '所占人數',
-    sca_text4: '學生',
-    sca_text5: '學習良好,穩定度高',
-    sca_text6: '粗心大意,不細心造成錯誤',
-    sca_text7: '學習尚且穩定,需要再用功',
-    sca_text8: '偶爾粗心,準備不够充分',
-    sca_text9: '學習不够充分,需要更加努力',
-    sca_text10: '學習極不穩定,對考試沒有充分準備',
-    sca_chart_text1: '通過率',
-    sca_chart_text2: '穩定度',
-    sca_table_text1: '答對題數',
-    sca_table_text2: '答錯題數',
-    sca_table_text3: '應努力題號',
-    sca_table_text4: '需小心題號',
-    sca_table_text5: '穩定程度',
-    sca_table_text6: '落點區域',
-
-    // TestAnalysis.vue
-    ta_title1: '試題落點分析',
-    ta_title2: '年級單題得分率統計',
-    ta_title3: '試題分析總表',
-    ta_title4: '試題得分率錶',
-
-    ta_text1: '區域',
-    ta_text2: '區域特性',
-    ta_text3: '題數',
-    ta_text4: '題目編號',
-    ta_text5: '所選題號',
-    ta_text6: '試題相當適當,可以用來區分學生的不同',
-    ta_text7: '試題可能含有異質成分在內,需要局部修正',
-    ta_text8: '試題困難度較高,適合區分高成就者學生',
-    ta_text9: '試題含有異質成分,可能數據錯誤或者題意不清,必須加以修改',
-
-    ta_chart_text1: '試題',
-    ta_chart_text2: '答對率',
-    ta_chart_text3: '穩定度',
-    ta_chart_text4: '班級得分率',
-    ta_chart_text5: '年級得分率',
-    ta_chart_text6: '區級得分率',
-
-    ta_table_text1: '題號',
-    ta_table_text2: '題型',
-    ta_table_text3: '知識點',
-    ta_table_text4: '配分',
-    ta_table_text5: '難易度',
-    ta_table_text6: '鑒別度',
-    ta_table_text7: '班級',
-    ta_table_text8: '得分率',
-    ta_table_text9: '區級',
-    ta_table_text10: '高分组',
-    ta_table_text11: '低分组',
-
-    ta_table_tip1: '* 組織:得分率',
-    ta_table_tip2: '* R1-R6:排名區間',
-
-    // KnowledgeAnalysis.vue
-    ka_title1: '知識點占比',
-    ka_title2: '認知層次分佈',
-    ka_title3: '得分率關係表',
-    ka_title4: '知識點得分率統計',
-    ka_title5: '知識點得分詳情',
-    ka_title6: '錯題率關係表',
-
-    ka_text1: '當前知識塊',
-    ka_text2: '當前知識點',
-    ka_text3: '當前認知層次',
-
-    ka_chart_text1: '切換柱狀圖',
-    ka_chart_text2: '切換雷达圖',
-
-    ka_radar_text1: '知識',
-    ka_radar_text2: '應用',
-    ka_radar_text3: '分析',
-    ka_radar_text4: '綜合',
-    ka_radar_text5: '評鑒',
-    ka_radar_text6: '理解',
-
-    ka_table_text1: '知識點',
-    ka_table_text2: '認知層次',
-    ka_table_text3: '年級得分率',
-    ka_table_text4: '分值',
-    ka_table_text5: '本節得分',
-    ka_table_text6: '得分率',
-    ka_table_text7: '涉及題號',
-    ka_table_text8: '平均得分率',
-    ka_table_text9: '錯題人數',
-    ka_table_text10: 'RH錯題人數',
-    ka_table_text11: 'RL錯題人數',
-
-    ka_tip1: '* RH:高分區段 / RL:低分區段',
-
-    // LevelAnalysis.vue
-    le_title1: '認知層次占比',
-    le_title2: '认知层次分布',
-    le_title3: '得分率關系表',
-    le_title4: '認知層次得分率統計',
-    le_title5: '認知層次得分詳情',
-    le_title6: '錯題率關系表',
-
-    // QuestionList.vue
-    ql_text1: '試卷總分',
-    ql_text2: '單項選擇題',
-    ql_text3: '多項選擇題',
-    ql_text4: '判斷題',
-    ql_text5: '填空題',
-    ql_text6: '問答題',
-    ql_text7: '綜合題',
-    ql_text8: '分',
-    ql_text9: '查看答案與解析',
-    ql_text10: '查看資料分析',
-    ql_text11: '參考答案',
-    ql_text12: '答題解析',
-    ql_text13: '返回'
+	echarts_text1: '最高值',
+	echarts_text2: '最低值',
+	echarts_text3: '平均值',
+	echarts_text4: '班級平均',
+	echarts_text5: '年級平均',
+	echarts_text6: '班級總人數',
+	echarts_text7: '進線總人數',
+	echarts_text8: '進線率',
+	echarts_text9: '當前年級',
+	echarts_text10: '篩選',
+	echarts_text11: '施測時間',
+	echarts_text12: '應參與人數',
+	echarts_text13: '實際參與人數',
+	echarts_text14: '參與率',
+	echarts_text15: '平均分',
+	echarts_text16: '成就指數',
+	echarts_text17: '優生率',
+	echarts_text18: '優生人數',
+
+	// Base Info
+	base_name: '姓名',
+	base_class: '班级',
+	base_id: '座號',
+	base_score: '分數',
+
+	// ExamList.vue
+	newest: '最新測驗',
+	more: '查看更多',
+
+	// index.vue
+	module1: '成績分析',
+	module2: '落点分析',
+	module3: '試題分析',
+	module4: '知識点掌握',
+	module5: '認知層次掌握',
+	exportTable: '匯出表格',
+	currentSubject: '當前科目',
+
+	// AchievementAnalysis.vue
+	ach_title1: '及格率統計',
+	ach_title2: '均分分析',
+	ach_title3: '進線人數統計',
+	ach_title4: '進線情况統計',
+	ach_title5: '進線率統計',
+	ach_title6: '預警統計',
+	ach_title7: '排名統計',
+	ach_title8: '均分分析',
+	ach_text1: '及格率',
+	ach_text2: '年级',
+	ach_text3: '區級',
+	ach_text4: '班級平均分',
+	ach_text5: '校級平均分',
+	ach_text6: '區級平均分',
+	ach_text7: '班級總人數',
+	ach_text8: '進線總人數',
+	ach_text9: '進線率',
+	ach_text10: '當前班級',
+	ach_text11: '總人數',
+	ach_text12: '返回',
+
+	ach_table_text1: '年級排名',
+	ach_table_text2: '總分',
+	ach_table_text3: '平均分',
+	ach_table_text4: '標準差',
+	ach_table_text5: '超均率',
+	ach_table_text6: '進線',
+	ach_table_text7: '踩線',
+	ach_table_text8: '班級排名',
+	ach_table_text9: '年級排名',
+	ach_table_text10: '區級排名',
+	ach_table_text11: '班級PR排名',
+	ach_table_text12: '年級PR排名',
+	ach_table_text13: '區級PR排名',
+	ach_table_text14: '進步班級',
+	ach_table_text15: '退步班級',
+	ach_table_text16: '穩定班級',
+
+	ach_chart_text1: '排序方式',
+	ach_chart_text2: '默認排序',
+	ach_chart_text3: '分數從高到低',
+	ach_chart_text4: '分數從低到高',
+
+	// ScatterAnalysis.vue
+	sca_title1: '學生學習力分佈',
+	sca_title2: '學生穩定度統計表',
+	sca_text1: '區域',
+	sca_text2: '區域特性',
+	sca_text3: '所占人數',
+	sca_text4: '學生',
+	sca_text5: '學習良好,穩定度高',
+	sca_text6: '粗心大意,不細心造成錯誤',
+	sca_text7: '學習尚且穩定,需要再用功',
+	sca_text8: '偶爾粗心,準備不够充分',
+	sca_text9: '學習不够充分,需要更加努力',
+	sca_text10: '學習極不穩定,對考試沒有充分準備',
+	sca_chart_text1: '通過率',
+	sca_chart_text2: '穩定度',
+	sca_table_text1: '答對題數',
+	sca_table_text2: '答錯題數',
+	sca_table_text3: '應努力題號',
+	sca_table_text4: '需小心題號',
+	sca_table_text5: '穩定程度',
+	sca_table_text6: '落點區域',
+
+	// TestAnalysis.vue
+	ta_title1: '試題落點分析',
+	ta_title2: '年級單題得分率統計',
+	ta_title3: '試題分析總表',
+	ta_title4: '試題得分率錶',
+
+	ta_text1: '區域',
+	ta_text2: '區域特性',
+	ta_text3: '題數',
+	ta_text4: '題目編號',
+	ta_text5: '所選題號',
+	ta_text6: '試題相當適當,可以用來區分學生的不同',
+	ta_text7: '試題可能含有異質成分在內,需要局部修正',
+	ta_text8: '試題困難度較高,適合區分高成就者學生',
+	ta_text9: '試題含有異質成分,可能數據錯誤或者題意不清,必須加以修改',
+
+	ta_chart_text1: '試題',
+	ta_chart_text2: '答對率',
+	ta_chart_text3: '穩定度',
+	ta_chart_text4: '班級得分率',
+	ta_chart_text5: '年級得分率',
+	ta_chart_text6: '區級得分率',
+
+	ta_table_text1: '題號',
+	ta_table_text2: '題型',
+	ta_table_text3: '知識點',
+	ta_table_text4: '配分',
+	ta_table_text5: '難易度',
+	ta_table_text6: '鑒別度',
+	ta_table_text7: '班級',
+	ta_table_text8: '得分率',
+	ta_table_text9: '區級',
+	ta_table_text10: '高分组',
+	ta_table_text11: '低分组',
+
+	ta_table_tip1: '* 組織:得分率',
+	ta_table_tip2: '* R1-R6:排名區間',
+
+	// KnowledgeAnalysis.vue
+	ka_title1: '知識點占比',
+	ka_title2: '認知層次分佈',
+	ka_title3: '得分率關係表',
+	ka_title4: '知識點得分率統計',
+	ka_title5: '知識點得分詳情',
+	ka_title6: '錯題率關係表',
+
+	ka_text1: '當前知識塊',
+	ka_text2: '當前知識點',
+	ka_text3: '當前認知層次',
+
+	ka_chart_text1: '切換柱狀圖',
+	ka_chart_text2: '切換雷达圖',
+
+	ka_radar_text1: '知識',
+	ka_radar_text2: '應用',
+	ka_radar_text3: '分析',
+	ka_radar_text4: '綜合',
+	ka_radar_text5: '評鑒',
+	ka_radar_text6: '理解',
+
+	ka_table_text1: '知識點',
+	ka_table_text2: '認知層次',
+	ka_table_text3: '年級得分率',
+	ka_table_text4: '分值',
+	ka_table_text5: '本節得分',
+	ka_table_text6: '得分率',
+	ka_table_text7: '涉及題號',
+	ka_table_text8: '平均得分率',
+	ka_table_text9: '錯題人數',
+	ka_table_text10: 'RH錯題人數',
+	ka_table_text11: 'RL錯題人數',
+
+	ka_tip1: '* RH:高分區段 / RL:低分區段',
+
+	// LevelAnalysis.vue
+	le_title1: '認知層次占比',
+	le_title2: '认知层次分布',
+	le_title3: '得分率關系表',
+	le_title4: '認知層次得分率統計',
+	le_title5: '認知層次得分詳情',
+	le_title6: '錯題率關系表',
+
+	// QuestionList.vue
+	ql_text1: '試卷總分',
+	ql_text2: '單項選擇題',
+	ql_text3: '多項選擇題',
+	ql_text4: '判斷題',
+	ql_text5: '填空題',
+	ql_text6: '問答題',
+	ql_text7: '綜合題',
+	ql_text8: '分',
+	ql_text9: '查看答案與解析',
+	ql_text10: '查看資料分析',
+	ql_text11: '參考答案',
+	ql_text12: '答題解析',
+	ql_text13: '返回'
 
 }

+ 137 - 33
TEAMModelOS/ClientApp/src/static/Global.js

@@ -1,40 +1,144 @@
-
+import i18n from '../locale/index.js'
+import Vue from 'vue'
+import VueI18n from 'vue-i18n'
+
+const PRIVATE_SPACE = 1024 * 1024 * 1024 * 1 //教师Blob个人空间
+const SCHOOL_SPACE = 1024 * 1024 * 1024 * 10 //学校Blob空间
+const DEFAULT_SCHOOL_CODE = 'SYSTEM_NO_SCHOOL' //尚未归属学校的默认学校编码
+const BLOB_URL = 'https://teammodelstorage.blob.core.chinacloudapi.cn' //尚未归属学校的默认学校编码
+
 //文件类型,对应内容模块Blob目录
 const CONTENT_TYPES = {
-    'image': ['JPG', 'JPEG', 'PNG', 'GIF', 'SVG'],
-    'video': ['AVI', 'MP4', 'WEBM'],
-    'doc': ['PPT', 'PPTX', 'DOC', 'DOCX', 'PDF', 'XLS', 'XLSX', 'CSV'],
-    'res': ['HTE', 'HTEX'],
-    'audio': ['MP3', 'WAV', 'OGG']
+	'image': ['JPG', 'JPEG', 'PNG', 'GIF', 'SVG'],
+	'video': ['AVI', 'MP4', 'WEBM'],
+	'doc': ['PPT', 'PPTX', 'DOC', 'DOCX', 'PDF', 'XLS', 'XLSX', 'CSV'],
+	'res': ['HTE', 'HTEX'],
+	'audio': ['MP3', 'WAV', 'OGG']
 }
 
-//教师Blob个人空间
-const PRIVATE_SPACE = 1024 * 1024 * 1024 * 1
-//学校Blob空间
-const SCHOOL_SPACE = 1024 * 1024 * 1024 * 10
-//尚未归属学校的默认学校编码
-const DEFAULT_SCHOOL_CODE = 'SYSTEM_NO_SCHOOL'
-
 //系统默认考试类型
-const EXAM_TYPE = [
-    {
-        id: "100",
-        name: "期中考试",
-    },
-    {
-        id: "101",
-        name: "期末考试",
-    },
-    {
-        id: "200",
-        name: "模拟考试",
-    }
-]
+const EXAM_TYPE = () => {
+	return [{
+		id: "100",
+		name: i18n.t('global.examType1')
+	},
+	{
+		id: "101",
+		name: i18n.t('global.examType2')
+	},
+	{
+		id: "200",
+		name: i18n.t('global.examType3')
+	}
+	]
+}
+//系统固定评测类型
+const EV_TYPE = () => {
+	return [
+		{
+			value: 'regular',
+			label: i18n.t('global.evType1')
+		},
+		{
+			value: 'simulation',
+			label: i18n.t('global.evType2')
+		},
+		{
+			value: 'normal',
+			label: i18n.t('global.evType3')
+		}
+	]
+}
+//系统固定评测类型
+const EV_MODE = () => {
+	return [
+		{
+			value: '0',
+			label: i18n.t('global.evMode1')
+		},
+		{
+			value: '1',
+			label: i18n.t('global.evMode2')
+		},
+		{
+			value: '2',
+			label: i18n.t('global.evMode3')
+		}
+	]
+}
+//系统固定评测发布方式
+const PUBLISH_TYPE = () => {
+	return [
+		{
+			value: '0',
+			label: i18n.t('global.publishType1')
+		},
+		{
+			value: '1',
+			label: i18n.t('global.publishType2')
+		}
+	]
+}
+
+/* 题目题型定义 */
+const EXERCISE_TYPES = () => {
+	return {
+		single: i18n.t('evaluation.single'),
+		multiple: i18n.t('evaluation.multiple'),
+		judge: i18n.t('evaluation.judge'),
+		complete: i18n.t('evaluation.complete'),
+		subjective: i18n.t('evaluation.subjective'),
+		connector: i18n.t('evaluation.connector'),
+		correct: i18n.t('evaluation.correct'),
+		compose: i18n.t('evaluation.compose')
+	}
+}
+
+/* 题目难度定义 */
+const EXERCISE_DIFFS = () => {
+	return [
+		i18n.t('evaluation.diff1'),
+		i18n.t('evaluation.diff2'),
+		i18n.t('evaluation.diff3'),
+		i18n.t('evaluation.diff4'),
+		i18n.t('evaluation.diff5')
+	]
+}
+
+/* 题目认知层次定义 */
+const EXERCISE_LEVELS = () => {
+	return [
+		i18n.t('evaluation.level1'),
+		i18n.t('evaluation.level2'),
+		i18n.t('evaluation.level3'),
+		i18n.t('evaluation.level4'),
+		i18n.t('evaluation.level5'),
+		i18n.t('evaluation.level6')
+	]
+}
+
+const GLOBAL = {
+	CONTENT_TYPES,
+	PRIVATE_SPACE,
+	SCHOOL_SPACE,
+	DEFAULT_SCHOOL_CODE,
+	BLOB_URL,
+	EXAM_TYPE,
+	EXERCISE_TYPES,
+	EXERCISE_DIFFS,
+	EXERCISE_LEVELS,
+	EV_TYPE,
+	EV_MODE,
+	PUBLISH_TYPE
+}
+
+const install = (Vue, options) => {
+	Vue.use(VueI18n)
+	Vue.prototype.$GLOBAL = GLOBAL
+}
 
 export default {
-    CONTENT_TYPES,
-    PRIVATE_SPACE,
-    SCHOOL_SPACE,
-    EXAM_TYPE,
-    DEFAULT_SCHOOL_CODE
-}
+	install
+
+}
+export {GLOBAL}

+ 8 - 0
TEAMModelOS/ClientApp/src/store/module/serviceDriveAuth.js

@@ -17,6 +17,7 @@ export default {
     spaceStatus: undefined,
     serviceIntroIsOpen: [],
     hiteachListItemIsOpen: [], //存放每個開關
+    currentTab:0,//0 服務清單, 1 hiteach 清單
 
     //接實際api使用,一開始序號為空
 
@@ -83,8 +84,15 @@ export default {
         return {};
       }
     },
+    getTab(state){
+      return state.currentTab
+    }
   },
   mutations: {
+    setTab(state,page){
+      state.currentTab = page;
+
+    },
     setServiceIntroIsOpen(state, data) {
       state.serviceIntroIsOpen = data;
     },

+ 12 - 11
TEAMModelOS/ClientApp/src/store/module/spaceAuth.js

@@ -1,4 +1,5 @@
 import apiTools from '@/api'
+import i18n from '@/locale'
 export default {
   namespaced: true,
   state: {
@@ -13,9 +14,9 @@ export default {
     currentSelectedTeacherId: [], //目前所選存放的老師的id,勾選給空間用
 
     pieNumData: [
-      { value: 0, name: '學校已使用空間' },
-      { value: 0, name: '已分配給教師空間' },
-      { value: 0, name: '剩餘空間' }
+      { value: 0, name: i18n.t("serviceDriveAuth['學校已使用空間']") },
+      { value: 0, name: i18n.t("serviceDriveAuth['已分配給教師空間']") },
+      { value: 0, name: i18n.t("serviceDriveAuth['剩餘空間']") }
     ],
     isKeyInSpace: false //存放是否有進行手動輸入
   },
@@ -108,17 +109,17 @@ export default {
       state.originalSpace = data.avaliable
       state.schoolUsedSpace = data.usedSpace
       state.pieNumData = [
-        { value: state.schoolUsedSpace, name: '學校已使用空間' },
-        { value: state.teacherUsedSpaceNum, name: '已分配給教師空間' },
-        { value: state.originalSpace - state.schoolUsedSpace - state.teacherUsedSpaceNum, name: '剩餘空間' }
+        { value: state.schoolUsedSpace, name: i18n.t("serviceDriveAuth['學校已使用空間']") },
+        { value: state.teacherUsedSpaceNum, name: i18n.t("serviceDriveAuth['已分配給教師空間']") },
+        { value: state.originalSpace - state.schoolUsedSpace - state.teacherUsedSpaceNum, name: i18n.t("serviceDriveAuth['剩餘空間']") }
       ]
       state.maxFixedAssignedValue = state.originalSpace - state.schoolUsedSpace
     },
     updatePieNumData(state) {
       state.pieNumData = [
-        { value: state.schoolUsedSpace, name: '學校已使用空間' },
-        { value: state.teacherUsedSpaceNum, name: '已分配給教師空間' },
-        { value: state.originalSpace - state.schoolUsedSpace - state.teacherUsedSpaceNum, name: '剩餘空間' }
+        { value: state.schoolUsedSpace, name: i18n.t("serviceDriveAuth['學校已使用空間']") },
+        { value: state.teacherUsedSpaceNum, name: i18n.t("serviceDriveAuth['已分配給教師空間']") },
+        { value: state.originalSpace - state.schoolUsedSpace - state.teacherUsedSpaceNum, name: i18n.t("serviceDriveAuth['剩餘空間']") }
       ]
     }
     //處理介面上的即時數據
@@ -168,10 +169,10 @@ export default {
           context.commit('updatePieNumData')
           context.commit('setIsLoading', false)
           context.commit('setMsgNum', 2)
-          if(res.status=='1'){
+          if (res.status == '1') {
             context.commit('setMsgNum', 3)
           }
-          if(res.status=='2'){
+          if (res.status == '2') {
             context.commit('setMsgNum', 4)
           }
         },

+ 36 - 0
TEAMModelOS/ClientApp/src/store/module/totalAnalysis.js

@@ -40,6 +40,42 @@ export default {
 		
 		// 更新最新学情分析数据
 		updateAnalysisJson(state,val){
+			let pointLevelKey = []
+			if(!val) return
+			/* 对知识点模块和认知层次模块进行数据格式化 */
+			val.subjects.forEach((subject,subjectIndex) => {
+				pointLevelKey.push({
+					subjectId:subject.id,
+					levelKey:{
+						level:val.fieldName[subjectIndex].Value,
+						pointList:val.fieldName[subjectIndex].Value,
+						per:val.fieldPer[subjectIndex].Value,
+						wrong:{
+							datas:val.fieldwrong[subjectIndex].Value,
+							keys:val.wrongKey
+						},
+						stupercent:tools.getLevelPercent(val,subjectIndex).stuResult,
+						classpercent:tools.getLevelPercent(val,subjectIndex).classResult
+					},
+					pointKey:{
+						level:val.knowName[subjectIndex].Value,
+						pointList:val.knowName[subjectIndex].Value,
+						per:val.knowPer[subjectIndex].Value,
+						wrong:{
+							datas:val.wrong[subjectIndex].Value,
+							keys:val.wrongKey
+						},
+						stupercent:tools.getKnowPercent(val,subjectIndex).stuResult,
+						classpercent:tools.getKnowPercent(val,subjectIndex).classResult
+					}
+				})
+			})
+			val.pointLevelKey = pointLevelKey
+			console.log('转换后的AnalysisJson',val)
+			state.analysisJson = val
+		},
+		
+		clearAnalysis(state,val){
 			state.analysisJson = val
 		},
 

+ 0 - 6
TEAMModelOS/ClientApp/src/utils/MathJax.js

@@ -2,13 +2,10 @@
 
 let isMathjaxConfig = false // 用于标识是否配置
 const initMathjaxConfig = () => {
-	console.log(window.MathJax)
 	if (!window.MathJax) {
 		return
 	}
-	console.log('MathJax配置')
 	window.MathJax.Hub.Config({
-		skipStartupTypeset: true,
 		showProcessingMessages: false, // 关闭js加载过程信息
 		messageStyle: 'none', // 不显示信息
 		tex: {
@@ -34,13 +31,10 @@ const initMathjaxConfig = () => {
 			showMathMenu: true
 		}
 	})
-	console.log('MathJax配置')
-	console.log(window.MathJax.Hub)
 	isMathjaxConfig = true // 配置完成,改为true
 }
 
 const MathQueue = function(elementId) {
-	console.log('进来了', elementId)
 	if (!window.MathJax) {
 		return
 	}

+ 109 - 62
TEAMModelOS/ClientApp/src/utils/blobTool.js

@@ -1,5 +1,5 @@
-import GLOBAL from '@/static/Global.js';
-
+import { GLOBAL } from '@/static/Global.js';
+import JsFn from '@/utils/js-fn.js';
 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"
 //获取文件后缀和类型
@@ -19,7 +19,6 @@ function getExAndType(fileName) {
 }
 
 export default class BlobTool {
-
     /**
      * 初始化Blob,需要先调用授权API
      * @param {string} blobUrl blob地址
@@ -59,7 +58,6 @@ export default class BlobTool {
             throw new Error("初始化参数不完整")
         }
     }
-
     /**
      * 获取容器信息 (授权失败,需要账号级别的授权)
      * @param {object} 
@@ -70,25 +68,21 @@ export default class BlobTool {
             this.containerClient.getProperties(options).then(
                 res => {
                     console.log('获取信息成功')
-                    console.log(res)
                     r(res)
                 },
                 err => {
                     console.log('获取信息失败')
-                    console.log(err)
                     j(err)
                 }
             )
         })
     }
-
     /**
      * 上传文件方法,带回调上传进度
      * @param {any} file 文件对象
      * @param {any} path 文件夹路径
      * @param {any} option 官方可配置项
      * @param {any} checkSize 上传时是否检查容器空间 官方可配置项。默认需要检查大小
-     * 
      * @returns {object} {url, name,size,createTime,extension,type}
      */
     upload(file, path, option, checkSize = true) {
@@ -140,18 +134,91 @@ export default class BlobTool {
             )
         })
     }
+    /**
+     * 处理HTEX文件类型
+     * @param {blobList} fileList 
+     */
+    handleHTEXFile(fileList) {
+        let parseRes = []
+        let names = []
+        fileList.forEach((item, index) => {
+            if (item.url.indexOf('/res/') > 0) {
+                let fileItem = {}
+                let startIndex = JsFn.findChartIndex(item.blob, '/', 1)
+                let endIndex = JsFn.findChartIndex(item.blob, '/', 2)
+                let name = item.blob.substring(startIndex + 1, endIndex)
+                let nameIndex = names.indexOf(name)
+                if (nameIndex == -1) {
+                    fileItem.url = this.blobUrl+ '/' + this.container +'/res/' + name
+                    fileItem.blob = `/res/${name}/index.json`
+                    fileItem.name = name + '.HTEX'
+                    fileItem.size = item.size
+                    fileItem.createTime = item.createTime
+                    fileItem.extension = 'HTEX'
+                    fileItem.type = 'res'
+                    names.push(name)
+                    parseRes.push(fileItem)
+                } else {
+                    parseRes[nameIndex].size += item.size
+                }
+            } else {
+                parseRes.push(item)
+            }
+        })
+        return parseRes
+    }
 
     /**
-     * 列出(查询)
+     * 列出所有(查询)
+     * @param {Object} option ContainerListBlobsOptions
+     * eg: option.prefix = 'res' 只查res文件夹下的blob
+     * @returns {object} {blobList, continuationToken}
+     */
+    async listBlob(option, hendleHTEX = true) {
+        return new Promise(async (r, j) => {
+            let blobList = []
+            if (this.containerClient) {
+                let iter = this.containerClient.listBlobsFlat(option ? option : {});
+                let blobItem = await iter.next();
+                while (!blobItem.done) {
+                    let blobName = blobItem.value.name
+                    let info = getExAndType(blobItem.value.name)
+                    blobList.push(
+                        {
+                            url: this.blobUrl + '/' + this.container + '/' + blobName,
+                            blob: '/' + blobName,
+                            // name: blobName.substring(JsFn.findChartIndex(blobName, '/', 0) + 1),
+                            name: blobName.substring(blobName.lastIndexOf('/') + 1),
+                            size: blobItem.value.properties.contentLength,
+                            createTime: blobItem.value.properties.createdOn.getTime(),
+                            extension: info.ex,
+                            type: info.type
+                        }
+                    )
+                    blobItem = await iter.next();
+                }
+                if (hendleHTEX) {
+                    blobList = this.handleHTEXFile(blobList)
+                }
+                r({
+                    blobList,
+                    continuationToken: 'end'
+                })
+            } else {
+                j('containerClient 错误')
+            }
+        })
+    }
+    /**
+     * 分页列出(查询)
      * @param {Object} option ContainerListBlobsOptions
      * eg: option.prefix = 'res' 只查res文件夹下的blob
      * @param {Object} pageInfo 
      * eg: pageInfo.maxPageSize 当前请求条数
      * eg: pageInfo.continuationToken 首次请求不需要,后面需要(首次请求会返回,下次需要传入)
-     * 
      * @returns {object} {blobList, continuationToken}
      */
-    async listBlob(option, pageInfo) {
+    async listBlobByPage(option, pageInfo) {
         return new Promise(async (r, j) => {
             let page = {}
             let blobList = []
@@ -189,7 +256,6 @@ export default class BlobTool {
             }
         })
     }
-
     /**
      * 删除Blob
      * @param {string} filePath 文件url + 容器 之后的路径
@@ -225,11 +291,9 @@ export default class BlobTool {
             blobBatchClient.deleteBlobs(files, this.blobService.credential).then(
                 res => {
                     console.log('批量删除成功')
-                    console.log(res)
                 },
                 err => {
                     console.log('批量删除失败')
-                    console.log(err)
                 }
             )
         })
@@ -239,7 +303,6 @@ export default class BlobTool {
      * @param {string} files 
      */
     deleteBlobBatch(files) {
-        console.log(files)
         return new Promise((r, j) => {
             let promises = []
             for (let item of files) {
@@ -263,10 +326,19 @@ export default class BlobTool {
      * 1、目标url(sourceUrl)不能出现中文或UTF-8码的字符, 如果有需要进行URI编码,否则会报错;
      * 2、目标url(sourceUrl)如果需要授权的容器,则url需要凭借授权。
      */
-    copyBlob(targetUrl, sourceUrl) {
+    copyBlob(targetUrl, sourceUrl, sas) {
         return new Promise((r, j) => {
             let newBlob = this.containerClient.getBlobClient(targetUrl)
-            newBlob.beginCopyFromURL(encodeURI(resourceUrl1) + schoolSas.sas)
+            let encodeUrl = encodeURI(sourceUrl)
+            // sas = "?sv=2020-02-10&st=2021-01-18T11%3A29%3A36Z&se=2021-01-19T11%3A59%3A36Z&sr=c&sp=rcwdl&sig=BXbsiVZ6ZogeWfyr3u2PgPVdeLlMMPOqvsh3%2BDEwnq4%3D"
+            newBlob.beginCopyFromURL(encodeUrl + sas).then(
+                res => {
+                    r(200)
+                },
+                err => {
+                    j(500)
+                }
+            )
         })
     }
 
@@ -282,24 +354,24 @@ export default class BlobTool {
             let sasString = ''
             if (blobTool) {
                 blobs = await blobTool.listBlob({
-                    prefix: sourceFolder
-                })
+                    prefix: sourceFolder + '/'
+                }, false)
                 sasString = blobTool.sasString
             } else {
                 blobs = await this.listBlob({
-                    prefix: sourceFolder
-                })
+                    prefix: sourceFolder + '/'
+                }, false)
                 sasString = this.sasString
             }
-            if(blobs && blobs.blobList){
+            if (blobs && blobs.blobList) {
                 let count = 0
-                blobs.blobList.forEach(blobItem=>{
-                    let newUrl =  targetFolder + blobItem.name
+                blobs.blobList.forEach(blobItem => {
+                    let newUrl = targetFolder + blobItem.name
                     let newBlob = this.containerClient.getBlobClient(newUrl)
                     let resourceUrl = encodeURI(blobItem.url)
-                    newBlob.beginCopyFromURL(resourceUrl + sasString).then().finally(()=>{
+                    newBlob.beginCopyFromURL(resourceUrl + sasString).then().finally(() => {
                         count++
-                        if(count == (blobs.blobList.length)){
+                        if (count == (blobs.blobList.length)) {
                             r('复制结束后')
                         }
                     })
@@ -307,12 +379,10 @@ export default class BlobTool {
             }
         })
     }
-
     /**
      * 判断文件是否存在
      * @param {string} filePath 文件路径 正确 'res/基础操作范例_16x9.HTE ' 错误 '/res/基础操作范例_16x9.HTE'
      * @param {object} 
-     * 
      * return true/false
      */
     exists(filePath, options) {
@@ -334,7 +404,7 @@ export default class BlobTool {
      */
     async getContainerSize() {
         return new Promise((r, j) => {
-            this.listBlob().then(
+            this.listBlob({},false).then(
                 res => {
                     let totalSize = res.blobList.reduce((total, item) => {
                         return total + parseInt(item.size)
@@ -373,12 +443,11 @@ export default class BlobTool {
      * 计算指定文件夹的空间大小,如果不传文件夹,则查询整个容器空间
      * @param {string} 
      * @param {object} 
-     * 
      * return true/false
      */
     getSize(option) {
         return new Promise((r, j) => {
-            this.listBlob(option).then(
+            this.listBlob(option,false).then(
                 res => {
                     let sizeInfo = {
                         total: 0,   //所有
@@ -395,50 +464,28 @@ export default class BlobTool {
                     }, 0)
                     sizeInfo.total = length
                     for (let item of res.blobList) {
-                        switch (item.type) {
+                        let folder = item.blob.substring(1, JsFn.findChartIndex(item.blob, '/', 1))
+                        switch (folder) {
                             case 'res':
-                                if (item.blob.indexOf('res') == 1) {
-                                    sizeInfo.res += item.size
-                                } else {
-                                    sizeInfo.data += item.size
-                                }
+                                sizeInfo.res += item.size
                                 break
                             case 'image':
-                                if (item.blob.indexOf('image') == 1) {
-                                    sizeInfo.image += item.size
-                                } else {
-                                    sizeInfo.data += item.size
-                                }
+                                sizeInfo.image += item.size
                                 break
                             case 'video':
-                                if (item.blob.indexOf('video') == 1) {
-                                    sizeInfo.video += item.size
-                                } else {
-                                    sizeInfo.data += item.size
-                                }
+                                sizeInfo.video += item.size
                                 break
                             case 'audio':
-                                if (item.blob.indexOf('audio') == 1) {
-                                    sizeInfo.audio += item.size
-                                } else {
-                                    sizeInfo.data += item.size
-                                }
+                                sizeInfo.audio += item.size
                                 break
                             case 'doc':
-                                if (item.blob.indexOf('doc') == 1) {
-                                    sizeInfo.doc += item.size
-                                } else {
-                                    sizeInfo.data += item.size
-                                }
+                                sizeInfo.doc += item.size
                                 break
                             case 'other':
-                                if (item.blob.indexOf('other') == 1) {
-                                    sizeInfo.other += item.size
-                                } else {
-                                    sizeInfo.data += item.size
-                                }
+                                sizeInfo.other += item.size
                                 break
                             default:
+                                sizeInfo.data += item.size
                                 break
                         }
                     }

+ 5 - 4
TEAMModelOS/ClientApp/src/utils/editorTools.js

@@ -336,12 +336,11 @@ export default {
 							}),
 							h('BaseMyCanvas', {
 								props:{
-									writeColor:'red',
 								},
 								on: {
 									onSaveCanvas(val) {
-										let widthPercent = val.width > 800 ? '50%' : '100%'
-										editor.txt.append('<img  src=' + val.base64 + ' class="richText-canvas" width="' + widthPercent +'"></img>');
+										// let widthPercent = val.width > 800 ? '50%' : '100%'
+										editor.txt.append('<img  src=' + val.base64 + ' class="richText-canvas" style="max-width:100%"></img>');
 										Modal.remove()
 									},
 									onCloseModal() {
@@ -462,7 +461,9 @@ export default {
 					let srcList = videoSrcList.concat(audioSrcList)
 					if (srcList.length) {
 						srcList.forEach(src => {
-							richTextObj[key] = richTextObj[key].replace(src, src.split('/')[src.split('/').length - 1]);
+							let withSas = src.split('/')[src.split('/').length - 1]
+							let j = withSas.lastIndexOf('?')
+							richTextObj[key] = richTextObj[key].replace(src, withSas.slice(0,j));
 						})
 						if (key === 'answer' && Array.isArray(exerciseItem.answer) && exerciseItem.answer.length) {
 							exerciseItem.answer[0] = richTextObj[key]

+ 64 - 22
TEAMModelOS/ClientApp/src/utils/evTools.js

@@ -2,9 +2,21 @@ import $api from '@/api'
 import store from '@/store'
 import $tools from './public.js'
 import $editorTools from './editorTools.js'
+import {
+	Message,
+	Modal
+} from 'view-design'
+
 
 
 export default {
+	
+	/* 根据登录后的用户信息获取blobHOST域名 */
+	getBlobHost(){
+		let s = store.state.user.userProfile.blob_uri || store.state.user.studentProfile.blob_uri || 'https://teammodelstorage.blob.core.chinacloudapi.cn/hbcn'
+		return s.split(s.substring(s.lastIndexOf('/')))[0]
+	},
+	
 	/* 获取试题保存在Blob的JSON文件 */
 	createBlobItem(item){
 		return new Promise((r,j) => {
@@ -16,7 +28,7 @@ export default {
 					explain:item.explain,
 					type:item.type,
 					opts:item.option.length,
-					points:item.points,
+					knowledge:item.knowledge,
 					field:item.field,
 					level:item.level,
 					periodId:item.periodId,
@@ -48,7 +60,7 @@ export default {
 				score:0,
 				type:item.type,
 				question:this.getSimpleText(item.question),
-				points:item.points,
+				knowledge:item.knowledge,
 				field:item.field,
 				level:item.level,
 				periodId:item.periodId,
@@ -104,7 +116,6 @@ export default {
 		})
 	},
 	
-	
 	/* 获取完整的试题数据 */
 	getFullItem(list){
 		return new Promise(async (resolve,reject) => {
@@ -128,6 +139,7 @@ export default {
 						// 调整渲染试题数据结构
 						jsonData.id = list[i].id
 						jsonData.exercise.question = jsonData.item[0].question
+						jsonData.exercise.createTime = list[i].createTime || 0
 						jsonData.exercise.blob = list[i].blob
 						jsonData.exercise.code = list[i].code
 						jsonData.exercise.option = jsonData.item[0].option
@@ -143,6 +155,9 @@ export default {
 			Promise.all(promiseArr).then(result => {
 				console.log('从Blob获取来的试题',result)
 				resolve(result)
+			}).catch(err => {
+				Message.error('有试题文件读取失败')
+				reject(err)
 			})
 		})
 	},
@@ -167,20 +182,36 @@ export default {
 					let audioSrcList = $editorTools.getRichTextSrc(richTextObj[key],'audio')
 					let srcList = videoSrcList.concat(audioSrcList)
 					if(srcList.length){
+						console.log('要添加list',srcList)
 						for(let i = 0;i<srcList.length;i++){
 							let src = srcList[i]
 							/* 如果是来自试卷的题目 则需要匹配试卷HOST */
 							if(examItem){
 								let examContainer = examItem.examId ?  (examItem.scope === 'school' ? store.state.userInfo.schoolCode : store.state.userInfo.TEAMModelId) : examItem.code
-								let blobUrl = 'https://teammodelstorage.blob.core.chinacloudapi.cn/' + examContainer  + examItem.blob +  '/' + src.split('?')[0]
-								let addSasUrl = await $tools.getFileSas(blobUrl)
-								richTextObj[key] = richTextObj[key].replace(src, addSasUrl.url);
+								let blobUrl = this.getBlobHost() +  '/' + examContainer  + examItem.blob +  '/' + src
+								try{
+									let addSasUrl = await $tools.getFileSas(blobUrl)
+									richTextObj[key] = richTextObj[key].replace(`src="${ src }"`, `src="${ addSasUrl.url }"`);
+								}catch(e){
+									j(500)
+								}
 							}else if(paperName){
-								let blobUrl = 'https://teammodelstorage.blob.core.chinacloudapi.cn/' + container + '/paper/' + paperName + '/' + src.split('?')[0]
-								let addSasUrl = await $tools.getFileSas(blobUrl)
-								richTextObj[key] = richTextObj[key].replace(src, addSasUrl.url);
+								let blobUrl = this.getBlobHost() +  '/'  + container + '/paper/' + paperName + '/' + src
+								try{
+									let addSasUrl = await $tools.getFileSas(blobUrl)
+									richTextObj[key] = richTextObj[key].replace(`src="${ src }"`, `src="${ addSasUrl.url }"`);
+								}catch(e){
+									j(500)
+								}
 							}else{
-								richTextObj[key] = richTextObj[key].replace(src, 'https://teammodelstorage.blob.core.chinacloudapi.cn/' + container + '/item/' + exerciseItem.id + '/' + src);
+								let blobUrl = this.getBlobHost() +  '/'  + container + '/item/' + exerciseItem.id + '/' + src
+								try{
+									let addSasUrl = await $tools.getFileSas(blobUrl)
+									richTextObj[key] = richTextObj[key].replace(`src="${ src }"`, `src="${ addSasUrl.url }"`);
+								}catch(e){
+									j(500)
+								}
+								
 							}
 						}
 						if(key === 'answer' && Array.isArray(exerciseItem.answer) && exerciseItem.answer.length){
@@ -197,11 +228,12 @@ export default {
 			Promise.all(promiseArr).then(result => {
 				//console.log('添加HOST之后的',exerciseItem)
 				resolve(exerciseItem)
+			}).catch(e => {
+				reject(e)
 			})
 		})
 	},
 	
-	
 	/* 保存综合题小题 */
 	saveChildren(children,containerClient){
 		return new Promise((resolve,reject) => {
@@ -302,12 +334,16 @@ export default {
 								itemJson.exercise.pid = itemJson.pid 
 								itemJson.exercise.blob = path + '/' + item.url // 添加blob是方便在保存试卷是 refresh 与导入的试题区分开
 								itemJson.exercise.score = item.scoring ? item.scoring.score : 0
-								if(paper.examId){
-									itemJson.exercise = await this.doAddHost(itemJson.exercise,paper.name,paper) // 检测试题中的富文本 为有src为相对路径的音视频文件添加blob的HOST地址
-								}else{
-									itemJson.exercise = await this.doAddHost(itemJson.exercise,paper.name) // 检测试题中的富文本 为有src为相对路径的音视频文件添加blob的HOST地址
+								try{
+									if(paper.examId){
+										itemJson.exercise = await this.doAddHost(itemJson.exercise,paper.name,paper) // 检测试题中的富文本 为有src为相对路径的音视频文件添加blob的HOST地址
+									}else{
+										itemJson.exercise = await this.doAddHost(itemJson.exercise,paper.name) // 检测试题中的富文本 为有src为相对路径的音视频文件添加blob的HOST地址
+									}
+									resolve(itemJson.exercise)
+								}catch(e){
+									reject(e)
 								}
-								resolve(itemJson.exercise)
 							}catch(e){
 								reject(e)
 							}
@@ -326,6 +362,9 @@ export default {
 						})
 						jsonData.item = res.filter(i => !i.pid)
 						r(jsonData)
+					}).catch(e => {
+						// Message.error('试卷文件读取失败')
+						j(e)
 					})
 				}
 			}catch(e){
@@ -351,7 +390,6 @@ export default {
 					jsonData.item = []
 					const path = sasString.url + '/' + paper.code + paper.blob
 					let promiseArr = []
-
 					jsonData.slides.forEach((item, index) => {
 						promiseArr.push(new Promise(async (resolve, reject) => {
 							// 获取题目JSON并且包装成完整试题对象
@@ -360,13 +398,16 @@ export default {
 							itemJson.exercise.option = itemJson.item[0].option
 							itemJson.exercise.id = itemJson.id 
 							itemJson.exercise.pid = itemJson.pid 
-							itemJson.exercise.score = item.scoring ? item.scoring.score : 0,
+							itemJson.exercise.score = item.scoring ? item.scoring.score : 0
 							// jsonData.item.push(itemJson.exercise)
-							itemJson.exercise = await this.doAddHost(itemJson.exercise,paper.name,paper)
-							resolve(itemJson.exercise)
+							try{
+								itemJson.exercise = await this.doAddHost(itemJson.exercise,paper.name,paper)
+								resolve(itemJson.exercise)
+							}catch(e){
+								reject(e)
+							}
 						}))
 					})
-
 					Promise.all(promiseArr).then(res => {
 						res.forEach((resItem,resIndex) => {
 							resItem.children = []
@@ -378,6 +419,8 @@ export default {
 						})
 						jsonData.item = res.filter(i => !i.pid)
 						r(jsonData)
+					}).catch(e => {
+						j(e)
 					})
 				}
 			}catch(e){
@@ -390,7 +433,6 @@ export default {
 		return new Promise(async (r, j) => {
 			// 根据试卷的Blob地址 去读取JSON文件
 			let sasString = paper.scope === 'school' ? await $tools.getSchoolSas(paper.code) : await $tools.getPrivateSas(paper.code)
-			//console.log(sasString)
 			try {
 				console.log(paper.blob + sasString.sas)
 				let jsonInfo = await $tools.getFile(paper.blob + sasString.sas)

+ 10 - 2
TEAMModelOS/ClientApp/src/utils/js-fn.js

@@ -239,7 +239,14 @@ function uuid() {
     }
     return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4())
 }
-
+// 获取某个字符在字符串中第num次出现的index
+function findChartIndex(str,cha,num){
+    var x=str.indexOf(cha);
+    for(var i=0;i<num;i++){
+        x=str.indexOf(cha,x+1);
+    }
+    return x;
+}
 
 export default {
     groupBy,
@@ -257,5 +264,6 @@ export default {
     debounce,
     throttle,
     formatBytes,
-    uuid
+    uuid,
+    findChartIndex
 }

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

@@ -34,7 +34,7 @@ export default function(editor) {
 				console.log(kfe)
               let latex = kfe.execCommand('get.source')
               latex = latex.replace(/\s/g, '') // 去掉空格
-				
+				console.log('latex',latex)
 				
               // 使用 editor.cmd.do  无法关闭弹窗
               // editor.cmd.do(

+ 85 - 1
TEAMModelOS/ClientApp/src/utils/public.js

@@ -612,5 +612,89 @@ export default {
 			}
 		}
 		return true;
-	}
+	},
+	
+	getLevelStuPercent(val,subjectIndex,index){
+		let result = []
+		val.students.forEach(stu => {
+			result.push([
+				stu.name,
+				stu.className,
+				stu.no || '-',
+				val.fScores[subjectIndex].Value[index],
+				stu.subjects[subjectIndex].fieldPoint[index],
+				(stu.subjects[subjectIndex].fieldPoint[index] / val.fScores[subjectIndex].Value[index]).toFixed(2)
+			])
+		})
+		return result
+	},
+	
+	getLevelClassPercent(val,subjectIndex,index){
+		let result = []
+		val.classes.forEach(classItem => {
+			result.push(classItem.subjects[subjectIndex].field[index])
+		})
+		return result
+	},
+	
+	getLevelPercent(val,subjectIndex){
+		let stuResult = {}
+		let classResult = {}
+		val.fieldName[subjectIndex].Value.forEach((item,index) => {
+			stuResult[item] = this.getLevelStuPercent(val,subjectIndex,index)
+			classResult[item] = this.getLevelClassPercent(val,subjectIndex,index)
+		})
+		stuResult.grade = val.fieldAllPer[subjectIndex].Value
+		stuResult.keys = val.knowKey
+		classResult.keys = val.knowkey
+		classResult.className = []
+		let obj = {
+			stuResult:stuResult,
+			classResult:classResult
+		}
+		return obj
+	},
+	
+	/* 学情知识点模块数据转换 */
+	getKnowStuPercent(val,subjectIndex,index){
+		let result = []
+		val.students.forEach(stu => {
+			result.push([
+				stu.name,
+				stu.className,
+				stu.no || '-',
+				val.kScores[subjectIndex].Value[index],
+				stu.subjects[subjectIndex].point[index],
+				(stu.subjects[subjectIndex].point[index] / val.kScores[subjectIndex].Value[index]).toFixed(2)
+			])
+		})
+		return result
+	},
+	
+	getKnowClassPercent(val,subjectIndex,index){
+		let result = []
+		val.classes.forEach(classItem => {
+			result.push(classItem.subjects[subjectIndex].point[index])
+		})
+		return result
+	},
+	
+	getKnowPercent(val,subjectIndex){
+		let stuResult = {}
+		let classResult = {}
+		val.knowName[subjectIndex].Value.forEach((item,index) => {
+			stuResult[item] = this.getKnowStuPercent(val,subjectIndex,index)
+			classResult[item] = this.getKnowClassPercent(val,subjectIndex,index)
+		})
+		stuResult.grade = val.knowAllper[subjectIndex].Value
+		stuResult.keys = val.knowKey
+		classResult.keys = val.knowkey
+		classResult.className = []
+		let obj = {
+			stuResult:stuResult,
+			classResult:classResult
+		}
+		return obj
+	},
+
 }

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


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