Selaa lähdekoodia

Merge branch 'develop5.0-tmd' of http://106.12.23.251:10000/TEAMMODEL/TEAMModelOS into develop5.0-tmd

zhouj1203@hotmail.com 4 vuotta sitten
vanhempi
commit
334cd2a02b
100 muutettua tiedostoa jossa 2499 lisäystä ja 1011 poistoa
  1. 3 3
      TEAMModelOS/Filter/ApiTokenAttribute.cs
  2. 38 0
      TEAMModelAPI/Startup.cs
  3. 1 2
      TEAMModelAPI/TEAMModelAPI.csproj
  4. 13 1
      TEAMModelAPI/appsettings.json
  5. 1 1
      TEAMModelOS.SDK/DI/AzureStorage/AzureStorageFactory.cs
  6. 2 2
      TEAMModelOS.SDK/Extension/JwtAuthExtension.cs
  7. 72 1
      TEAMModelOS.SDK/Models/Cosmos/Api/OpenApi.cs
  8. 3 1
      TEAMModelOS.SDK/Models/Cosmos/Common/Snode.cs
  9. 9 2
      TEAMModelOS.SDK/Models/Cosmos/Common/Syllabus.cs
  10. 1 1
      TEAMModelOS.SDK/Models/Cosmos/Common/Vote.cs
  11. 1 0
      TEAMModelOS.SDK/Models/Cosmos/School/Paper.cs
  12. 15 23
      TEAMModelOS.SDK/Models/Cosmos/Teacher/Share.cs
  13. 1 0
      TEAMModelOS/ClientApp/package.json
  14. 7 0
      TEAMModelOS/ClientApp/src/api/evaluation.js
  15. 1 1
      TEAMModelOS/ClientApp/src/api/openMgmt.js
  16. 4 0
      TEAMModelOS/ClientApp/src/api/service.js
  17. 5 0
      TEAMModelOS/ClientApp/src/api/studentWeb.js
  18. 3 0
      TEAMModelOS/ClientApp/src/api/syllabus.js
  19. 26 3
      TEAMModelOS/ClientApp/src/assets/iconfont/demo_index.html
  20. 7 3
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css
  21. 1 1
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.js
  22. 7 0
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.json
  23. BIN
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.ttf
  24. BIN
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff
  25. BIN
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff2
  26. 2 2
      TEAMModelOS/ClientApp/src/common/BaseKonva.vue
  27. 11 1
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  28. 8 2
      TEAMModelOS/ClientApp/src/common/BaseMyCanvas.vue
  29. 1 1
      TEAMModelOS/ClientApp/src/common/BaseNotification.vue
  30. 405 346
      TEAMModelOS/ClientApp/src/common/BaseUserPoptip.vue
  31. 1 1
      TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.vue
  32. 5 8
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseQuestionnaire.vue
  33. 18 9
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContent.vue
  34. 72 64
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue
  35. 28 18
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReportCharts/StudentScore.vue
  36. 51 25
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperTest.vue
  37. 50 14
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperView.vue
  38. 109 64
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/QuesNaire.vue
  39. 166 121
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/Vote.vue
  40. 18 1
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventList.vue
  41. 15 5
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventView.vue
  42. 1 1
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/HomeView.vue
  43. 25 1
      TEAMModelOS/ClientApp/src/components/syllabus/DragTree.less
  44. 342 18
      TEAMModelOS/ClientApp/src/components/syllabus/DragTree.vue
  45. 9 6
      TEAMModelOS/ClientApp/src/components/syllabus/InviteTeacher.vue
  46. 1 0
      TEAMModelOS/ClientApp/src/css/dark-iview-poptip.less
  47. 2 2
      TEAMModelOS/ClientApp/src/locale/lang/en-US/classMgmt.js
  48. 14 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js
  49. 85 22
      TEAMModelOS/ClientApp/src/locale/lang/en-US/learnActivity.js
  50. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolBaseInfo.js
  51. 4 4
      TEAMModelOS/ClientApp/src/locale/lang/en-US/serviceDriveAuth.js
  52. 5 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/settings.js
  53. 10 6
      TEAMModelOS/ClientApp/src/locale/lang/en-US/stuAccount.js
  54. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/system.js
  55. 10 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/task.js
  56. 4 2
      TEAMModelOS/ClientApp/src/locale/lang/en-US/teachContent.js
  57. 2 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/classMgmt.js
  58. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/courseManage.js
  59. 14 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/cusMgt.js
  60. 4 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/evaluation.js
  61. 75 11
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/learnActivity.js
  62. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/schoolBaseInfo.js
  63. 6 6
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/serviceDriveAuth.js
  64. 5 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/settings.js
  65. 11 7
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/stuAccount.js
  66. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/syllabus.js
  67. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/system.js
  68. 10 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/task.js
  69. 4 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachContent.js
  70. 6 8
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachermgmt.js
  71. 2 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/classMgmt.js
  72. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/courseManage.js
  73. 15 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/cusMgt.js
  74. 40 36
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/evaluation.js
  75. 73 10
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/learnActivity.js
  76. 9 8
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/schoolBaseInfo.js
  77. 4 4
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/serviceDriveAuth.js
  78. 6 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/settings.js
  79. 13 9
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/stuAccount.js
  80. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/syllabus.js
  81. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/system.js
  82. 10 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/task.js
  83. 4 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/teachContent.js
  84. 4 4
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/teachermgmt.js
  85. 34 10
      TEAMModelOS/ClientApp/src/router/routes.js
  86. 2 4
      TEAMModelOS/ClientApp/src/static/Global.js
  87. 13 1
      TEAMModelOS/ClientApp/src/store/module/user.js
  88. 3 1
      TEAMModelOS/ClientApp/src/utils/blobTool.js
  89. 130 0
      TEAMModelOS/ClientApp/src/utils/editorLangTw.js
  90. 20 2
      TEAMModelOS/ClientApp/src/utils/editorTools.js
  91. 132 42
      TEAMModelOS/ClientApp/src/utils/evTools.js
  92. 33 2
      TEAMModelOS/ClientApp/src/utils/js-fn.js
  93. 17 1
      TEAMModelOS/ClientApp/src/utils/public.js
  94. 21 12
      TEAMModelOS/ClientApp/src/view/Home.vue
  95. 1 1
      TEAMModelOS/ClientApp/src/view/answersheet/BaseEditor.vue
  96. 28 4
      TEAMModelOS/ClientApp/src/view/answersheet/index.vue
  97. 27 21
      TEAMModelOS/ClientApp/src/view/evaluation/bank/TestPaperList.vue
  98. 15 4
      TEAMModelOS/ClientApp/src/view/evaluation/bank/index.vue
  99. 1 0
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseExerciseList.vue
  100. 0 0
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseFilter.vue

+ 3 - 3
TEAMModelOS/Filter/ApiTokenAttribute.cs

@@ -48,9 +48,9 @@ namespace TEAMModelOS.Filter
                     jti = jwt.Payload.Jti;
                     name = jwt.Claims.FirstOrDefault(claim => claim.Type == "name")?.Value;
                     //处理限流问题
-                    if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(school) || string.IsNullOrEmpty(name) || string.IsNullOrEmpty(jti))
+                    if (!string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(school) && !string.IsNullOrEmpty(name)&& !string.IsNullOrEmpty(jti))
                     {
-                        context.Result = new BadRequestResult();
+                        pass = true;
                     }
                     else { 
                         
@@ -64,7 +64,7 @@ namespace TEAMModelOS.Filter
                     context.HttpContext.Items.Add("School", school);
                 }
                 else
-                    context.Result = new BadRequestResult();
+                    context.Result = new UnauthorizedResult();
             }
 
             public void OnResourceExecuted(ResourceExecutedContext context)

+ 38 - 0
TEAMModelAPI/Startup.cs

@@ -10,7 +10,11 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading.Tasks;
+using TEAMModelOS.Models;
 using TEAMModelOS.SDK.DI;
+using System.IdentityModel.Tokens.Jwt;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.IdentityModel.Tokens;
 
 namespace TEAMModelAPI
 {
@@ -27,6 +31,37 @@ namespace TEAMModelAPI
         // This method gets called by the runtime. Use this method to add services to the container.
         public void ConfigureServices(IServiceCollection services)
         {
+           
+            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
+            services.AddAuthentication(options => options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
+                .AddJwtBearer(options => //AzureADJwtBearer
+                {
+                    //options.SaveToken = true; //驗證令牌由服務器生成才有效,不適用於服務重啟或分布式架構
+                    options.Authority = Configuration["Option:Authority"];
+                    options.Audience = Configuration["Option:Audience"];
+                    options.RequireHttpsMetadata = true;
+                    options.TokenValidationParameters = new TokenValidationParameters
+                    {
+                        RoleClaimType = "roles",
+                        ValidAudiences = new string[] { Configuration["Option:Audience"], $"api://{Configuration["Option:Audience"]}" }
+                    };
+                    options.Events = new JwtBearerEvents();
+                    //下列事件有需要紀錄則打開
+                    //options.Events.OnMessageReceived = async context => { await Task.FromResult(0); };
+                    //options.Events.OnForbidden = async context => { await Task.FromResult(0); };
+                    //options.Events.OnChallenge = async context => { await Task.FromResult(0); };
+                    //options.Events.OnAuthenticationFailed = async context => { await Task.FromResult(0); };
+                    options.Events.OnTokenValidated = async context =>
+                    {
+                        if (!context.Principal.Claims.Any(x => x.Type == "http://schemas.microsoft.com/identity/claims/scope") //ClaimConstants.Scope
+                        && !context.Principal.Claims.Any(y => y.Type == "roles")) //ClaimConstants.Roles //http://schemas.microsoft.com/ws/2008/06/identity/claims/role
+                        {
+                            //TODO 需處理額外授權非角色及範圍的訪問異常紀錄
+                            throw new UnauthorizedAccessException("Neither scope or roles claim was found in the bearer token.");
+                        }
+                        await Task.FromResult(0);
+                    };
+                });
             //設定跨域請求
             services.AddCors(options =>
             {
@@ -50,6 +85,9 @@ namespace TEAMModelAPI
             services.AddHttpClient();
             services.AddHttpClient<DingDing>();
             services.AddAzureServiceBus(Configuration.GetValue<string>("Azure:ServiceBus:ConnectionString"));
+            //HttpContextAccessor,并用来访问HttpContext。(提供組件或非控制器服務存取HttpContext)
+            services.AddHttpContextAccessor();
+            services.Configure<Option>(options => Configuration.GetSection("Option").Bind(options));
         }
 
         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

+ 1 - 2
TEAMModelAPI/TEAMModelAPI.csproj

@@ -5,7 +5,6 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <ProjectReference Include="..\TEAMModelOS\TEAMModelOS.csproj" />
+    <ProjectReference Include="..\TEAMModelOS.SDK\TEAMModelOS.SDK.csproj" />
   </ItemGroup>
-
 </Project>

+ 13 - 1
TEAMModelAPI/appsettings.json

@@ -6,5 +6,17 @@
       "Microsoft.Hosting.Lifetime": "Information"
     }
   },
-  "AllowedHosts": "*"
+  "AllowedHosts": "*",
+  "Option": {
+    "Location": "China",
+    "LocationNum": "8",
+    "HostName": "localhost:5001",
+    "AllowedHosts": [ "localhost", "*.teammodel.cn", "*.teammodel.net", "*.habookaclass.biz", "test" ],
+    "Authority": "https://login.chinacloudapi.cn/4807e9cf-87b8-4174-aa5b-e76497d7392b/v2.0", //China:"https://login.chinacloudapi.cn/4807e9cf-87b8-4174-aa5b-e76497d7392b/v2.0", //Global:"https://login.microsoftonline.com/73a2bcc5-fe99-4566-aa8a-07e7bb287df1/v2.0"
+    "Audience": "72643704-b2e7-4b26-b881-bd5865e7a7a5", //China:"72643704-b2e7-4b26-b881-bd5865e7a7a5",Global:"8768b06f-c5c5-4b0c-abfb-d7ded354626d"
+    "Issuer": "www.teammodel.cn",
+    "JwtSecretKey": "fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=",
+    "Exp": 86400,
+    "IdTokenSalt": "8263692E2213497BB55E74792B7900B4"
+  }
 }

+ 1 - 1
TEAMModelOS.SDK/DI/AzureStorage/AzureStorageFactory.cs

@@ -156,7 +156,7 @@ namespace TEAMModelOS.SDK.DI
                 BlobContainerSasPermissions blobContainerSasPermissions = BlobContainerSasPermissions.Read;
                 if (isRead)
                 {
-                    blobContainerSasPermissions = BlobContainerSasPermissions.Read;
+                    blobContainerSasPermissions = BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List;
                 }
                 else
                 {

+ 2 - 2
TEAMModelOS.SDK/Extension/JwtAuthExtension.cs

@@ -81,11 +81,11 @@ namespace TEAMModelOS.SDK.Extension
                 var handler = new JwtSecurityTokenHandler();
                 var validationParameters = new TokenValidationParameters
                 {
-                    RequireExpirationTime = true,
+                    RequireExpirationTime = false,
                     ValidateIssuer = false,
                     ValidateAudience = false,
                     IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(salt)),
-                    //ValidateLifetime = false,
+                    ValidateLifetime = false,
                     //LifetimeValidator = LifetimeValidator,
                     ClockSkew = TimeSpan.Zero
                 };

+ 72 - 1
TEAMModelOS.SDK/Models/Cosmos/Api/OpenApi.cs

@@ -28,22 +28,93 @@ namespace TEAMModelOS.SDK.Models
 
             PartitionKey = "IES5-API";
         } 
+        /// <summary>
+        /// 接口名称
+        /// </summary>
         public string name { get; set; }
+        /// <summary>
+        /// 接口url
+        /// </summary>
         public string url { get; set; }
+        /// <summary>
+        /// 请求方法
+        /// </summary>
         public string method { get; set; }
+        /// <summary>
+        /// 开放的api接口
+        /// </summary>
         public string descr { get; set; }
         public int auth { get; set; }
-
+        /// <summary>
+        /// r,w,d,l
+        /// </summary>
+        public string type { get; set; }
     }
+    [TableName(Name = "OpenApi")]
+    public class Webhook : TableEntity
+    {
+        public Webhook()
+        {
 
+            PartitionKey = "IES5-WEBHOOK";
+        }
+        /// <summary>
+        /// 接口名称
+        /// </summary>
+        public string name { get; set; }
+        /// <summary>
+        /// 接口url
+        /// </summary>
+        public string url { get; set; }
+        /// <summary>
+        /// 请求方法
+        /// </summary>
+        public string method { get; set; }
+        /// <summary>
+        /// 开放的api接口
+        /// </summary>
+        public string descr { get; set; }
+        public int auth { get; set; }
+        /// <summary>
+        /// r,w,d,l
+        /// </summary>
+        public string type { get; set; }
+    }
     public class OpenApp : CosmosEntity {
+        /// <summary>
+        /// 图标
+        /// </summary>
         public string icon { get; set; }
+        /// <summary>
+        /// 应用名称
+        /// </summary>
         public string name { get; set; }
+        /// <summary>
+        /// 应用描述
+        /// </summary>
         public string descr { get; set; }
+        /// <summary>
+        /// 授权信息
+        /// </summary>
         public List<int> auths { get; set; } = new List<int>();
+        public List<int> webhooks { get; set; } = new List<int>();
+        /// <summary>
+        /// 学校编码
+        /// </summary>
         public string school { get; set; }
+        /// <summary>
+        /// 生成的token
+        /// </summary>
         public string token { get; set; }
         /// <summary>
+        /// domain的域名
+        /// </summary>
+        public string domain { get; set; }
+        /// <summary>
+        ///webhook
+        /// </summary>
+        public string webhookToken { get; set; }
+        /// <summary>
         /// 0禁用,1正常,2 token封禁
         /// </summary>
         public int status { get; set; }

+ 3 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/Snode.cs

@@ -2,6 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.Text;
+using System.Text.Json;
 
 namespace TEAMModelOS.SDK.Models.Cosmos.Common
 {
@@ -63,6 +64,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         /// <summary>
         /// 存放地址 外部链接是绝对地址有http   blob是相对地址
         /// </summary>
-        public List<string> link { get; set; }
+        public string link { get; set; }
+       
     }
 }

+ 9 - 2
TEAMModelOS.SDK/Models/Cosmos/Common/Syllabus.cs

@@ -32,7 +32,14 @@ namespace TEAMModelOS.SDK.Models
     {
         public string tmdid { get; set; }
         public string tmdname { get; set; }
-        public bool coedit { get; set; }
-        public bool share { get; set; }
+        /// <summary>
+        /// 分享  type=coedit共编,share分享
+        /// </summary>
+        public string type { get; set; }
+        /// <summary>
+        /// 是否同意
+        /// </summary>
+        public int agree { get; set; } = 0;
     }
+     
 }

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

@@ -27,7 +27,7 @@ namespace TEAMModelOS.SDK.Models
         /// <summary>
         /// 学校编码或教师tmdid
         /// </summary>
-        [Required(ErrorMessage = "school 必须设置")]
+       // [Required(ErrorMessage = "school 必须设置")]
         public string school { get; set; }
         /// <summary>
         /// 投票名称

+ 1 - 0
TEAMModelOS.SDK/Models/Cosmos/School/Paper.cs

@@ -62,6 +62,7 @@ namespace TEAMModelOS.SDK.Models
         public int multipleRule { get; set; }
         //记录试卷大小
         public long? size { get; set; } = 0;
+        
         /// <summary>
         /// type:{
         ///     pointkey:[num1,num2....]

+ 15 - 23
TEAMModelOS.SDK/Models/Cosmos/Teacher/Share.cs

@@ -45,14 +45,6 @@ namespace TEAMModelOS.SDK.Models
         [Required(ErrorMessage = "scope 必须设置")]
         public string scope { get; set; }
         /// <summary>
-        /// 共编
-        /// </summary>
-        public bool coedit { get; set; }
-        /// <summary>
-        /// 分享
-        /// </summary>
-        public bool share { get; set; }
-        /// <summary>
         /// 册别id
         /// </summary>
         public string volumeId { get; set; }
@@ -65,14 +57,15 @@ namespace TEAMModelOS.SDK.Models
         /// 册别名称
         /// </summary>
         public string volumeName { get; set; }
+       
         /// <summary>
-        /// 共编-是否同意
+        /// 分享  type=coedit共编,share分享
         /// </summary>
-        public bool cagree { get; set; } = false;
+        public string type { get; set; }
         /// <summary>
-        /// 分享-是否同意
+        /// 是否同意
         /// </summary>
-        public bool sagree { get; set; } = false;
+        public int agree { get; set; } = 0;
     }
     /// <summary>
     /// 主动分享给谁,当接收者接收并完成相关资源复制后则删除本条数据。
@@ -97,15 +90,7 @@ namespace TEAMModelOS.SDK.Models
 
         [Required(ErrorMessage = "tmdid 必须设置")]
         public List<TmdInfo> tmdInfo { get; set; } = new List<TmdInfo>();
-        
-        /// <summary>
-        /// 共编权限
-        /// </summary>
-        public bool coedit { get; set; } = false;
-        /// <summary>
-        /// 分享权限
-        /// </summary>
-        public bool share { get; set; } = false;
+      
         /// <summary>
         /// 课纲章节的id
         /// </summary>
@@ -129,7 +114,14 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         [Required(ErrorMessage = "issuer 必须设置")]
         public string issuer { get; set; }
-    }
-
 
+        /// <summary>
+        /// 分享  type=coedit共编,share分享
+        /// </summary>
+        public string type { get; set; }
+        /// <summary>
+        /// 是否同意
+        /// </summary>
+        public int agree { get; set; } = 0;
+    }
 }

+ 1 - 0
TEAMModelOS/ClientApp/package.json

@@ -34,6 +34,7 @@
 		"firestore": "^1.1.6",
 		"html2canvas": "^1.0.0-rc.7",
 		"html2pdf.js": "^0.9.3",
+		"i18next": "^20.3.1",
 		"imports-loader": "^0.8.0",
 		"increase-memory-limit": "^1.0.7",
 		"js-sha1": "^0.6.0",

+ 7 - 0
TEAMModelOS/ClientApp/src/api/evaluation.js

@@ -0,0 +1,7 @@
+import { fetch, post } from '@/api/http'
+
+export default {
+    getFilterCount: function (data) {        
+        return post('/item/cond-count', data)
+    }
+}

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

@@ -20,7 +20,7 @@ export default{
      * @param {} data
      */
     getApiList: function (data) {
-        return post('/open-api/get', data)
+        return post('/open-api/get-api', data)
     },
     /**
      * 新增/编辑

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

@@ -4,4 +4,8 @@ export default {
     getNotification: function (data) {
         return post('https://api2.teammodel.net/service/getnotification', data)
     },
+    /* 获取id详细信息 */
+    getIdProfile: function (host,data) {
+        return post(`${host}/oauth2/profile`, data)
+    },
 }

+ 5 - 0
TEAMModelOS/ClientApp/src/api/studentWeb.js

@@ -225,4 +225,9 @@ export default {
 	isAnswerd: function (data) {
 	    return post('/common/survey/answered',data)
 	},
+
+    // 删除不存在的投票和问卷
+    delActivity: function (data) {
+        return post("/common/delete-activity", data)
+    }
 }

+ 3 - 0
TEAMModelOS/ClientApp/src/api/syllabus.js

@@ -28,6 +28,9 @@ export default {
 	ViewShare:function(data) {
 	    return post('/teacher/share/view-share', data)
 	},
+	ShareAgree:function(data) {
+	    return post('/teacher/share/agree-share', data)
+	},
 	// 查找知识块数量
 	FindBlockCount: function (data) {
 		return post('/knowledges/find-count', data)

+ 26 - 3
TEAMModelOS/ClientApp/src/assets/iconfont/demo_index.html

@@ -54,6 +54,12 @@
       <div class="content unicode" style="display: block;">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+              <span class="icon iconfont">&#xe6c3;</span>
+                <div class="name">开放</div>
+                <div class="code-name">&amp;#xe6c3;</div>
+              </li>
+          
             <li class="dib">
               <span class="icon iconfont">&#xe718;</span>
                 <div class="name">在籍学生</div>
@@ -810,9 +816,9 @@
 <pre><code class="language-css"
 >@font-face {
   font-family: 'iconfont';
-  src: url('iconfont.woff2?t=1623427872430') format('woff2'),
-       url('iconfont.woff?t=1623427872430') format('woff'),
-       url('iconfont.ttf?t=1623427872430') format('truetype');
+  src: url('iconfont.woff2?t=1624327216353') format('woff2'),
+       url('iconfont.woff?t=1624327216353') format('woff'),
+       url('iconfont.ttf?t=1624327216353') format('truetype');
 }
 </code></pre>
           <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -838,6 +844,15 @@
       <div class="content font-class">
         <ul class="icon_lists dib-box">
           
+          <li class="dib">
+            <span class="icon iconfont icon-open"></span>
+            <div class="name">
+              开放
+            </div>
+            <div class="code-name">.icon-open
+            </div>
+          </li>
+          
           <li class="dib">
             <span class="icon iconfont icon-student1"></span>
             <div class="name">
@@ -1972,6 +1987,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-open"></use>
+                </svg>
+                <div class="name">开放</div>
+                <div class="code-name">#icon-open</div>
+            </li>
+          
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#icon-student1"></use>

+ 7 - 3
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css

@@ -1,8 +1,8 @@
 @font-face {
   font-family: "iconfont"; /* Project id 2000444 */
-  src: url('iconfont.woff2?t=1623427872430') format('woff2'),
-       url('iconfont.woff?t=1623427872430') format('woff'),
-       url('iconfont.ttf?t=1623427872430') format('truetype');
+  src: url('iconfont.woff2?t=1624327216353') format('woff2'),
+       url('iconfont.woff?t=1624327216353') format('woff'),
+       url('iconfont.ttf?t=1624327216353') format('truetype');
 }
 
 .iconfont {
@@ -13,6 +13,10 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-open:before {
+  content: "\e6c3";
+}
+
 .icon-student1:before {
   content: "\e718";
 }

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 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": "20587121",
+      "name": "开放",
+      "font_class": "open",
+      "unicode": "e6c3",
+      "unicode_decimal": 59075
+    },
     {
       "icon_id": "8827519",
       "name": "在籍学生",

BIN
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.ttf


BIN
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff


BIN
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff2


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

@@ -1,6 +1,6 @@
 <template>
 	<div class="app-container">
-		<div id="container" ref="container" class="container" />
+		<div id="containers" ref="container" class="container" />
 	</div>
 </template>
 
@@ -60,7 +60,7 @@
 			initStage() {
 				let that = this
 				var stage = new Konva.Stage({
-					container: 'container',
+					container: 'containers',
 					width: this.config.canvasWidth,
 					height: this.config.canvasHeight
 				});

+ 11 - 1
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -335,7 +335,17 @@ export default {
                     menuName: 'totalIndex',
                     child: []
                 },
-
+                //开放平台
+                {
+                    icon: 'iconfont icon-open',
+                    name: this.$t('settings.setting_title3'),
+                    router: '/home/OpenPlat',
+                    tag: '',
+                    role: 'admin',
+                    permission: '',
+                    menuName: 'OpenPlat',
+                    child: []
+                }
             ] : []
             this.teacherMenu = [
                 // 我的班级

+ 8 - 2
TEAMModelOS/ClientApp/src/common/BaseMyCanvas.vue

@@ -1,6 +1,7 @@
 <template>
 	<div id="baseCanvas" @mouseover="mouseOver" @mouseleave="mouseLeave">
 		<!-- <BaseCanvas class="sign-canvas" ref="SignCanvas" :options="options"/> -->
+		<!-- <BaseCanvas class="sign-canvas" ref="SignCanvas" :options="options" :status="curMode"/> -->
 		<BaseKonva class="sign-canvas" ref="SignCanvas" :options="options"/>
 		<div class="canvas-tools animated fadeIn" ref="canvasTools">
 			<span :class="['canvas-tools-item',curMode === 'move' ? 'tools-active' : '']" @click="doMove()" style="border-radius: 15px 0 0 0;">
@@ -56,7 +57,7 @@
 	</div>
 </template>
 <script>
-	import BaseCanvas from './BaseCanvas.vue';
+	import BaseCanvas from '@/view/task/mark/MarkCanvas.vue';
 	export default {
 		components: {
 			BaseCanvas
@@ -94,6 +95,8 @@
 				activeColor: 'black',
 				curMode:'paint',
 				options: {
+					width: 1200,         //画布宽度
+					height: 480, 
 					textColor:'red',
 					textSize:16,
 					isDpr: false, //是否使用dpr兼容高分屏 [Boolean] 可选
@@ -108,6 +111,8 @@
 					borderWidth: 2, // 网格线宽度  [Number] 可选
 					borderColor: "#7c7c7c", //网格颜色  [String] 可选
 					writeWidth: 5, //基础轨迹宽度  [Number] 可选
+					lineColor: 'red', // 轨迹颜色  [String] 可选
+					lineWidth: 5, //基础轨迹宽度  [Number] 可选
 					writeColor: 'red', // 轨迹颜色  [String] 可选
 					isSign: true, //签名模式 [Boolean] 默认为非签名模式,有线框, 当设置为true的时候没有任何线框
 					imgType: 'png' //下载的图片格式  [String] 可选为 jpeg  canvas本是透明背景的
@@ -138,7 +143,7 @@
 			},
 			
 			doPaint(){
-				this.curMode = 'paint'
+				this.curMode = 'line'
 				this.$refs.SignCanvas.mode = 'paint'
 			},
 			
@@ -162,6 +167,7 @@
 			},
 
 			onSelectWriteWidth(val) {
+				this.options.lineWidth = val
 				this.options.writeWidth = val
 				this.activeDot = val
 			},

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

@@ -1,6 +1,6 @@
 <template>
 	<div class="base-notification">
-		<Poptip :title="$t('utils.newNotice')" class="dark-iview-poptip">
+		<Poptip :title="$t('utils.newNotice')" class="dark-iview-poptip" placement="bottom">
 			<Badge :count="msgArr.length">
 				<Icon type="md-notifications" />
 			</Badge>

+ 405 - 346
TEAMModelOS/ClientApp/src/common/BaseUserPoptip.vue

@@ -1,28 +1,50 @@
 <template>
-	<div class="base-user-center">
-		<div style="display: flex;">
-			<div class="base-user-info">
-				<p class="base-user-name">{{ userInfo.username }}</p>
-				<!-- <p class="base-user-post">教务主任</p> -->
-				<Dropdown @on-click="onRoleSelect">
-					<a href="javascript:void(0)" class="base-user-post">
-						{{ getRoleName(curRole) }}
-						<Icon type="ios-arrow-down"></Icon>
-					</a>
-					<DropdownMenu slot="list">
-						<DropdownItem v-if="curRole != 'teacher' && curRole != 'admin'" name="teacher">{{ $t('utils.teacher') }}</DropdownItem>
-						<DropdownItem v-if="curRole != 'student'" name="student">{{ $t('utils.student') }}</DropdownItem>
-						<!-- <DropdownItem  name="student">學生</DropdownItem> -->
-					</DropdownMenu>
-				</Dropdown>
-			</div>
-			<Poptip class="dark-iview-poptip" @on-popper-show="doRefresh()">
-				<!-- <img :src="user.picture" /> -->
+    <div class="base-user-center">
+        <div style="display: flex;">
+            <div class="base-user-info">
+                <!-- <p class="base-user-name" style="margin-top:6px">{{ userInfo.username }}</p> -->
+                <!-- <Dropdown @on-click="onRoleSelect">
+                    <a href="javascript:void(0)" class="base-user-post">
+                        {{ getRoleName(curRole) }}
+                        <Icon type="ios-arrow-down"></Icon>
+                    </a>
+                    <DropdownMenu slot="list">
+                        <DropdownItem v-if="curRole != 'teacher' && curRole != 'admin'" name="teacher">{{ $t('utils.teacher') }}</DropdownItem>
+                        <DropdownItem v-if="curRole != 'student'" name="student">{{ $t('utils.student') }}</DropdownItem>
+                    </DropdownMenu>
+                </Dropdown> -->
+            </div>
+            <Dropdown placement="bottom-end">
+                <PersonalPhoto style="cursor: pointer;" :name="userInfo.username" :picture="user.picture" :color="userInfo.nameColor" />
+                <DropdownMenu slot="list" class="user-center-wrap">
+                    <DropdownItem class="user-info-wrap" @click.native="toUserCenter()">
+                        <p>{{userInfo.username}}</p>
+                        <p class="user-id">{{`ID: ${user.id}`}}</p>
+                        <Icon class="user-info-arrow" type="ios-arrow-forward" color="#1cc0f3" />
+                    </DropdownItem>
+                    <DropdownItem class="drop-item" style="margin-top:8px" @click.native="onRoleSelect('student')">
+                        <Icon type="md-swap" class="drop-item-icon" />
+                        切换为学生
+                    </DropdownItem>
+                    <DropdownItem class="drop-item" @click.native="toSettings('1')">
+                        <Icon custom="iconfont icon-school" class="drop-item-icon" />
+                        学校管理
+                    </DropdownItem>
+                    <DropdownItem class="drop-item" @click.native="toSettings('0')">
+                        <Icon type="ios-settings" class="drop-item-icon" />
+                        系统设置
+                    </DropdownItem>
+                    <DropdownItem divided @click.native="onQuit">
+                        <Icon type="md-power" class="drop-item-icon" />
+                        {{$t('utils.logout')}}
+                    </DropdownItem>
+                </DropdownMenu>
+            </Dropdown>
+            <!-- <Poptip class="dark-iview-poptip" @on-popper-show="doRefresh()">
 				<PersonalPhoto style="cursor: pointer;" :name="userInfo.username" :picture="user.picture" :color="userInfo.nameColor"/>
 
 				<div slot="content" class="user-center">
 					<div class="user-info">
-						<!-- <img :src="user.picture" />     border: 2px solid #fff;-->
 						<PersonalPhoto :width="'70px'" :height="'70px'" :fontSize="'1.50rem'" :name="userInfo.username" :picture="user.picture" :color="userInfo.nameColor"/>
 
 						<span class="user-info-username">{{ userInfo.username }}</span>
@@ -72,358 +94,395 @@
 					</div>
 					<div class="btn-logout" @click="onQuit">{{ $t('utils.logout') }}</div>
 				</div>
-			</Poptip>
-		</div>
-	</div>
+			</Poptip> -->
+        </div>
+    </div>
 </template>
 
 <script>
-    import BlobTool from '@/utils/blobTool.js';
-	import PersonalPhoto from '@/components/public/personalPhoto/Index.vue'
-	export default {
-		data() {
-			return {
-				curRole: '',
-				userInfo: {
-					username: '',
-					account: '',
-					role: '',
-					courseNum: 0,
-					activityNum: 0,
-					classNum: 0,
-					nameColor: '',
-				},
-				user: {},
-                sizeInfo: {
-                    total: 0,   //所有
-                    image: 0,   //内容模块图片
-                    res: 0,     //内容模块教材
-                    video: 0,   //内容模块视频
-                    audio: 0,   //内容模块音频
-                    doc: 0,     //内容模块文档
-                    other: 0,   //内容模块其他文件
-                    data: 0      //除了内容模块之外的文件
-                }
-			}
-		},
-		created() {
-            this.doRefresh()
-		},
-		methods: {
-			doRefresh(){
-				this.user = JSON.parse(decodeURIComponent(localStorage.userInfo, "utf-8"));
-				let user_profile = JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8"));
-				if(this.user.roles.length){
-					this.curRole = this.user.roles[0]
-				}
-				this.userInfo.username = this.user.name
-				this.userInfo.nameColor = this.randomColor()
-				this.getSize()
-			},
-			//获取Blob空间信息
-			getSize() {
-                BlobTool.getSizeByServe(this.$store.state.userInfo.TEAMModelId).then(
-                    res => {
-                        this.sizeInfo = res
-                    },
-                    err => {
-                        this.$Message.error(this.$t('utils.caclErrorL'))
-                    }
-                )
-			},
-            //计算空间占比
-            getPercent(size) {
-                if (this.sizeInfo.total > this.$GLOBAL.PRIVATE_SPACE) {
-                    return '0%'
-                } else {
-                    let p = (size * 100 / this.$GLOBAL.PRIVATE_SPACE)
-					p = p > 1 ? p.toFixed(2) : p > 0 ? 1 : 0
-                    return p + '%'
-                }
+import BlobTool from '@/utils/blobTool.js';
+import PersonalPhoto from '@/components/public/personalPhoto/Index.vue'
+export default {
+    data() {
+        return {
+            curRole: '',
+            userInfo: {
+                username: '',
+                account: '',
+                role: '',
+                courseNum: 0,
+                activityNum: 0,
+                classNum: 0,
+                nameColor: '',
             },
-			onRoleSelect(val){
-				if(localStorage.getItem('identity') != val){
-					this.curRole = val
-					let path = val === 'student' ? '/studentWeb' : '/home'
-					localStorage.setItem('identity', val)
-					this.$router.push({ path: path })					
-				}
-			},
-			onQuit() {
-				this.$emit('logout')
-			},
-			randomColor: function(){
-				let r = Math.floor(Math.random()*255);
-				let g = Math.floor(Math.random()*255);
-				let b = Math.floor(Math.random()*255);
-				return 'rgba('+ r +','+ g +','+ b +',0.8)';
-			},
-		},
-
-		computed: {
-            
-			getSizeVal() {
-				return val => {
-					return this.$tools.bytesToSize(val)
-				}
-			},
-			getRoleName() {
-				return val => {
-					return val === 'student' ? this.$t('utils.student') : this.$t('utils.teacher')
-				}
-			}
-		},
-    	components:{
-			PersonalPhoto
-		}
-	}
+            user: {},
+            sizeInfo: {
+                total: 0,   //所有
+                image: 0,   //内容模块图片
+                res: 0,     //内容模块教材
+                video: 0,   //内容模块视频
+                audio: 0,   //内容模块音频
+                doc: 0,     //内容模块文档
+                other: 0,   //内容模块其他文件
+                data: 0      //除了内容模块之外的文件
+            }
+        }
+    },
+    created() {
+        this.doRefresh()
+    },
+    methods: {
+        // 这里可以携带参数,直接跳转到对应的tab
+        toSettings(tab) {
+            this.$router.push({
+                path: '/home/settings',
+                query: { tab }
+            })
+        },
+		// 这里可以携带参数,直接跳转到对应的tab
+        toUserCenter() {
+            this.$router.push({
+                name: 'userCenter'
+            })
+        },
+        doRefresh() {
+            this.user = JSON.parse(decodeURIComponent(localStorage.userInfo, "utf-8"));
+            let user_profile = JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8"));
+            if (this.user.roles.length) {
+                this.curRole = this.user.roles[0]
+            }
+            this.userInfo.username = this.user.name
+            this.userInfo.nameColor = this.randomColor()
+            this.userInfo.courseNum = user_profile.courses.length
+            this.getSize()
+        },
+        //获取Blob空间信息
+        getSize() {
+            BlobTool.getSizeByServe(this.$store.state.userInfo.TEAMModelId).then(
+                res => {
+                    this.sizeInfo = res
+                },
+                err => {
+                    this.$Message.error(this.$t('utils.caclErrorL'))
+                }
+            )
+        },
+        //计算空间占比
+        getPercent(size) {
+            if (this.sizeInfo.total > this.$GLOBAL.PRIVATE_SPACE) {
+                return '0%'
+            } else {
+                let p = (size * 100 / this.$GLOBAL.PRIVATE_SPACE)
+                p = p > 1 ? p.toFixed(2) : p > 0 ? 1 : 0
+                return p + '%'
+            }
+        },
+        onRoleSelect(val) {
+            if (localStorage.getItem('identity') != val) {
+                this.curRole = val
+                let path = val === 'student' ? '/studentWeb' : '/home'
+                localStorage.setItem('identity', val)
+                this.$router.push({ path: path })
+            }
+        },
+        onQuit() {
+            this.$emit('logout')
+        },
+        randomColor: function () {
+            let r = Math.floor(Math.random() * 255);
+            let g = Math.floor(Math.random() * 255);
+            let b = Math.floor(Math.random() * 255);
+            return 'rgba(' + r + ',' + g + ',' + b + ',0.8)';
+        },
+    },
+
+    computed: {
+
+        getSizeVal() {
+            return val => {
+                return this.$tools.bytesToSize(val)
+            }
+        },
+        getRoleName() {
+            return val => {
+                return val === 'student' ? this.$t('utils.student') : this.$t('utils.teacher')
+            }
+        }
+    },
+    components: {
+        PersonalPhoto
+    }
+}
 </script>
 <style scoped>
-    .user-storage-distribution {
-		overflow:hidden;
-	}
-    .user-storage-text span {
-		margin-right:20px;
-		display:inline-block;
-	}
-    .storage-full {
-        background-color: red;
-    }
-
-    .storage-data {
-        background-color: #F8C006;
+.drop-item-icon {
+    margin-right: 5px;
+}
+.drop-item {
+    padding: 10px 16px;
+}
+.user-info-arrow {
+    float: right;
+    margin-top: -25px;
+}
+.user-info-wrap {
+    /* background: #608f94; */
+    padding: 12px 16px;
+    box-shadow: 0px 2px 5px #eee;
+}
+.user-id {
+    color: rgb(174 176 178);
+    margin-top: 5px;
+    font-size: 12px;
+}
+.user-center-wrap {
+    min-width: 200px;
+    border-radius: 6px;
+    overflow: hidden;
+}
+.user-storage-distribution {
+    overflow: hidden;
+}
+.user-storage-text span {
+    margin-right: 20px;
+    display: inline-block;
+}
+.storage-full {
+    background-color: red;
+}
+
+.storage-data {
+    background-color: #f8c006;
+}
+
+.storage-image {
+    background-color: #45c84a;
+}
+
+.storage-video {
+    background-color: #8e2bdd;
+}
+
+.storage-audio {
+    background-color: #e1027b;
+}
+
+.storage-doc {
+    background-color: #03c0c2;
+}
+
+.storage-res {
+    background-color: #1ffcc5;
+}
+
+.storage-other {
+    background-color: #e87b22;
+}
+
+.text-data {
+    color: #f8c006;
+}
+
+.text-image {
+    color: #45c84a;
+}
+
+.text-video {
+    color: #8e2bdd;
+}
+
+.text-audio {
+    color: #e1027b;
+}
+
+.text-doc {
+    color: #03c0c2;
+}
+
+.text-res {
+    color: #1ffcc5;
+}
+
+.text-other {
+    color: #e87b22;
+}
+</style>
+<style lang="less">
+.base-user-center .ivu-select-dropdown {
+    padding: 0px 0px 5px 0px;
+    border-radius: 7px;
+}
+.base-user-center {
+    .base-user-info {
+        margin-right: 20px;
+        text-align: right;
+
+        .base-user-name {
+            font-weight: bold;
+            color: #b2b5b4;
+        }
+
+        .base-user-post {
+            color: #686b6b;
+        }
     }
 
-    .storage-image {
-        background-color: #45C84A;
+    img {
+        width: 40px;
+        border-radius: 50%;
+        border: 2px solid #dddddd;
+        cursor: pointer;
     }
 
-    .storage-video {
-        background-color: #8E2BDD;
+    .ivu-dropdown-item {
+        text-align: left;
     }
 
-    .storage-audio {
-        background-color: #E1027B;
+    .ivu-poptip-popper {
+        width: 460px !important;
     }
 
-    .storage-doc {
-        background-color: #03C0C2;
+    .ivu-poptip-popper {
+        left: -400px !important;
+        padding: 0;
     }
 
-    .storage-res {
-        background-color: #1FFCC5;
+    .ivu-poptip-title {
+        display: none;
     }
 
-    .storage-other {
-        background-color: #E87B22;
+    .ivu-poptip-arrow {
+        left: 90% !important;
     }
 
-    .text-data {
-        color: #F8C006;
-    }
+    .user-center {
+        height: 620px;
+        padding-top: 30px;
+
+        .user-info {
+            .fl-col-center;
+
+            img {
+                width: 70px;
+                border: 2px solid #fff;
+            }
+
+            &-username {
+                margin: 10px 0;
+                font-size: 18px;
+                font-weight: bold;
+                letter-spacing: 0.6px;
+                color: #1cc0f3;
+            }
+
+            &-account {
+                color: #a5a5a5;
+            }
+
+            &-btn {
+                background: #1cc0f3;
+                padding: 5px 60px;
+                color: #fff;
+                margin-top: 20px;
+                border-radius: 5px;
+                cursor: pointer;
+            }
+        }
+
+        .user-nums {
+            display: flex;
+            justify-content: space-around;
+            padding-top: 60px;
+
+            &-item {
+                .fl-col-center;
+
+                span {
+                    &:first-child {
+                        font-size: 34px;
+                        font-weight: bold;
+                        color: #fff;
+                    }
 
-    .text-image {
-        color: #45C84A;
-    }
+                    &:last-child {
+                        font-size: 14px;
+                        color: #1cc0f3;
+                    }
+                }
+            }
+        }
+
+        .user-storage {
+            padding-top: 50px;
+
+            p {
+                text-align: center;
+                color: #a5a5a5;
+                font-size: 12px;
+            }
+
+            &-distribution {
+                margin: 15px 0;
+                height: 10px;
+                width: 100%;
+                border-radius: 50px;
+                background-color: #888888;
+                display: flex;
+
+                span {
+                    display: inline-block;
+                    width: 50px;
+                    height: 10px;
+                }
 
-    .text-video {
-        color: #8E2BDD;
-    }
+                &-green {
+                    border-radius: 5px 0 0 5px;
+                    background-color: #00d523;
+                }
 
-    .text-audio {
-        color: #E1027B;
-    }
+                &-orange {
+                    background-color: #e87b22;
+                }
 
-    .text-doc {
-        color: #03C0C2;
-    }
+                &-red {
+                    background-color: #ff40bc;
+                }
 
-    .text-res {
-        color: #1FFCC5;
+                &-blue {
+                    background-color: #1fccd5;
+                }
+            }
+
+            &-text {
+                margin-top: 10px;
+                font-size: 12px;
+                font-weight: bold;
+                white-space: normal;
+                /*display: flex;
+					flex-wrap: wrap;
+					justify-content: space-around;*/
+            }
+        }
+
+        .btn-logout {
+            .fl-col-center;
+            background: #1cc0f3;
+            padding: 6px 0;
+            color: #fff;
+            width: 60%;
+            margin-left: 20%;
+            margin-top: 40px;
+            border-radius: 5px;
+            font-size: 16px;
+            cursor: pointer;
+        }
     }
 
-    .text-other {
-        color: #E87B22;
+    .fl-col-center {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
     }
-</style>
-<style lang="less">
-	.base-user-center {
-		.base-user-info {
-			margin-right: 20px;
-			text-align: right;
-
-			.base-user-name {
-				font-weight: bold;
-				color: #b2b5b4;
-			}
-
-			.base-user-post {
-				color: #686b6b;
-			}
-		}
-
-
-		img {
-			width: 40px;
-			border-radius: 50%;
-			border: 2px solid #dddddd;
-			cursor: pointer;
-		}
-		
-		.ivu-dropdown-item{
-			text-align: left;
-		}
-
-		.ivu-poptip-popper {
-			width: 460px !important;
-		}
-
-		.ivu-poptip-popper {
-			left: -400px !important;
-			padding: 0;
-		}
-
-		.ivu-poptip-title {
-			display: none;
-		}
-
-		.ivu-poptip-arrow {
-			left: 90% !important;
-		}
-
-		.user-center {
-			height: 620px;
-			padding-top: 30px;
-
-			.user-info {
-				.fl-col-center;
-
-				img {
-					width: 70px;
-					border: 2px solid #fff;
-				}
-
-				&-username {
-					margin: 10px 0;
-					font-size: 18px;
-					font-weight: bold;
-					letter-spacing: .6px;
-					color: #1CC0F3;
-				}
-
-				&-account {
-					color: #a5a5a5;
-				}
-
-				&-btn {
-					background: #1CC0F3;
-					padding: 5px 60px;
-					color: #fff;
-					margin-top: 20px;
-					border-radius: 5px;
-					cursor: pointer;
-				}
-
-			}
-
-
-			.user-nums {
-				display: flex;
-				justify-content: space-around;
-				padding-top: 60px;
-
-				&-item {
-					.fl-col-center;
-
-					span {
-
-						&:first-child {
-							font-size: 34px;
-							font-weight: bold;
-							color: #fff
-						}
-
-						&:last-child {
-							font-size: 14px;
-							color: #1CC0F3
-						}
-					}
-
-					;
-				}
-			}
-
-			.user-storage {
-				padding-top: 50px;
-
-				p {
-					text-align: center;
-					color: #a5a5a5;
-					font-size: 12px;
-				}
-
-				&-distribution {
-					margin: 15px 0;
-					height: 10px;
-					width: 100%;
-					border-radius: 50px;
-					background-color: #888888;
-					display: flex;
-
-					span {
-						display: inline-block;
-						width: 50px;
-						height: 10px;
-					}
-
-					&-green {
-						border-radius: 5px 0 0 5px;
-						background-color: #00D523;
-					}
-
-					&-orange {
-						background-color: #e87b22;
-					}
-
-					&-red {
-						background-color: #ff40bc;
-					}
-
-					&-blue {
-						background-color: #1fccd5;
-					}
-				}
-
-				&-text {
-					margin-top: 10px;
-					font-size: 12px;
-					font-weight: bold;
-					white-space:normal;
-					/*display: flex;
-					flex-wrap: wrap;
-					justify-content: space-around;*/
-				}
-			}
-
-			.btn-logout {
-				.fl-col-center;
-				background: #1CC0F3;
-				padding: 6px 0;
-				color: #fff;
-				width: 60%;
-				margin-left: 20%;
-				margin-top: 40px;
-				border-radius: 5px;
-				font-size: 16px;
-				cursor: pointer;
-			}
-		}
-
-		.fl-col-center {
-			display: flex;
-			flex-direction: column;
-			align-items: center;
-			justify-content: center;
-		}
-	}
+}
 </style>

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

@@ -182,7 +182,7 @@
 			}
 		},
 		data() {
-			return {
+			return { 
 				examPropScope:null,
 				dataLoading: false,
 				exersicesType: this.$GLOBAL.EXERCISE_TYPES(),

+ 5 - 8
TEAMModelOS/ClientApp/src/components/questionnaire/BaseQuestionnaire.vue

@@ -182,7 +182,7 @@
 			// 提取富文本内容中的文本
 			getSimpleText(html) {
 				var r = /<(?!img|video|audio).*?>/g;
-				return html.replace(r, "");
+				return html.replace(r, "").replace(/&nbsp;/g, ' ');
 			},
 			
 			// 检测是否有空选项
@@ -354,12 +354,7 @@
 					return 0 
 				}
 			},
-			
-			// 提取富文本内容中的文本
-			getSimpleText(html) {
-				var r = /<(?!img|video|audio).*?>/g;
-				return html.replace(r, "");
-			},
+
 			
 			async getQnRecord(item) {
 				return new Promise(async (r, j) => {
@@ -434,7 +429,9 @@
 			isEdit:{
 				handler(n,o){
 					this.editable = n
-				}
+					console.log(n)
+				},
+				immediate:true
 			}
 		}
 	};

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

@@ -1,26 +1,27 @@
 <template>
-    <div class="event-content">
+    <!-- <div class="event-content"> -->
+    <div class="eventContentArea-view">
         <!--<VoteHint v-if="this.$store.getters.getisVoteResulthover==true"/>-->
-        <div v-if="this.$store.getters.getIsSelectedNow">
+        <div v-if="getIsSelectedNow">
 
-            <!--<div v-if="this.$store.getters.getItemTitle.eventType=='preview'">
+            <!--<div v-if="getItemTitle.eventType=='preview'">
               <PreviewMission/>
             </div>
-            <div v-if="this.$store.getters.getItemTitle.eventType=='homeWork'">
+            <div v-if="getItemTitle.eventType=='homeWork'">
               <Homework/>
             </div>-->
-            <div v-if="this.$store.getters.getItemTitle.eventType == 'Exam'">
+            <div v-if="getItemTitle.eventType == 'Exam'">
                 <PaperView />
             </div>
-            <div v-if="this.$store.getters.getItemTitle.eventType == 'Vote'">
+            <div v-if="getItemTitle.eventType == 'Vote'">
                 <Vote />
             </div>
-            <div v-if="this.$store.getters.getItemTitle.eventType == 'Survey'">
+            <div v-if="getItemTitle.eventType == 'Survey'">
                 <QuesNaire />
             </div>
         </div>
         <!-- 如果篩選時未選的時候預設顯示列表第一個-->
-        <div class="noSelected" v-if="!this.$store.getters.getIsSelectedNow">
+        <div class="noSelected" v-if="!getIsSelectedNow">
             <h3>{{$t("studentWeb.event.selectActivity")}}</h3>
         </div>
 
@@ -34,6 +35,7 @@
     import PaperView from "./EventContentTypeTemplate/PaperView";
     import VoteHint from "./EventContentTypeTemplate/VoteHint";
     import QuesNaire from "./EventContentTypeTemplate/QuesNaire";
+    import { mapGetters } from 'vuex';
     export default {
         name: "EventContent",
         components: {
@@ -51,9 +53,16 @@
         data() {
             return {
             };
+        },
+        computed: {
+            ...mapGetters([
+                "getIsSelectedNow",
+                "getItemTitle"
+            ])
         }
     };
 </script>
 
-<style>
+<style scoped>
+@import "EventContentArea.css";
 </style>

+ 72 - 64
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue

@@ -1,11 +1,11 @@
 <template>
     <div class="lesson-test-report">
         <div class="scoreboard">
-            <div v-show="$store.getters.getItemTitle.progress == 'finish' && testState == 1">
+            <div v-show="getItemTitle.progress == 'finish' && testState == 1">
                 <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 v-show="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>
@@ -209,24 +209,25 @@
                         <div class="rightAnalys">
                             <div class="TitleRec2"><span style="margin-left:5px">{{$t("studentWeb.exam.report.testAns")}}:</span></div>
                             <br />
-                            <div style="display:flex">
+                            <div style="display: flex">
                                 <div v-for="(item,index) in question.answer" :key="index" v-html="item" style="margin-left:10px;"></div>
                             </div>
-                            <div class="TitleRec2"><span style="margin-left:5px">{{$t("studentWeb.exam.report.testAnalyse")}}:</span></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 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 style="margin-left: 10px; display: flex" v-show="examInfo.stuScore[index] != -1 && examInfo.stuScore[index] != question.score">
                                 <span v-if="question.repair.length == 0">{{$t("studentWeb.exam.report.noSource")}}</span>
                                 <div v-if="question.repair && question.repair.length > 0" class="repair-box">
                                     <Collapse style="width:85%" accordion @on-change="getSource(question.repair,question)">
+                                        <!-- 网络资源 -->
                                         <Panel name="1">
                                             {{$t("studentWeb.exam.report.linkSource")}}
                                             <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">
+                                                        <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>
@@ -236,6 +237,7 @@
                                                 </List>
                                             </p>
                                         </Panel>
+                                        <!-- 文件资源 -->
                                         <Panel name="2">
                                             {{$t("studentWeb.exam.report.fileSource")}}
                                             <p slot="content">
@@ -315,6 +317,7 @@
     import LessonTestReportCharts from "./LessonTestReportCharts/LessonTestReportCharts";
     import Loading from "vue-loading-overlay";
     import "vue-loading-overlay/dist/vue-loading.css";
+    import { mapGetters } from 'vuex';
     export default {
         name: "LessonTestReport",
         components: {
@@ -344,17 +347,17 @@
                 //loading畫面
                 closeAnsDetail: false,
                 checkedAns: ["right", "wrong", "noAns"],
-                testState: 0,// 表示有没有作答
+                testState: 0, //1:未作答  2:未评分  3:已评分
                 paperData: [], //所有题目信息
-                ansData: [],
+                ansData: [], //题目的作答答案
                 repairSource: {
-                    normal: [],
-                    file: []
+                    normal: [], //网络资源
+                    file: [] //文件资源
                 },
                 repairData: [],
-                previewStatus: false,
+                previewStatus: false, //展示补救资源
                 previewFile: {},
-                numPages:null
+                numPages: null //pdf的页数
             };
         },
         mounted() {
@@ -362,11 +365,13 @@
             this.testJudge()
         },
         methods: {
+            // 关闭Modal
             closePreview() {
                 this.previewStatus = !this.previewStatus
                 this.previewFile = {}
             },
-           async getItemData(data) {
+            // 点击文件资源
+            async getItemData(data) {
                this.previewStatus = false
                 if (data.file) {
                     this.previewFile = this._.cloneDeep(data)
@@ -444,10 +449,17 @@
             },
             showTest() {
                 if (this.examInfo.subject !== undefined) {
-                    console.log(this.examInfo);
                     this.$store.commit("ToggleLessonTestPopWithSubject", this.examInfo)
                 }
             },
+            // 判断题型
+            getTestType(data) {
+                for (let item of this.$t('global.testType')) {
+                    if (item.value == data) {
+                        return item.label
+                    }
+                }
+            },
             //判断作答情况
             testJudge() {
                 if (this.examInfo.subject !== undefined) {
@@ -471,51 +483,13 @@
                     }
                 }
             },
-            getTestType(data) {
-                for (let item of this.$t('global.testType')) {
-                    if (item.value == data) {
-                        return item.label
-                    }
-                }
-            },
-            //获取学生作答数据
-            async getItem(data) {
-                let datas = []
-                if (data !== undefined) {
-                    let codes = this.$store.getters.getItemTitle
-                    let code = {
-                        scope: codes.scope,
-                        code: codes.scope === 'school' ? codes.school : codes.creatorId,
-                        blob: data
-                    }
-                    let blob = this.formUrl(code)
-                    code.blob = blob
-                    datas = await this.$evTools.getComposeItem(code)
-                    return datas
-                } else {
-                    return []
-                }
-            },
-            //处理学生作答数据blob地址
-            formUrl(data) { 
-                let a = ""
-                if (data.blob.indexOf('https://teammodelstorage') > -1) {
-                    a = data.blob
-                } else {
-                    let blobUrl = JSON.parse(decodeURIComponent(localStorage.student_profile, "utf-8")).blob_uri
-                    let studentBlob = blobUrl.split('/')
-                    let url = data.scope == 'school' ? blobUrl : "https://" + studentBlob[studentBlob.length - 2] + '/' + this.$store.getters.getItemTitle.creatorId
-                    a = `${url}/exam/${data.blob}`
-                }
-                return a 
-            },
             async formPaper() {
                 let paper = []
                 this.paperData.length = 0
                 this.ansData.length = 0
-                let data = this.$store.getters.getPaperInfo.item
+                let data = this.getPaperInfo.item
                 let exam = [...data]
-                if (this.$store.getters.getPaperInfo.item.length) {
+                if (this.getPaperInfo.item.length) {
                     for (let i = 0; i < exam.length; i++) {
                         if (exam[i].repair == undefined) {
                             exam[i].repair = []
@@ -545,8 +519,36 @@
                     this.ansData= await this.getItem(this.examInfo.stuAns[0])
                 }
             },
-            closeDetail() {
-                this.closeAnsDetail = !this.closeAnsDetail;
+            // 获取学生作答数据
+            async getItem(data) {
+                let datas = []
+                if (data !== undefined) {
+                    let codes = this.getItemTitle
+                    let code = {
+                        scope: codes.scope,
+                        code: codes.scope === 'school' ? codes.school : codes.creatorId,
+                        blob: data
+                    }
+                    let blob = this.formUrl(code)
+                    code.blob = blob
+                    datas = await this.$evTools.getComposeItem(code)
+                    return datas
+                } else {
+                    return []
+                }
+            },
+            // 处理学生作答数据blob地址
+            formUrl(data) { 
+                let a = ""
+                if (data.blob.indexOf('https://teammodelstorage') > -1) {
+                    a = data.blob
+                } else {
+                    let blobUrl = JSON.parse(decodeURIComponent(localStorage.student_profile, "utf-8")).blob_uri
+                    let studentBlob = blobUrl.split('/')
+                    let url = data.scope == 'school' ? blobUrl : "https://" + studentBlob[studentBlob.length - 2] + '/' + this.getItemTitle.creatorId
+                    a = `${url}/exam/${data.blob}`
+                }
+                return a 
             },
             checkedAnsFilter(index) {
                 if (this.checkedAns.includes("right") == true && this.examInfo.stuScore[index] == this.paperData[index].score) {
@@ -560,18 +562,24 @@
                 else return false;
 
             },
+            /* =====未调用====== */
+            closeDetail() {
+                this.closeAnsDetail = !this.closeAnsDetail;
+            },
         },
         computed: {
+            ...mapGetters([
+                "getItemTitle",
+                "getPaperInfo",
+            ]),
             testScore() {
-                console.log(this.examInfo);
-                console.log(this.paperInfo);
                 let data = 0
                 if (this.examInfo.subject !== undefined) {
                     for (let item of this.examInfo.stuScore) {
                         data += item
                     }
                 }
-                if(String(data).indexOf(".") != -1) {
+                if (String(data).indexOf(".") != -1) {
                     data = data.toFixed(2)
                 }
                 return data
@@ -589,7 +597,7 @@
                         noAns:0,
                         wrong:0,
                     }
-                    if (this.paperData[0]!= undefined) {
+                    if (this.paperData[0] != undefined) {
                         for (let i = 0; i < this.examInfo.stuScore.length; i++) {
                             if (this.examInfo.stuScore[i] == -1) {
                                 info.noAns++
@@ -833,9 +841,9 @@
         }
 
     /**對問題進行篩選 */
-    .filterBtn {
-        /* display: inline-block; */
-    }
+    /* .filterBtn {
+        display: inline-block;
+    } */
 
     .filterBtn .wrong-exercises{
         /* border: 1px solid #515A6E; */

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

@@ -4,7 +4,7 @@
             <div class="stu-info">
                 <ul>
                     <li>
-                        <p><Icon type="ios-home" size="24" />{{$t("studentWeb.exam.studentScore.examName")}}:<span>{{$store.getters.getItemTitle.name}}</span></p>
+                        <p><Icon type="ios-home" size="24" />{{$t("studentWeb.exam.studentScore.examName")}}:<span>{{getItemTitle.name}}</span></p>
                     </li>
                     <li>
                         <p><Icon type="ios-paper" size="24" />{{$t("studentWeb.exam.studentScore.examType")}}:<span>--</span></p>
@@ -13,13 +13,13 @@
                         <p><Icon type="ios-list-box" size="24" />{{$t("studentWeb.exam.studentScore.stableIndex")}}:<span>--</span></p>
                     </li>
                     <li>
-                        <p><Icon type="ios-person" size="24" />{{$t("studentWeb.exam.studentScore.name")}}:<span>{{$store.state.userInfo.name}}</span></p>
+                        <p><Icon type="ios-person" size="24" />{{$t("studentWeb.exam.studentScore.name")}}:<span>{{userInfo.name}}</span></p>
                     </li>
                     <li>
-                        <p style="margin-top:5px">{{$t("studentWeb.exam.studentScore.stuNo")}}:<span>{{$store.state.userInfo.sub}}</span></p>
+                        <p style="margin-top:5px">{{$t("studentWeb.exam.studentScore.stuNo")}}:<span>{{userInfo.sub}}</span></p>
                     </li>
                     <li>
-                        <p style="margin-top:5px">{{$t("studentWeb.exam.studentScore.class")}}:<span>{{$store.state.user.studentProfile.classinfo.name}}</span></p>
+                        <p style="margin-top:5px">{{$t("studentWeb.exam.studentScore.class")}}:<span>{{classinfo.name}}</span></p>
                     </li>
                 </ul>
             </div>
@@ -214,6 +214,7 @@
     </div>
 </template>
 <script>
+    import { mapGetters, mapState } from 'vuex'
     export default {
         props: {
             stuData: {
@@ -231,7 +232,7 @@
         },
         data() {
             return {
-                testData: [],
+                testData: [], //试卷的题目信息
                 stuScore: [],
                 scoreInfo: {}
             }
@@ -256,11 +257,11 @@
                     this.scoreInfo = {}
                     let req = {
                         // "code": this.$store.state.user.schoolCode,
-                        "code": this.$store.getters.getItemTitle.owner == 'school' ? this.$store.getters.getItemTitle.school : this.$store.getters.getItemTitle.creatorId,
+                        "code": this.getItemTitle.owner == 'school' ? this.getItemTitle.school : this.getItemTitle.creatorId,
                         "id": this.examData[0].id,
-                        "sId": this.$store.state.userInfo.sub,
+                        "sId": this.userInfo.sub,
                         "cId": this.stuData.claId[0],
-                        "gId": this.$store.state.user.studentProfile.classinfo.gradeId
+                        "gId": this.classinfo.gradeId
                     }
                     this.$api.studentWeb.getStudentAnalysis(req).then(res => {
                         if (res.gradeAverage && this.stuScore.length) {
@@ -294,12 +295,12 @@
                 } else {
                     let blobUrl = JSON.parse(decodeURIComponent(localStorage.student_profile, "utf-8")).blob_uri
                     let studentBlob = blobUrl.split('/')
-                    let url = data.scope == 'school' ? blobUrl : "https://" + studentBlob[studentBlob.length - 2] + '/' + this.$store.getters.getItemTitle.creatorId
+                    let url = data.scope == 'school' ? blobUrl : "https://" + studentBlob[studentBlob.length - 2] + '/' + this.getItemTitle.creatorId
                     a = `${url}/exam/${data.blob}`
                 }
                 return a 
             },
-            async getStudentData(data,score,ans) {
+            async getStudentData(data, score, ans) {
                 let paper = []
                 let item = {
                     objItem: [],
@@ -307,13 +308,13 @@
                 }
                 console.log('5636123322',data)
                 if (data !== undefined) {
-                    let codes = this.$store.getters.getItemTitle.scope == 'school' ? data.school : data.creatorId
-                        let code = {
-                            scope: data.scope,
-                            code: codes,
-                            blob: data.blob,
-                            examId:codes
-                        }
+                    let codes = this.getItemTitle.scope == 'school' ? data.school : data.creatorId
+                    let code = {
+                        scope: data.scope,
+                        code: codes,
+                        blob: data.blob,
+                        examId:codes
+                    }
                     let papers = await this.$evTools.getStuPaper(code)
                     let answer = await this.getItem(ans)
                     paper = await this.formPaper(papers)
@@ -344,7 +345,7 @@
             async getItem(data) {
                 let datas = []
                 if (data !== undefined) {
-                    let key = this.$store.getters.getItemTitle
+                    let key = this.getItemTitle
                     let code = {
                         scope: this.stuData.papers[0].scope,
                         code: key.scope == 'school' ? key.school : key.creatorId,
@@ -397,6 +398,15 @@
                 }
                 deep: true
             }
+        },
+        computed: {
+            ...mapState({
+                userInfo: state => state.userInfo,
+                classinfo: state => state.user.studentProfile.classinfo
+            }),
+            ...mapGetters([
+                "getItemTitle",
+            ])
         }
     }
 </script>

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

@@ -272,7 +272,6 @@
             Complete
         },
         created() {
-            console.log(this.getItemTitle);
             this.WarmMessageisOpen = false;
             this.showMessageNum = 0;
         },
@@ -290,6 +289,11 @@
                 // Chrome, Safari, Firefox 4+, Opera 12+ , IE 9+
                 return "关闭提示";
             }
+            /* if (window.history && window.history.pushState) {
+                // 向历史记录中插入了当前页
+                // history.pushState(null, null, document.URL);
+                window.addEventListener('popstate', this.docGoBack, false);
+            } */
         },
         props: {
             papers: {
@@ -361,6 +365,24 @@
             };
         },
         methods: {
+            docGoBack() {
+                console.log("点击了浏览器的返回按钮");
+                this.$Modal.confirm({
+                    title: this.$t("studentWeb.exam.testpop.exitQuizhint"),
+                    content: "离开页面,您已作答的数据不会保存,是否确认退出?",
+                    onOk: () => {
+                        window.removeEventListener("popstate", this.docGoBack, false)
+                        // sessionStorage.clear(); //删除当前页面的数据
+                        // window.history.back();
+                        this.quitTest()
+                    },
+                    onCancel: () => {
+                        // window.removeEventListener("popstate", this.docGoBack, false)
+                    },
+                })
+                /* sessionStorage.clear();
+                window.history.back(); */
+            },
             getClassName(index){
                 let names = []
                 if(this.queNo == index) {
@@ -446,10 +468,6 @@
                     this.hintHandon()
                 }
             },
-            getJudge() {
-                this.checkers[this.queNo] = []
-                this.checkers[this.queNo].push(this.judgeSelect)
-            },
             getPaper() {
                 let paper = this.getCurrentSubject
                 this.paperData = { ...paper }
@@ -596,25 +614,6 @@
                     this.isLoading = false
                 }, 500)
             },
-            async getItem(data) {
-                let datas = []
-                if (data !== undefined) {
-                    let key = this.getExamInfo.code.split('-')
-                    let code = {
-                        scope: this.getExamInfo.scope,
-                        code: key[(key.length - 1)],
-                        blob: data
-                    }
-                    let blob = this.formUrl(code)
-                    code.blob = blob
-                    console.log(code);
-                    datas = await this.$evTools.getComposeItem(code)
-                    console.log(datas);
-                    return datas
-                } else {
-                    return []
-                }
-            },
             //处理学生作答数据blob地址
             formUrl(data) { 
                 let a = ""
@@ -649,11 +648,38 @@
                     }
                 }
             },
+            /* ======未调用====== */
+            getJudge() {
+                this.checkers[this.queNo] = []
+                this.checkers[this.queNo].push(this.judgeSelect)
+            },
+            async getItem(data) {
+                let datas = []
+                if (data !== undefined) {
+                    let key = this.getExamInfo.code.split('-')
+                    let code = {
+                        scope: this.getExamInfo.scope,
+                        code: key[(key.length - 1)],
+                        blob: data
+                    }
+                    let blob = this.formUrl(code)
+                    code.blob = blob
+                    console.log(code);
+                    datas = await this.$evTools.getComposeItem(code)
+                    console.log(datas);
+                    return datas
+                } else {
+                    return []
+                }
+            },
+        },
+        destroyed () {
+            // window.removeEventListener("popstate", this.docGoBack, false)
         },
 
         watch: {
             checkers:{
-                handler(n,o){
+                handler(n, o) {
                     // 未作答:0  对:1  错:2  主观题:3  已作答:4
                     // 已作答
                     if(n[this.queNo] && n[this.queNo].length) {

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

@@ -1,7 +1,7 @@
 <template>
     <div class="lesson-test">
         <br />
-        <PaperTest :papers="selectData" v-if="this.$store.getters.getisOpenLessonTestPopNow" /> 
+        <PaperTest :papers="selectData" v-if="getisOpenLessonTestPopNow" /> 
         <div>
             <div class="load-box">
                 <load :active.sync="isLoad"
@@ -27,7 +27,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' ? $t('studentWeb.exam.isSubject'):''}}</span>
+                                <span style="margin-top:5px">{{ item.subject.name }}{{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>
@@ -43,7 +43,7 @@
                     </div>
                 </TabPane>
                 <!-- 成绩分析 -->
-                <TabPane :label="$t('studentWeb.exam.gradeReport')" v-if="isTestOver && $store.getters.getItemTitle.owner == 'school'" name="analyse">
+                <TabPane :label="$t('studentWeb.exam.gradeReport')" v-if="isTestOver && getItemTitle.owner == 'school'" name="analyse">
                     <div class="title-rect-group">
                         <!-- <div class="title-rect" /> -->
                         <h2 class="title-rect-name">{{$t("studentWeb.exam.gradeAnalyse")}}</h2>
@@ -60,6 +60,7 @@
 <script>
     import Load from "vue-loading-overlay";
     import "vue-loading-overlay/dist/vue-loading.css";
+    import { mapGetters } from 'vuex';
     import EventBasicInfo from "../../EventBasicInfo";
     import LessonTestReport from "./LessonTestReport";
     import StudentScore from "./LessonTestReportCharts/StudentScore";
@@ -78,7 +79,7 @@
         },
         mounted() {
             this.selectTab = "test"
-            this.privateType = this.$store.getters.getItemTitle.owner
+            this.privateType = this.getItemTitle.owner
         },
         data() {
             return {
@@ -89,14 +90,14 @@
                 nextItem: "", //存放下個活動預告
                 isHintNextItem: false,
                 showHint: false,
-                paperData: [],
+                paperData: [], //试卷信息
                 openEva: false,
                 selectData: {}, // 存放完整试卷接口的返回值
                 isExamDown: false,
                 chooseData: {},
                 examData: [],
                 isLoad: false,
-                stuData: {},
+                stuData: {}, //当前评测的所有信息:classId、学科、试卷、作答答案
                 isTestOver: false,
                 selectTab: "test",
                 paperCtn: null, // 当前评测的scope
@@ -110,9 +111,9 @@
                 this.chooseData = {}
                 this.isTestOver = false
                 this.isLoad = true
-                if (this.$store.getters.getItemTitle.name !== undefined) {
-                    let paper = this.$store.getters.getItemTitle
-                    let codes = this.$store.getters.getItemTitle.scope == 'school' ? this.$store.getters.getItemTitle.school : this.$store.getters.getItemTitle.creatorId
+                if (this.getItemTitle.name !== undefined) {
+                    let paper = this.getItemTitle
+                    let codes = this.getItemTitle.scope == 'school' ? this.getItemTitle.school : this.getItemTitle.creatorId
                     let req = {
                         id: paper.id,
                         studentId: this.$store.state.userInfo.sub,
@@ -162,12 +163,43 @@
                             }
                             this.opentestWithSubject(this.paperData[0])
                         } else {
-                            this.$Message.warning('试卷已删除!')
+                            // this.$Message.warning('试卷已删除!')
+                            this.$Modal.confirm({
+                                title: "评测已被删除,是否删除此条记录?",
+                                okText: "删除",
+                                cancelText: "取消",
+                                onOk: () => {
+                                    this.delActivity()
+                                }
+                            })
                         }
                     })
                 }
                 this.isLoad = false
             },
+            // 删除不存在的问卷
+            delActivity() {
+                let roles = ""
+                if(this.$store.state.userInfo.roles.indexOf('student') > -1) {
+                    roles = 'student'
+                } else {
+                    roles = 'taecher'
+                }
+                let param = {
+                    'id': this.getItemTitle.id,
+                    'code': this.getItemTitle.code,
+                    "role": roles
+                }
+                this.$api.studentWeb.delActivity(param).then(res => {
+                    if(res) {
+						if(res.status == 200) {
+							this.$Message.success('评测已删除!')
+							this.$EventBus.$emit('delNotFound', this.getItemTitle.id)
+                            this.$store.commit("ChangeItemName", {})
+						}
+					}
+                })
+            },
             opentestWithSubject(item) {
                 if (item !== undefined) {
                     this.getPaper(item)
@@ -178,8 +210,7 @@
                 this.isLoad = true
                 this.selectData = {}
                 this.chooseData = {}
-                console.log(this.$store.getters.getItemTitle);
-                let codes = this.$store.getters.getItemTitle.scope == 'school' ? data.school : data.creatorId
+                let codes = this.getItemTitle.scope == 'school' ? data.school : data.creatorId
                 if (data.blob !== undefined && data.blob !== "") {
                     let code = {
                         scope: this.paperCtn,
@@ -235,8 +266,13 @@
             },
         },
         computed: {
+            ...mapGetters([
+                "getisOpenLessonTestPopNow",
+                "getItemTitle",
+                "getCurrentSubject",
+            ]),
             listData() {
-                return this.$store.getters.getCurrentSubject;
+                return this.getCurrentSubject;
             }
         },
         watch: {
@@ -251,7 +287,7 @@
             },
             listData: {
                 handler() {
-                    if (this.$store.getters.getCurrentSubject == '') {
+                    if (this.getCurrentSubject == '') {
                         this.getPaperData()
                     }
                 },

+ 109 - 64
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/QuesNaire.vue

@@ -36,54 +36,56 @@
 		</div> -->
 		<br />
 		<EventBasicInfo />
-		<!-- 已提交 -->
-		<div v-if="alreadyAnswered" style="text-align: center;padding-top: 15%;">
-			<Icon type="md-checkmark-circle-outline" color="#00ad6c" size="80"/>
-			<p style="font-size: 30px;color:#00ad6c;font-weight: 600; margin:20px;">{{ $t('survey.studentWeb.already') }}</p>
-		</div>
-		<!-- 活动结束 -->
-		<div v-if="!alreadyAnswered && surveyInfo.progress === 'finish'" style="text-align: center;padding-top: 15%;">
-			<Icon type="md-stopwatch" color="#00ad6c" size="80"/>
-			<p style="font-size: 30px;color:#00ad6c;font-weight: 600; margin:20px;">{{ $t('survey.studentWeb.overtime') }}</p>
-		</div>
-		
-
-		<!--問卷完成後,在時間結束前仍可修改答案再提交-->
-		<div v-if="surveyInfo.progress !== 'finish' && !alreadyAnswered">
-			<BillBoardandLightBox :activityData="surveyInfo" />
-			<div class="title-rect-group">
-				<!-- <div class="title-rect" /> -->
-				<h2 class="title-rect-name">{{ $t('survey.studentWeb.content') }}</h2>
+		<div>
+			<!-- 已提交 -->
+			<div v-if="alreadyAnswered" style="text-align: center;padding-top: 15%;">
+				<Icon type="md-checkmark-circle-outline" color="#00ad6c" size="80"/>
+				<p style="font-size: 30px;color:#00ad6c;font-weight: 600; margin:20px;">{{ $t('survey.studentWeb.already') }}</p>
+			</div>
+			<!-- 活动结束 -->
+			<div v-if="!alreadyAnswered && surveyInfo.progress === 'finish'" style="text-align: center;padding-top: 15%;">
+				<Icon type="md-stopwatch" color="#00ad6c" size="80"/>
+				<p style="font-size: 30px;color:#00ad6c;font-weight: 600; margin:20px;">{{ $t('survey.studentWeb.overtime') }}</p>
 			</div>
-			<br />
-			<!-- 问卷内容 -->
-			<div v-for="(item, index) in surveyInfo.items" :key="index" class="survey-item">
-				<!-- <br /> -->
-				<div style="display: flex;font-weight: bold;">
-					<span>{{ index + 1 }}. </span>
-					<span v-html="item.question"></span>({{ typeList[item.type] }})<span></span>
+			
+
+			<!--問卷完成後,在時間結束前仍可修改答案再提交-->
+			<div v-if="surveyInfo.progress !== 'finish' && !alreadyAnswered">
+				<BillBoardandLightBox :activityData="surveyInfo" />
+				<div class="title-rect-group">
+					<!-- <div class="title-rect" /> -->
+					<h2 class="title-rect-name">{{ $t('survey.studentWeb.content') }}</h2>
 				</div>
-				<!-- 非问答 -->
-				<div v-if="item.type !== 'subjective'">
-					<div class="unitTestBtn" v-for="(option, optionIndex) in item.option" :key="optionIndex">
-						<div class="unitTestbg" @click="onOptionClick(item,index,option.code)"
-							:style="{ backgroundColor: submitArr[index].includes(option.code) ?  '#24b880' : 'transparent' }">
-							{{ option.code }}. <span v-html="option.value" style="margin-left: 10px;"></span>
+				<br />
+				<!-- 问卷内容 -->
+				<div v-for="(item, index) in surveyInfo.items" :key="index" class="survey-item">
+					<!-- <br /> -->
+					<div style="display: flex;font-weight: bold;">
+						<span>{{ index + 1 }}. </span>
+						<span v-html="item.question"></span>({{ typeList[item.type] }})<span></span>
+					</div>
+					<!-- 非问答 -->
+					<div v-if="item.type !== 'subjective'">
+						<div class="unitTestBtn" v-for="(option, optionIndex) in item.option" :key="optionIndex">
+							<div class="unitTestbg" @click="onOptionClick(item,index,option.code)"
+								:style="{ backgroundColor: submitArr[index].includes(option.code) ?  '#24b880' : 'transparent' }">
+								{{ option.code }}. <span v-html="option.value" style="margin-left: 10px;"></span>
+							</div>
 						</div>
 					</div>
+					<!-- 问答 -->
+					<div v-if="item.type === 'subjective'">
+						<Input v-model="submitArr[index][0]" type="textarea" :rows="8" :placeholder="$t('studentWeb.exam.inputAnswers')" />
+					</div>
+					<Divider v-if="index != surveyInfo.items.length - 1" />
 				</div>
-				<!-- 问答 -->
-				<div v-if="item.type === 'subjective'">
-					<Input v-model="submitArr[index][0]" type="textarea" :rows="8" :placeholder="$t('studentWeb.exam.inputAnswers')" />
-				</div>
-				<Divider v-if="index != surveyInfo.items.length - 1" />
+				<br />
+				<br />
+				<button class="uploadBtn" @click="submitMessage()">
+					<svg-icon icon-class="quesnaire" class="uloadBtn-icon" />
+					<span>{{ $t('survey.studentWeb.submit') }}</span>
+				</button>
 			</div>
-			<br />
-			<br />
-			<button class="uploadBtn" @click="submitMessage()">
-				<svg-icon icon-class="quesnaire" class="uloadBtn-icon" />
-				<span>{{ $t('survey.studentWeb.submit') }}</span>
-			</button>
 		</div>
 
 		<!-- {{ createdSaveCheckers() }} -->
@@ -94,6 +96,7 @@
 	import QuesNaireReport from "./QuesNaireReport";
 	import EventBasicInfo from "../../EventBasicInfo";
 	import BillBoardandLightBox from "../../EventView/BillBoardandLightBox";
+import { mapGetters } from 'vuex';
 	export default {
 		name: "QuesNaire",
 		components: {
@@ -181,22 +184,22 @@
 				this.WarmMessageisOpen = false;
 			},
 			createdSaveCheckers() {
-				if (this.$store.getters.getResetSurvey == true) {
+				if (this.getResetSurvey == true) {
 					this.checkers = [];
 					var mockcheckersheet = [];
 					for (let i = 0; i < 10; i++) {
 						if (
-							this.$store.getters.getItemTitle.isDone == false &&
-							this.$store.getters.getFinishedItem.includes(
-								this.$store.getters.getItemTitle.eventID
+							this.getItemTitle.isDone == false &&
+							this.getFinishedItem.includes(
+								this.getItemTitle.eventID
 							) == false
 						) {
 							mockcheckersheet.push([]);
 						} else if (
-							this.$store.getters.getFinishedItem.includes(
-								this.$store.getters.getItemTitle.eventID
+							this.getFinishedItem.includes(
+								this.getItemTitle.eventID
 							) == true ||
-							this.$store.getters.getItemTitle.isDone == true
+							this.getItemTitle.isDone == true
 						) {
 							mockcheckersheet.push("B");
 						}
@@ -211,7 +214,7 @@
 				}
 			},
 			qesNaire() {
-				return this.$store.getters.getItemTitle.qesNaire;
+				return this.getItemTitle.qesNaire;
 			},
 			
 			/* 判断当前学生是否已作答该问卷 */
@@ -227,23 +230,36 @@
 			//获取投票数据
 			// 获取surveyInfo的数据
 			async getSurveyInfo() {
-				if (this.$store.getters.getItemTitle.id) {
+				// this.surveyInfo = {}
+				if (this.getItemTitle.id) {
 					let params = {
-						"id": this.$store.getters.getItemTitle.id,
-						"code": this.$store.getters.getItemTitle.scode
+						"id": this.getItemTitle.id,
+						"code": this.getItemTitle.scode
 					}
 					let isAnswerd = await this.isAnswerd(params)
 					if(!isAnswerd){
 						// 没有提交
 						this.$api.studentWeb.getSurveyInfo(params).then(async res => {
 							if (res) {
-								this.surveyInfo = res.survey
-								this.surveyInfo.items = await this.getBlobItems(res.survey)
-								this.submitArr = []
-								this.surveyInfo.items.forEach(i => {
-									this.submitArr.push([])
-								})
-								this.$forceUpdate()
+								if(res.status == 404) {
+									this.isLoad = false
+									this.$Modal.confirm({
+										title: "问卷已被删除,是否删除此条记录?",
+										okText: "删除",
+										cancelText: "取消",
+										onOk: () => {
+											this.delActivity()
+										}
+									})
+								} else if(res.status == 200) {
+									this.surveyInfo = res.survey
+									this.surveyInfo.items = await this.getBlobItems(res.survey)
+									this.submitArr = []
+									this.surveyInfo.items.forEach(i => {
+										this.submitArr.push([])
+									})
+									this.$forceUpdate()
+								}
 							}
 						}).catch(err => {
 							console.log(err)
@@ -251,12 +267,33 @@
 					}else{
 						this.alreadyAnswered = true
 					}
-					
 				}
-				
-				console.log(this.alreadyAnswered)
-				console.log(this.surveyInfo)
 			},
+			// 删除不存在的问卷
+            delActivity() {
+                let roles = ""
+                if(this.$store.state.userInfo.roles.indexOf('student') > -1) {
+                    roles = 'student'
+                } else {
+                    roles = 'taecher'
+                }
+                let param = {
+                    'id': this.getItemTitle.id,
+                    'code': this.getItemTitle.code,
+                    "role": roles
+                }
+                this.$api.studentWeb.delActivity(param).then(res => {
+                    if(res) {
+						if(res.status == 200) {
+							this.$Message.success('问卷已删除!')
+							this.$EventBus.$emit('delNotFound', this.getItemTitle.id)
+							this.$store.commit("ChangeItemName", {})
+						}
+					}
+                }).finally(()=>{
+                    this.isLoad = false
+                })
+            },
 
 			// 获取blob里的问卷内容
 			getBlobItems(qnItem) {
@@ -332,6 +369,14 @@
 				deep: true
 			},
 		},
+		
+		computed: {
+			...mapGetters([
+				"getItemTitle",
+				"getResetSurvey",
+				"getFinishedItem"
+			])	
+		},
 	};
 </script>
 

+ 166 - 121
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/Vote.vue

@@ -9,113 +9,115 @@
         </div>
         <EventBasicInfo />
         <div>
+            <div>
             <!--超时-->
-            <div v-if="this.$store.getters.getItemTitle.endTime <= '2020.02.10'">
-                <br />
-                <div class="dec animate__animated animate__bounceInLeft">
-                    <svg-icon icon-class="handonHint" class="warm-icon" />
-                    <span class="warm-hint">{{ $t("studentWeb.vote.timeoutHint") }}</span>
-                </div>
-            </div>
-            <div v-if="!showResult">
-                <div class="load-box">
-                    <Load :active.sync="isLoad"
-                          background-color="#000">
-                        <template slot="default">
-                            <svg-icon icon-class="loader" class="loader-icon" />
-                        </template>
-                    </Load>
-                </div>
-                <BillBoardandLightBox :activityData="voteInfo" :voteRes="voteResData" />
-                <div class="vote-title">
-                    <div class="title-rect-group">
-                        <!-- <div class="title-rect" /> -->
-                        <h2 class="title-rect-name">{{ $t("studentWeb.vote.bollotbox") }}</h2>
-                        <p v-if="voteInfo.repeat" style="margin-left:15px;margin-top:2px">{{ $t("studentWeb.vote.surplusTickets")}} <span style="font-size:16px">{{voteCount}}</span><span> {{ $t("studentWeb.vote.tickets")}} </span></p>
+                <div v-if="getItemTitle.endTime <= '2020.02.10'">
+                    <br />
+                    <div class="dec animate__animated animate__bounceInLeft">
+                        <svg-icon icon-class="handonHint" class="warm-icon" />
+                        <span class="warm-hint">{{ $t("studentWeb.vote.timeoutHint") }}</span>
                     </div>
-                    <Button v-show="isResult"
-                            style="float:right;margin-top:-30px"
-                            size="small" type="success"
-                            @click="showRes"
-                    >
-                        <span style="margin-left:5px">{{$t("studentWeb.vote.voteRes")}}</span>
-                    </Button>
                 </div>
-                <!-- 投票内容 -->
-                <!-- <div class="question-box">
-                    <span v-html="voteInfo.description"></span>
-                </div> -->
-                <div class="vote-option">
-                    <!-- 1票
-                    <RadioGroup v-model="voteChecked" v-if="voteInfo.voteNum == 1" class="option-group">
-                        <Radio :label="item.code" v-for="(item, index) in voteInfo.options" :key="index" class="option-wrapper">
-                            <span v-html="item.value"></span>
-                        </Radio>
-                    </RadioGroup>
-                    多票  不重复
-                    <CheckboxGroup v-model="voteChecked" v-if="voteInfo.voteNum > 1 && !voteInfo.repeat" class="option-group">
-                        <Checkbox :label="item.code" v-for="(item, index) in voteInfo.options" :key="index" class="option-wrapper">
-                            <span v-html="item.value"></span>
-                        </Checkbox>
-                    </CheckboxGroup>
-                    多票  重复
-                    <CheckboxGroup v-model="voteChecked" v-if="voteInfo.voteNum > 1 && voteInfo.repeat" class="option-group option-repeat">
-                        <Checkbox :label="item.code" v-for="(item, index) in voteInfo.options" :key="index" class="option-wrapper">
-                            <InputNumber v-model="item.count"
-                                         :min="0"
-                                         size="small"
-                                         :formatter="value => `${value}` +$t('studentWeb.vote.tickets')"
-                            ></InputNumber>
-                            <span v-html="item.value"></span>
-                        </Checkbox>
-                    </CheckboxGroup> -->
-                    <div class="checkAnswer" v-for="(item, index) in voteInfo.options" :key="index">  
-                        <label class="testBtn">
-                            <input type="checkbox" :value="item" v-model="voteChecked" @click="getVote(item)" />
-                            <div class="testbg">
-                                <div class="vote-info">
-                                    <span style="display:flex;margin-right:5px">{{item.code}}.<span v-html="item.value"></span></span>
-                                </div>
+                <div v-if="!showResult">
+                    <div class="load-box">
+                        <Load :active.sync="isLoad"
+                            background-color="#000">
+                            <template slot="default">
+                                <svg-icon icon-class="loader" class="loader-icon" />
+                            </template>
+                        </Load>
+                    </div>
+                    <BillBoardandLightBox :activityData="voteInfo" :voteRes="voteResData" />
+                    <div class="vote-title">
+                        <div class="title-rect-group">
+                            <!-- <div class="title-rect" /> -->
+                            <h2 class="title-rect-name">{{ $t("studentWeb.vote.bollotbox") }}</h2>
+                            <p v-if="voteInfo.repeat" style="margin-left:15px;margin-top:2px">{{ $t("studentWeb.vote.surplusTickets")}} <span style="font-size:16px">{{voteCount}}</span><span> {{ $t("studentWeb.vote.tickets")}} </span></p>
+                        </div>
+                        <Button v-show="isResult"
+                                style="float:right;margin-top:-30px"
+                                size="small" type="success"
+                                @click="showRes"
+                        >
+                            <span style="margin-left:5px">{{$t("studentWeb.vote.voteRes")}}</span>
+                        </Button>
+                    </div>
+                    <!-- 投票内容 -->
+                    <!-- <div class="question-box">
+                        <span v-html="voteInfo.description"></span>
+                    </div> -->
+                    <div class="vote-option">
+                        <!-- 1票
+                        <RadioGroup v-model="voteChecked" v-if="voteInfo.voteNum == 1" class="option-group">
+                            <Radio :label="item.code" v-for="(item, index) in voteInfo.options" :key="index" class="option-wrapper">
+                                <span v-html="item.value"></span>
+                            </Radio>
+                        </RadioGroup>
+                        多票  不重复
+                        <CheckboxGroup v-model="voteChecked" v-if="voteInfo.voteNum > 1 && !voteInfo.repeat" class="option-group">
+                            <Checkbox :label="item.code" v-for="(item, index) in voteInfo.options" :key="index" class="option-wrapper">
+                                <span v-html="item.value"></span>
+                            </Checkbox>
+                        </CheckboxGroup>
+                        多票  重复
+                        <CheckboxGroup v-model="voteChecked" v-if="voteInfo.voteNum > 1 && voteInfo.repeat" class="option-group option-repeat">
+                            <Checkbox :label="item.code" v-for="(item, index) in voteInfo.options" :key="index" class="option-wrapper">
                                 <InputNumber v-model="item.count"
-                                             :formatter="value => `${value}` +$t('studentWeb.vote.tickets')"
-                                             :parser="value => value.replace($t('studentWeb.vote.tickets'), '')"
-                                             :min="0"
-                                             v-if="voteInfo.repeat"
-                                             @on-change="setVoteNum(item)"
-                                             :disabled="!voteStatus">
-                                </InputNumber>
-                            </div>
-                        </label>
+                                            :min="0"
+                                            size="small"
+                                            :formatter="value => `${value}` +$t('studentWeb.vote.tickets')"
+                                ></InputNumber>
+                                <span v-html="item.value"></span>
+                            </Checkbox>
+                        </CheckboxGroup> -->
+                        <div class="checkAnswer" v-for="(item, index) in voteInfo.options" :key="index">  
+                            <label class="testBtn">
+                                <input type="checkbox" :value="item" v-model="voteChecked" @click="getVote(item)" />
+                                <div class="testbg">
+                                    <div class="vote-info">
+                                        <span style="display:flex;margin-right:5px">{{item.code}}.<span v-html="item.value"></span></span>
+                                    </div>
+                                    <InputNumber v-model="item.count"
+                                                :formatter="value => `${value}` +$t('studentWeb.vote.tickets')"
+                                                :parser="value => value.replace($t('studentWeb.vote.tickets'), '')"
+                                                :min="0"
+                                                v-if="voteInfo.repeat"
+                                                @on-change="setVoteNum(item)"
+                                                :disabled="!voteStatus">
+                                    </InputNumber>
+                                </div>
+                            </label>
+                        </div>
                     </div>
-                </div>
-                <Button :disabled="!isVote" size="large" type="success" @click="submitMessage()">
-                    <svg-icon icon-class="vote" class="uploadBtn-icon" />
-                    <span style="margin-left:5px">{{ $t("studentWeb.vote.submitBVote") }}</span>
-                </Button>
-                <span class="clickbutnoChoosehint"
-                      v-if="clickbutnoChoose == true && voteChecked == ''">{{ $t("studentWeb.vote.note") }}</span>
-                <span v-if="isOverCount" style="margin-top:5px;margin-left:15px;color:red">{{$t("studentWeb.vote.warning2")}}</span>
+                    <Button :disabled="!isVote" size="large" type="success" @click="submitMessage()">
+                        <svg-icon icon-class="vote" class="uploadBtn-icon" />
+                        <span style="margin-left:5px">{{ $t("studentWeb.vote.submitBVote") }}</span>
+                    </Button>
+                    <span class="clickbutnoChoosehint"
+                        v-if="clickbutnoChoose == true && voteChecked == ''">{{ $t("studentWeb.vote.note") }}</span>
+                    <span v-if="isOverCount" style="margin-top:5px;margin-left:15px;color:red">{{$t("studentWeb.vote.warning2")}}</span>
 
-            </div>
-        </div>
-        <!-- 投票结果 -->
-        <div class="voteResults" v-if="showResult">
-            <h3 class="voteResultsMainRow ">
-                {{ $t("studentWeb.vote.voteResult") }}
-            </h3>
-            <div class="question-box">
-                <span style="display:block;width:90%" v-html="voteInfo.description"></span>
-                <Button style="float:right;margin-top:0px" size="small" type="success" @click="showRes">
-                    <span style="margin-left:5px">{{$t("studentWeb.vote.voteRecord")}}</span>
-                </Button>
-            </div>
-            <div v-for="(item,index) in voteInfo.options" :key="index">
-                <div class="voteResultsItem">
-                    <p style="display:flex">{{ item.code }}.<span v-html="item.value"></span></p>
                 </div>
             </div>
-            <div align="center">
-                <VoteResultChart :voteData="voteData" :voteList="voteList" />
+            <!-- 投票结果 -->
+            <div class="voteResults" v-if="showResult">
+                <h3 class="voteResultsMainRow ">
+                    {{ $t("studentWeb.vote.voteResult") }}
+                </h3>
+                <div class="question-box">
+                    <span style="display:block;width:90%" v-html="voteInfo.description"></span>
+                    <Button style="float:right;margin-top:0px" size="small" type="success" @click="showRes">
+                        <span style="margin-left:5px">{{$t("studentWeb.vote.voteRecord")}}</span>
+                    </Button>
+                </div>
+                <div v-for="(item,index) in voteInfo.options" :key="index">
+                    <div class="voteResultsItem">
+                        <p style="display:flex">{{ item.code }}.<span v-html="item.value"></span></p>
+                    </div>
+                </div>
+                <div align="center">
+                    <VoteResultChart :voteData="voteData" :voteList="voteList" />
+                </div>
             </div>
         </div>
     </div>
@@ -126,6 +128,7 @@
     import BillBoardandLightBox from "../../EventView/BillBoardandLightBox";
     import VoteResultChart from "./VoteResultChart";
     import Load from "vue-loading-overlay";
+    import { mapGetters } from 'vuex';
     export default {
         name: "Vote",
         components: {
@@ -164,11 +167,11 @@
         methods: {
             //获取个人投票结果数据
             getVoteRecord() {
-                if (this.$store.getters.getItemTitle.id) {
+                if (this.getItemTitle.id) {
                     this.voteRes = {}
                     let params = {
-                        "id": this.$store.getters.getItemTitle.id,
-                        "code": this.$store.getters.getItemTitle.scode,
+                        "id": this.getItemTitle.id,
+                        "code": this.getItemTitle.scode,
                         "userid": this.$store.state.userInfo.sub
                     }
                     this.$api.studentWeb.getVoteResult(params).then(res => {
@@ -185,37 +188,76 @@
             },
             //获取活动投票结果数据
             getVoteInfo() {
-                if (this.$store.getters.getItemTitle.id) {
+                if (this.getItemTitle.id) {
                     let params = {
-                        "id": this.$store.getters.getItemTitle.id,
-                        "code": this.$store.getters.getItemTitle.scode
+                        "id": this.getItemTitle.id,
+                        "code": this.getItemTitle.scode
                     }
                     this.isLoad = true
                     this.$api.studentWeb.getVoteInfo(params).then(res => {
                         if (res) {
-                            this.showResult = false
-                            this.isResult = false
-                            for (let item of res.vote.options) {
-                                item.count = 0
-                            }
-                            this.voteInfo = res.vote
-                            if (res.vote.progress == "finish") {
-                                this.getVoteRecord()
-                                this.getVoteRes()
-                                this.isResult = true
-                            } else {
-                                this.getVoteRecord()
+                            if(res.status == 404) {
+                                this.isLoad = false
+                                this.$Modal.confirm({
+                                    title: "投票已被删除,是否删除此条记录?",
+                                    okText: "删除",
+                                    cancelText: "取消",
+                                    onOk: () => {
+                                        this.delActivity()
+                                    }
+                                })
+                            } else if(res.status == 200) {
+                                this.showResult = false
+                                this.isResult = false
+                                for (let item of res.vote.options) {
+                                    item.count = 0
+                                }
+                                this.voteInfo = res.vote
+                                if (res.vote.progress == "finish") {
+                                    this.getVoteRecord()
+                                    this.getVoteRes()
+                                    this.isResult = true
+                                } else {
+                                    this.getVoteRecord()
+                                }
                             }
                         }
+                    }).catch(err => {
+                        console.log(err)
                     })
                 }
             },
-           async getVoteRes() {
+            async getVoteRes() {
                 if (this.voteInfo.recordUrl !== "") {
                     let data = await this.getBlobItems(this.voteInfo)
                     this.setData(data[0])
                 }
             },
+            // 删除不存在的投票
+            delActivity() {
+                let roles = ""
+                if(this.$store.state.userInfo.roles.indexOf('student') > -1) {
+                    roles = 'student'
+                } else {
+                    roles = 'taecher'
+                }
+                let param = {
+                    'id': this.getItemTitle.id,
+                    'code': this.getItemTitle.code,
+                    "role": roles
+                }
+                this.$api.studentWeb.delActivity(param).then(res => {
+                    if(res) {
+                        if(res.status == 200) {
+                            this.$Message.success('投票已删除!')
+                            this.$EventBus.$emit('delNotFound', this.getItemTitle.id)
+                            this.$store.commit("ChangeItemName", {})
+                        }
+                    }
+                }).finally(()=>{
+                    this.isLoad = false
+                })
+            },
             // 获取blob里的试题数据
             getBlobItems(qnItem) {
                 let key = this.voteInfo.code.split('-')
@@ -364,8 +406,8 @@
                 this.clickbutnoChoose = false;
                 if (this.voteChecked.length) {
                     let params = {
-                        "id": this.$store.getters.getItemTitle.id,
-                        "code": this.$store.getters.getItemTitle.scode,
+                        "id": this.getItemTitle.id,
+                        "code": this.getItemTitle.scode,
                         "option": {}
                     }
                     for (let item of this.voteChecked) {
@@ -396,8 +438,11 @@
             },
         },
         computed: {
+            ...mapGetters([
+                "getItemTitle",
+            ]),
             listData() {
-                return this.$store.getters.getItemTitle.id;
+                return this.getItemTitle.id;
             },
             voteCount() {
                 if (this.voteInfo.voteNum !== undefined) {

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

@@ -216,7 +216,12 @@ import { mapGetters, mapState } from 'vuex';
     import PreviewProgressPie from "../EventView/PreviewProgressPie";
     export default {
         name: "EventList",
-        mounted() { 
+        mounted() {
+            this.$EventBus.$off('delNotFound')
+            this.$EventBus.$on('delNotFound', id => {
+                console.log(id);
+                this.delListData(id)
+            })
             this.getActivityInfo()
             this.selectedCondition(this.getItemTitle);
             if (this.getIsSelectedNow == false) {
@@ -524,6 +529,18 @@ import { mapGetters, mapState } from 'vuex';
                     return true;
                 } else return false;
             },
+            // 删除页面上不不存在的数据
+            delListData(id) {
+                if(this.eventList) {
+                    for(let i = 0; i < this.eventList.length; i++) {
+                        if(this.eventList[i].id == id) {
+                            this.eventList.splice(i, 1)
+                            break
+                        }
+                    }
+                    this.predealMockdatafirstItem()
+                }
+            },
 
             /* =======未调用======== */
             //取得目前滑鼠座標

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

@@ -1,8 +1,9 @@
 <template>
     <div class="event-view">
-        <EventList :class="{ 'hide-sidebars': $store.getters.getSidebarisOpen == false}"></EventList>
-        <EventContentArea :class="{'eventContentArea-Span': $store.getters.getSidebarisOpen == false}"></EventContentArea>
-        <!--<CommentList v-if=" $store.getters.getOpenCommentList == true && $store.getters.getSidebarisOpen == false" />-->
+        <EventList :class="{ 'hide-sidebars': getSidebarisOpen == false}"></EventList>
+        <!-- <EventContentArea :class="{'eventContentArea-Span': getSidebarisOpen == false}"></EventContentArea> -->
+        <EventContent :class="{'eventContentArea-Span': getSidebarisOpen == false}"></EventContent>
+        <!--<CommentList v-if=" $store.getters.getOpenCommentList == true && getSidebarisOpen == false" />-->
     </div>
 </template>
 
@@ -10,12 +11,15 @@
     import CommentList from "./CommentList.vue";
     import EventList from "./EventList";
     import EventContentArea from "./EventContentArea.vue";
+    import EventContent from "./EventContent.vue";
+    import { mapGetters } from 'vuex';
     export default {
         name: "EventView",
         components: {
             EventList,
             EventContentArea,
             CommentList,
+            EventContent,
         },
         data() {
             return {
@@ -38,7 +42,7 @@
                 this.selectedEventStatusNow = "所有活動狀態";
                 this.eventTypeCheckers = [];
                 let targetItem = document.getElementById(
-                    `event${this.$store.getters.getItemTitle.eventID}`
+                    `event${this.getItemTitle.eventID}`
                 );
                 let scrollList = document.querySelectorAll(".event-list .list-block")[0];
 
@@ -59,7 +63,7 @@
             gotoNextItem() {
                 let nextItems = [];
                 for (let i = 0; i <= this.mockdata.length; i++) {
-                    if (this.$store.getters.getItemTitle == this.mockdata[i]) {
+                    if (this.getItemTitle == this.mockdata[i]) {
                         let j = i + 1;
                         if (
                             j < this.mockdata.length && this.eventPageType.includes(this.mockdata[j].eventType)
@@ -97,6 +101,12 @@
                 }
             },
         },
+        computed: {
+            ...mapGetters([
+                "getSidebarisOpen",
+                "getItemTitle"
+            ])
+        }
     };
 </script>
 <style scoped>

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

@@ -299,7 +299,7 @@ export default {
 
     created() {
         (this.MyName = this.$t("studentWeb.homeView-title")),
-            this.$emit("onNavNo", this.MyNo)
+        this.$emit("onNavNo", this.MyNo)
         this.$emit("onNavName", this.MyName)
     },
     mounted() {

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

@@ -17,7 +17,7 @@
     padding-left: 0 !important;
     &:hover {
       height: 45px;
-      background: #313131;
+      background: #2b2b2b;
     }
 	
 	.el-tree-node__expand-icon{
@@ -72,6 +72,24 @@
 /* 修改iview Modal样式 */
 .tree-modal {
 	font-family: 'NotoSerif', '微软正黑体', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Sans-serif;
+	
+	
+	
+	.ivu-input::-webkit-input-placeholder {
+		color: #808080;
+	}
+	
+	.ivu-select-single .ivu-select-selection {
+		background: #575757;
+		color: #fbfbfb;
+		border-color: transparent;
+		height: 35px;
+		margin-left: 15px;
+	}
+	
+	.ivu-select-single .ivu-select-arrow {
+		color: #fbfbfb;
+	}
   .ivu-modal-content {
     background: #3c3c3c;
     overflow: hidden;
@@ -103,6 +121,12 @@
       margin: 30px 0;
       font-size: 14px;
     }
+	.node-name{
+		font-size: 16px;
+		font-weight: bold;
+		color: #00fec1;
+		margin-left: 10px;
+	}
     .ivu-input {
       background: #575757;
       border-color: transparent;

+ 342 - 18
TEAMModelOS/ClientApp/src/components/syllabus/DragTree.vue

@@ -3,14 +3,21 @@
 		<vuescroll>
 			<el-tree :data="treeDatas" :props="defaultProps" :allow-drop="allowDrop" class="tree" node-key="id"
 				default-expand-all highlight-current @node-drop="handleDrop" @node-click="onNodeClick"
-				:draggable="editable" :expand-on-click-node="false" ref="tree">
+				:draggable="Boolean(editable)" :expand-on-click-node="false" ref="tree">
 				<span class="custom-tree-node" slot-scope="{ node, data }">
 					<span class="tree-node-lable">
 						{{data.title}}
 						<!-- {{data.id}} -->
-						<Icon type="md-cube" :title="$t('syllabus.tree.hasResource')" v-if="data.rnodes && data.rnodes.length" />
+						<Icon type="md-cube" color="#00c38d" :title="$t('syllabus.tree.hasResource')" v-if="data.rnodes && data.rnodes.length" />
+						<Icon type="md-git-compare" color="#00c38d" :title="$t('syllabus.tree.hasCoEdit')" v-if="hasEditAuth(data) && isSchool" />
 					</span>
-					<span class="custom-tree-tools" v-if="(hasEditAuth(data) || $access.can('admin.*|Syllabus_Edit'))">
+					<span class="custom-tree-tools" v-if="inShareView && isFirstLevel(data)">
+						<Icon type="md-copy" style="margin-right: 5px;" size="16" />
+						<span style="color: #9f9f9f;font-size: 12px;margin-right: 20px;" @click="onCopyChapter(data)">复制该章节</span>
+						<Icon type="ios-remove-circle-outline" style="margin-right: 5px;" size="16" />
+						<span style="color: #9f9f9f;font-size: 12px;margin-right: 20px;"  @click="onIgnoreShare(data)">忽略该章节</span>
+					</span>
+					<span class="custom-tree-tools" v-if="((hasEditAuth(data) || $access.can('admin.*|Syllabus_Edit')) && !inShareView)">
 						<Icon type="md-create" size="16" :title="$t('syllabus.tree.edit')" @click="onEditItem(node,data,$event)" />
 						<Icon type="md-add" size="16" :title="$t('syllabus.tree.add')" @click="onAddNode(node,data,$event)" />
 						<Icon type="md-remove" size="16" :title="$t('syllabus.tree.remove')" @click="remove(node,data)" v-if="!isFirstLevel(data) ||  (canDeleteChapter(data) && isFirstLevel(data))"/>
@@ -33,11 +40,26 @@
 			<Button @click="onSubmitNode" class="modal-btn"
 				style="width: 88%;margin-left: 6%;margin-bottom: 20px;">{{ $t('syllabus.tree.confirm') }}</Button>
 		</Modal>
+		
+		<!-- 新增或者编辑弹窗 -->
+		<Modal v-model="chapterCopyModal" width="500" footer-hide class="tree-modal add-volume-modal choose-content-modal">
+			<div class="modal-header" slot="header">复制节点</div>
+			<div class="modal-content">
+				<p class="node-title">当前章节: <span class="node-name">{{ curChapter.title }}</span></p>
+				<p class="node-title" style="display: inline-block;">目标册别:</p>
+				<Select v-model="copyTargetVolume" style="width: 300px;">
+					<Option v-for="(item,index) in volumeList" :value="index" :key="index">{{item.name}}</Option>
+				</Select>
+			</div>
+			<Button @click="doCopyChapter" :loading="isCopyBtnLoading" class="modal-btn"
+				style="width: 88%;margin-left: 6%;margin-bottom: 20px;">{{ $t('syllabus.tree.confirm') }}</Button>
+		</Modal>
 	</div>
 </template>
 
 <script>
 	import '@/utils/Math.uuid'
+	import BlobTool from '@/utils/blobTool.js'
 	import BaseResource from '@/view/syllabus/newSyllabus/operation/BaseResource'
 	import BaseKnowledge from '@/view/syllabus/newSyllabus/operation/BaseKnowledge'
 	import BaseQuestionList from '@/common/BaseQuestionList'
@@ -60,9 +82,12 @@
 				},
 				isEditOrAdd: false,
 				isLoading: false,
+				isCopyBtnLoading:false,
 				isRelatedContent: false,
 				isShowContent: false,
+				chapterCopyModal:false,
 				isEditItem: false,
+				copyTargetVolume:0,
 				contentIndex: '1',
 				currentVolume: null,
 				currentEditData: null,
@@ -71,6 +96,10 @@
 				currentItems: [],
 				curNode: null,
 				curData:null,
+				curChapter:{
+					id: null,
+					title: '',
+				},
 				nodeInfo: {
 					id: null,
 					title: '',
@@ -89,7 +118,8 @@
 					rnodes:[]
 				},
 				isSchool: false,
-				flatArr:[]
+				flatArr:[],
+				flatRNodes:[],
 			}
 		},
 		created() {
@@ -104,11 +134,9 @@
 					node:node
 				})
 			},
-
 			doShare(data) {
 				this.$emit('doShare', data)
 			},
-			
 			/* 禁止一级节点往下级进行拖拽 */
 			allowDrop(draggingNode, dropNode, dropType) {
 				if (draggingNode.level === dropNode.level) {
@@ -145,7 +173,298 @@
 				this.$parent.hasModify = true
 
 			},
-
+			/* 忽略某个章节的分享 */
+			onIgnoreShare(data){
+				this.$Modal.confirm({
+					title: this.$t('syllabus.tree.removeTitle'),
+					content: '确认忽略该章节吗?',
+					onOk: () => {
+						this.$api.syllabus.ShareAgree({
+							"code": this.$store.state.userInfo.TEAMModelId,
+							"id": data.id,
+							"type": "share",
+							"opt": "ignore"
+						}).then(res => {
+							if(res.status === 200){
+								this.$Message.success('操作成功!')
+								this.$parent.getShareVolumeList()
+							}
+						})
+					}
+				})
+			},
+			/* 复制章节到课纲 */
+			onCopyChapter(data){
+				if(this.volumeList.length){
+					this.curChapter = data
+					this.chapterCopyModal = true
+				}else{
+					this.$Message.warning('请先创建您的个人课纲!')
+				}
+			},
+			/* 复制章节的业务逻辑 */
+			async doCopyChapter(){
+				let targetVolume = this.volumeList[this.copyTargetVolume]
+				let allRNodes = this.getAllRNodes(JSON.parse(JSON.stringify(this.curChapter)))
+				let hasItemOrPaper = allRNodes.filter(i => i.type === 'item' || i.type === 'paper').length > 0
+				this.flatRNodes = allRNodes
+				this.isCopyBtnLoading = true
+				this.curChapter.auth = []
+				this.curChapter.pid = targetVolume.id
+				// 在复制章节过程中 如果章节节点以及子节点有关联试题试卷 则需要询问用户是否进行入库操作
+				if(hasItemOrPaper){
+					this.$Modal.confirm({
+						title: '提示',
+						content: '该章节中有关联试题试卷信息,是否需要同步到您的个人试题试卷库?',
+						okText: '同步并复制',
+						cancelText: '不需要',
+						onOk: async () => {
+							let copyResult = await this.doCopyResources(allRNodes,true)
+							console.log('复制后的回调',copyResult)
+							this.sendCopyApi(targetVolume)
+						},
+						onCancel: async () => {
+							let copyResult = await this.doCopyResources(allRNodes,false)
+							console.log('复制后的回调',copyResult)
+							this.sendCopyApi(targetVolume)
+						}
+					})
+				}else{
+					let copyResult = await this.doCopyResources(allRNodes,false)
+					this.sendCopyApi(targetVolume)
+				}
+			},
+			/* 发送复制章节到个人课纲的请求API */
+			sendCopyApi(targetVolume){
+				console.log(JSON.stringify(this.flatRNodes))
+				let upsertParams = [{
+					id: this.curChapter.id,
+					volumeId: targetVolume.id,
+					scope: targetVolume.scope,
+					trees: [this.refreshCopyChapter(this.curChapter)]
+				}]
+				this.$api.syllabus.UpsertTree(upsertParams).then((res) => {
+					if (!res.error && res) {
+						this.$Message.success("复制成功");
+						this.chapterCopyModal = false
+					} else {
+						this.$Message.error("获取数据失败");
+					}
+				}).catch(e => {
+					this.$Message.error(e);
+				}).finally(() => {
+					this.isCopyBtnLoading = false
+				})
+			},
+			/* 将复制的节点内的创建信息、code等更新为当前用户 */
+			refreshCopyChapter(chapterNode){
+				console.log(this.flatRNodes);
+				let myId = this.$store.state.userInfo.TEAMModelId
+				const fn = (source)=>{
+					source.creatorId = myId
+					if(source.rnodes.length){
+						source.rnodes.forEach(i => {
+							i.cntr = myId
+							i.code = i.code.split('-').length > 1 ? i.code.split('-')[0] + '-' + myId : myId
+							i.link = this.flatRNodes.find(j => j.id === i.id).link
+						})
+					}
+					if(source.children.length){
+						source.creatorId = myId
+						source.children.forEach(i => {
+							fn(i)
+						})
+					}
+				}
+				fn(chapterNode)
+				return chapterNode
+			},
+			/* 复制节点到个人课纲 需要把关联的内容全部拷贝到个人的BLOB容器内 */
+			doCopyResources(rnodes,needSave){
+				return new Promise((r,j) => {
+					let promiseArr = []
+					let tmdId = this.$store.state.userInfo.TEAMModelId
+					console.log(JSON.stringify(this.flatRNodes));
+					rnodes.forEach((file,fileIndex) => {
+						let copyFile = JSON.parse(JSON.stringify(file))
+						if(copyFile.type === 'item'){
+							promiseArr.push(this.copyItemToBlob(copyFile,needSave))
+							// 如果不入库 则需要修改资源的link地址
+							if(!needSave){
+								this.flatRNodes[fileIndex].link = '/syllabus/' + rnodes[fileIndex].id + '/' + rnodes[fileIndex].id + '.json'
+							}
+						}else if(copyFile.type === 'paper'){
+							promiseArr.push(this.copyPaperToBlob(copyFile,needSave))
+							// 如果不入库 则需要修改资源的link地址
+							if(!needSave){
+								this.flatRNodes[fileIndex].link = rnodes[fileIndex].link.replace('paper','syllabus')
+							}
+						}else{
+							promiseArr.push(this.copyFileToBlob(copyFile))
+						}
+						this.flatRNodes[fileIndex].code = this.flatRNodes[fileIndex].code.includes('-') ? this.flatRNodes[fileIndex].code.split('-')[0] + '-' +  tmdId : tmdId
+						this.flatRNodes[fileIndex].cntr = tmdId
+					})
+					Promise.all(promiseArr).then(result => {
+						r(result)
+						console.log(result)
+					}).catch(err =>{
+						j(err)
+					})
+				})
+			},
+			/* 根据醍摩豆ID获取对应BLOB个人容器授权信息 */
+			getBlobPrivateSas(tmdId){
+				return new Promise((r,j) => {
+					this.$api.blob.blobSasR({
+						name:tmdId,
+						role:'teacher'
+					}).then(res => {
+						if(!res.error){
+							r(res)
+						}
+					})
+				})
+			},
+			/* 复制试题到当前用户BLOB */
+			copyItemToBlob(resourceItem,needSave){
+				// console.log(JSON.stringify(rnodes))
+				return new Promise(async (r, j) => {
+					let toPath = needSave ? `item/${resourceItem.id}/` : `syllabus/${resourceItem.id}/`
+					// 是否入库 来决定保存的路径
+					let fromPath = `item/${resourceItem.id}`
+					// 试题的拥有者也就是复制的来源容器
+					let myId = this.$store.state.userInfo.TEAMModelId
+					let fileOwner = resourceItem.code.replace('Item-','')
+					let privateSas = await this.getBlobPrivateSas(fileOwner)
+					let privateBlobTool = new BlobTool(privateSas.url, privateSas.name, '?' + privateSas.sas,'private')
+					// 拿到试题的完整数据 方便保存到COSMOS
+					const itemJsonFile = await this.$evTools.getFullItemByTmdId(fileOwner, resourceItem.link)
+					let file = new File([JSON.stringify(itemJsonFile)],resourceItem.id + ".json", {type: "",});
+					console.log(itemJsonFile);
+					// 先把对应试题目录下的全部复制到校本BLOB 然后再更新添加学段科目等字段后的题目Json文件
+					this.$parent.containerClient.copyFolder(toPath,fromPath,privateBlobTool).then(async res => {
+						try{
+							itemJsonFile.blob = '/' + toPath + resourceItem.id + '.json'
+							itemJsonFile.code = myId
+							itemJsonFile.scope = resourceItem.scope
+							this.$parent.saveExercise(itemJsonFile).then(result => {
+								console.log(result)
+								r(result)
+							})
+						}catch(e){
+							j(e)
+						}
+					}).catch(err => {
+						j(err)
+					})
+				})
+			},
+			/* 根据关联的试卷资源获取数据库的试卷信息 方便复制的入库问题 */
+			getCosmosPaper(paperResourceItem){
+				console.log(JSON.stringify(paperResourceItem))
+				return new Promise((r,j) => {
+					this.$api.learnActivity.FindExamPaper({
+						id:paperResourceItem.id,
+						code:paperResourceItem.code.replace('Paper-',''),
+						scope:paperResourceItem.scope
+					}).then(res => {
+						if(!res.error && res.papers.length){
+							r(res.papers[0])
+						}
+					}).catch(e => {
+						j(e)
+					})
+				})
+			},
+			/* 保存复制的试卷到cosmos */
+			async savePaperToCosmos(paperResourceItem){
+				console.log(JSON.stringify(paperResourceItem))
+				let cosmosPaper = await this.getCosmosPaper(paperResourceItem)
+				cosmosPaper.code = this.$store.state.userInfo.TEAMModelId
+				cosmosPaper.scope = 'pravite'
+				return new Promise(async (r,j) => {
+					let params = {
+						paper: cosmosPaper,
+						option: 'insert'
+					}
+					//  保存试卷到cosmos
+					this.$api.learnActivity.SaveExamPaper(params).then(
+						res => {
+							if (res.error == null) {
+								r(res)
+							} else {
+								r(res.error)
+							}
+						},
+						err => {
+							j(err)
+						}
+					)
+				})
+			},
+			/* 复制试题到当前用户BLOB */
+			copyPaperToBlob(resourceItem,needSave){
+				return new Promise(async (r, j) => {
+					let toPath = needSave ? `paper/${resourceItem.title}/` : `syllabus/${resourceItem.title}/`
+					// 是否入库 来决定保存的路径
+					let fromPath = `paper/${resourceItem.title}`
+					// 试题的拥有者也就是复制的来源容器
+					let myId = this.$store.state.userInfo.TEAMModelId
+					let fileOwner = JSON.parse(JSON.stringify(resourceItem.code)).replace('Paper-','')
+					let privateSas = await this.getBlobPrivateSas(fileOwner)
+					let privateBlobTool = new BlobTool(privateSas.url, privateSas.name, '?' + privateSas.sas,'private')
+					// 拿到试题的完整数据 方便保存到COSMOS
+					const paperJsonFile = await this.$evTools.getFullPaperByTmdId(fileOwner, resourceItem.link)
+					// let file = new File([JSON.stringify(paperJsonFile)],resourceItem.id + ".json", {type: "",});
+					// 先把对应试题目录下的全部复制到校本BLOB 然后再更新添加学段科目等字段后的题目Json文件
+					this.$parent.containerClient.copyFolder(toPath,fromPath,privateBlobTool).then(async res => {
+						try{
+							console.log(JSON.stringify(resourceItem))
+							this.savePaperToCosmos(resourceItem).then(result => {
+								console.log(result)
+								r(result)
+							})
+						}catch(e){
+							j(e)
+						}
+					}).catch(err => {
+						j(err)
+					})
+				})
+			},
+			/* 复制内容文件到当前用户BLOB */
+			copyFileToBlob(resourceItem){
+				return new Promise(async (r, j) => {
+					// 试题的拥有者也就是复制的来源容器
+					let fileOwner = resourceItem.code.replace('Paper-','')
+					let privateSas = await this.$evTools.getBlobPrivateSas(fileOwner)
+					let fullLink = 	this.$evTools.getBlobHost() + '/' + fileOwner + resourceItem.link
+					console.log(fullLink)
+					// 拿到试题的完整数据 方便保存到COSMOS
+					this.$parent.containerClient.copyBlob('syllabus/' + resourceItem.title, fullLink, privateSas).then(res => {
+						r(200)
+					}).catch(err => {
+						console.log(err)
+						j(err)
+					})
+				})
+			},
+			/* 获取章节下所有的资源节点 */
+			getAllRNodes(chapterNode){
+				let result = []
+				const fn = (source)=>{
+					result.push(...source.rnodes)
+					if(source.children.length){
+						console.log(JSON.stringify(source.children[0].rnodes));
+						source.children.forEach(i => {
+							fn(i)
+						})
+					}
+				}
+				fn(chapterNode)
+				return result
+			},
 			// 删除节点操作
 			remove(node, data) {
 				let isFirstLevel = this.isFirstLevel(data)
@@ -168,6 +487,10 @@
 										this.$parent.modifyIdArr  = this.$parent.modifyIdArr.filter(i => i !== data.id)
 									}
 									children.splice(index, 1)
+									this.$nextTick().then(() => {
+										const firstNode = document.querySelector('.el-tree-node')
+										firstNode.click();
+									})
 									this.$Message.success(this.$t('syllabus.tree.removeSucTip'))
 								} else {
 									this.$Message.warning(res.error);
@@ -184,7 +507,6 @@
 					}
 				})
 			},
-
 			// 点击添加展开弹窗
 			onAddNode(node,data, e) {
 				e.stopPropagation() // 防止点击事件穿透到父层
@@ -196,7 +518,6 @@
 				this.nodeInfo.title = ''
 				this.curNode = node
 			},
-
 			// 编辑节点操作
 			onEditItem(node, data, e) {
 				e.stopPropagation() // 防止点击事件穿透到父层
@@ -208,7 +529,6 @@
 				this.nodeInfo.id = node.data.id
 				this.curNode = node
 			},
-			
 			/* 根据节点获取它所在的章节信息 */
 			getChapterByNode(node){
 				console.log(node)
@@ -218,7 +538,6 @@
 					return this.getChapterByNode(node.parent)
 				}
 			},
-
 			// 提交编辑或者新增
 			onSubmitNode() {
 				if (!this.nodeInfo.title) {
@@ -248,7 +567,6 @@
 				this.$emit('addModifyId',this.getChapterIdById(this.curData.id))
 				this.$Message.success(this.isEditItem ? this.$t('syllabus.tree.editSucTip') : this.$t('syllabus.tree.addSucTip'))
 			},
-			
 			/* 获取整个树的章节与子节点归属 */
 			getAllChild(arr){
 				let result = []
@@ -260,7 +578,6 @@
 				})
 				this.flatArr = result
 			},
-			
 			/* 递归拉平所有children */
 			flatChildren(children){
 				let result = []
@@ -275,14 +592,13 @@
 				fn(children)
 				return result
 			},
-			
 			/* 根据某个节点ID换取它对应的章节ID */
 			getChapterIdById(id){
 				if(this.flatArr.map(i => i.chapterId).includes(id)){
 					return id
 				}else{
 					let targetChapter = this.flatArr.find(i => i.children.includes(id))
-					return targetChapter.chapterId
+					return targetChapter ? targetChapter.chapterId : 0
 				}
 			}
 
@@ -301,7 +617,6 @@
 					// 判断是否为一级节点,如果是二级节点则需要拿对应的一级节点去做判断
 					let chapterId = nodeData.pid === this.volume.id ? nodeData.id : this.getChapterIdById(nodeData.id)
 					let chapterNode = this.treeDatas.find(i => i.id === chapterId)
-					console.log(this.volume);
 					return this.volume.creatorId === userId || (chapterNode.auth && chapterNode.auth.length && chapterNode.auth.map(i => i.tmdid).includes(userId))
 				}
 			},
@@ -310,6 +625,13 @@
 				return nodeData => {
 					return nodeData.creatorId === this.$store.state.userInfo.TEAMModelId
 				}
+			},
+			inShareView(){
+				return !this.isSchool && this.$parent.activeTab === 'fromShare'
+			},
+			volumeList(){
+				console.log(this.$parent)
+				return this.$parent.myVolumeList
 			}
 		},
 		watch: {
@@ -328,13 +650,15 @@
 					})
 				},
 				immediate: true,
-				deep:true
+				// deep:true
 			},
 			// 监听课纲数据变化
 			volume: {
 				handler: function(n, o) {
 					this.volume = n
-				}
+					
+				},
+				immediate: true
 			}
 		}
 	}

+ 9 - 6
TEAMModelOS/ClientApp/src/components/syllabus/InviteTeacher.vue

@@ -182,8 +182,8 @@
 						this.nodeInfo.auth.push({
 							tmdid:val.id,
 							tmdname:val.name,
-							share:false,
-							coedit:true
+							aggre:0,
+							type:'coedit'
 						})
 					}else{
 						this.nodeInfo.auth.splice(this.nodeInfo.auth.map(i => i.tmdid).indexOf(val.id),1)
@@ -193,6 +193,10 @@
 			/* 分享课纲操作 */
 			doShare(){
 				let val = this.curTeacher
+				if(this.nodeInfo.auth.map(i => i.tmdid).includes(val.id)){
+					this.$Message.warning('该章节已分享给当前教师!请勿重复分享!')
+					return
+				}
 				this.isShareLoading = true
 				this.sendShareApi(val.id,val.name,true,true).then(res => {
 					setTimeout(() => {
@@ -200,8 +204,8 @@
 						this.nodeInfo.auth.push({
 							tmdid:val.id,
 							tmdname:val.name,
-							share:true,
-							coedit:false
+							aggre:0,
+							type:'share'
 						})
 						this.isShareLoading = false
 						this.curTeacher = null
@@ -237,8 +241,7 @@
 								"tmdname": toName
 							}
 						],
-						"coedit": !isShare,
-						"share": isShare,
+						"type": isShare ? 'share' : 'coedit',
 						"issuer": this.$store.state.userInfo.TEAMModelId,
 						"opt": isAdd ? 'add' : 'del',
 						"syllabusId": this.nodeInfo.id,

+ 1 - 0
TEAMModelOS/ClientApp/src/css/dark-iview-poptip.less

@@ -26,6 +26,7 @@
 	}
 	
 	.ivu-poptip-arrow{
+		left: 62% !important;
 		top:-10px !important;
 		border-width: 0 10px 10px !important;
 		border-bottom-color: #3b3b3b !important;

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

@@ -111,7 +111,7 @@ export default {
   '6AIG9YGV': 'Sokrates Report',
   'IPALYEIY': '、IES Smarter Teaching Service Space',
   'ON6MBDOP': 'Smarter School Management Service',
-  'RYGVCPLY': 'AClass One',
+  'RYGVCPLY': 'AClass ONE',
   'RYG6BOPC6MDVCPLY': 'Sokrates Management Service',
-  'AEGMCPLY': 'AClass One cycle'
+  'AEGMCPLY': 'AClass ONE cycle'
   }

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

@@ -3,7 +3,7 @@ export default {
     searchHolder:'搜索',
     delBatch:'批量删除',
     delCus:'删除课程',
-    addCus:'添加课程',
+    addCus:'新增课程',
     editCus:'编辑课程',
     noTeacher:'暂无',
     cusName:'课程名称',
@@ -237,4 +237,17 @@ export default {
     scClass:'校本班级',
     customNameList:'自定义名单',
 
+    // JoinClass.vue
+    join:{
+        title:'加入课程名单',
+        errorInfo:'数据错误,请重新扫码',
+        teacherLabel:'教师:',
+        listLabel:'名单:',
+        joinBtn:'立即加入',
+        errorTile:'信息错误',
+        errorContent:'课程名单获取失败,请重新扫码加入!',
+        joinOk:'加入成功',
+        joinErr:'加入失敗',
+        getListErr:'獲取名單信息失敗'
+    }
 }

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

@@ -22,7 +22,7 @@ export default{
         autoTips2:'此功能仅用于展示情景快速模拟教师评分数据,且分数为随机生成,仅供参考!',
         autoScore:'一键评分',
         autoAnswer:'一键作答',
-        evSubject:'测试科:',
+        evSubject:'测试科:',
         returnTop:'返回顶部',
         mockOk:'模拟成功',
         mockErr:'模拟失败',
@@ -56,7 +56,7 @@ export default{
         evType:'评测类型',
         examType:'考试类别',
         courseType:'课程类别',
-        cusLabel1:'校课程',
+        cusLabel1:'校课程',
         cusLabel2:'个人课程',
         evTarget:'施测对象',
         publishType:'发布方式',
@@ -65,7 +65,7 @@ export default{
         endTime:'结束时间',
         eTimeHolder:'请选择结束时间',
         addSubject:'添加学科',
-        noSubject:'暂无科,请添加科',
+        noSubject:'暂无科,请添加科',
         noSubject1:'* 请先选择测试学段',
         papersLabel:'试卷库',
         perviewLabel:'试卷预览',
@@ -87,13 +87,13 @@ export default{
         formWarning:'请先完善评测基础信息!',
         paperWarning:'请挑选或导入试卷!',
         paperWarning1:'还没有试卷,请挑选或导入试卷!',
-        pdWarning:'请添加测试科!',
+        pdWarning:'请添加测试科!',
         publishOk:'评测发布成功!',
         togglePeriod:'切换学段',
         togglePdTip1:'您已添加',
-        togglePdTip2:'的测试科,如果现在切换学段会清空已选科,确定切换学段吗?',
+        togglePdTip2:'的测试科,如果现在切换学段会清空已选科,确定切换学段吗?',
         toggleOkText:'切换',
-        delPdTitle:'删除科',
+        delPdTitle:'删除科',
         delPdContent:'是否确认删除',
         delOk:'删除成功',
         pdTips:'请先选择测试学段!',
@@ -103,12 +103,12 @@ export default{
     manual:{
         source:'来源:',
         sourceP:'个人试卷库',
-        sourceS:'校试卷库',
+        sourceS:'校试卷库',
         pdLabel:'学段:',
         subjectLabel:'学科:',
         gradeLabel:'年级:',
         fitPd:'适用学段:',
-        fitSubject:'适用科:',
+        fitSubject:'适用科:',
         quCount:'题量:',
         useCount:'使用次数:',
         stdPaper:'已选试卷',
@@ -213,19 +213,14 @@ export default{
     },
 
     mark:{
-        baseSetting:'基础设置',
-        markMode:'阅卷模式',
-        full:'完整阅卷',
-        question:'指定题目',
-        markNum:'阅卷次数',
-        allocation:'分配方式',
-        random:'随机分配',
-        class:'按班分配',
-        scoreDiff:'分差',
+        markTimes:'阅卷次数',
+        markNum1:'单评制',
+        markNum2:'双评制',
+        markNum3:'三评制',
         markRole:'阅卷角色',
-        errRole:'异常处理',
-        arb:'仲裁教师',
-        markRole:'阅卷教师',
+        errRole:'异常处理',
+        arb:'仲裁教师',
+        markRole:'阅卷教师',
         noTea:'暂无教师',
         remove:'移除',
         addTea:'添加阅卷老师',
@@ -252,7 +247,7 @@ export default{
         unassigned:'未分配',
         teaProgress:'教师阅卷进度',
         schedule:'调度',
-        subject:'科',
+        subject:'科',
         stuNum:'考试人数',
         scanProg:'扫描进度',
         assignStatus:'阅卷分配',
@@ -264,6 +259,74 @@ export default{
         progress:'进度',
         action:'操作',
         addTeaTitle:'添加阅卷老师',
-        markNum:'阅卷量'
+        markNum:'阅卷量',
+        noPublish:'暫未發布閱卷任務',
+        publish:'發布任務',
+        startTime:'開始時間',
+        endTime:'結束時間',
+        allocation:'分配方式',
+        allocationByStu:'按人分配',
+        allocationByQu:'按題分配',
+        openArb:'啟用仲裁',
+        yes:'是',
+        no:'否',
+        allQu:'所有題目',
+        noSet:'暫未設置',
+        quNoSet:'題號設置',
+        startErr:'請設置閱卷開始時間',
+        endErr:'請設置閱卷結束時間',
+        typeErr:'請設置分配方式',
+        numErr:'請設置閱卷次數',
+        markerErr:'請設置閱卷老師',
+        markQuNo:'批閱題號',
+        rmvTitle:'移除老師',
+        rmvContent:'是否確認移除',
+        baseErr:'請完成閱卷基礎設置',
+        teacherErr:'閱捲和相關老師設置',
+        saveOk:'保存成功! ',
+        saveErr:'保存失敗! ',
+        //ByqU.vue & ByStu.vue
+        quit:'退出阅卷',
+        examName:'考试名称:',
+        reviewType:'阅卷方式:',
+        byQu:'按题阅卷',
+        byStu:'按人阅卷',
+        stuId:'学生Id',
+        score:'分数:',
+        curQu:'当前题号:',
+        quProg:'题目进度',
+        exception:'异常申报',
+        move:'移动',
+        text:'文字',
+        brush:'画笔',
+        arrow:'箭头',
+        oval:'椭圆',
+        rect:'方框',
+        seal:'印章',
+        clear:'清除批注',
+        marked:'已阅',
+        unmark:'未阅',
+        fullScore:'满分',
+        zeroScore:'零分',
+        submit:'提交分数',
+        setting1:'打分自动切换学生',
+        setting2:'完成批阅自动弹出切换',
+        setting3:'打分自动切换题目',
+        setting4:'完成阅卷自动获取新学生',
+        toggleQu:'切换题目',
+        toggleStu:'切换学生',
+        saveErr:'保存失败',
+        noSocreErr:'请先打分',
+        completeQu:'当前题目已阅完,请切换题目',
+        completeStu:'当前完成当前学生评分,如果继续评分,请切换学生',
+        noAnswer:'未作答',
+        stuInfoErr:'学生信息异常',
+        ummarkQu:'未阅题目',
+        unmarkContent:'题目尚未评分,是否跳转到对应题目继续评分?',
+        finished:'已阅完',
+        noUnMarkStu:'已无未阅学生,请挑选进行中的学生继续阅卷。',
+        completeTask:'您已完成阅卷任务',
+        // ProgPie.vue
+        marking:'进行中'
     }
 }

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

@@ -196,6 +196,7 @@ export default {
   addOk:'添加成功',
   addErr:'添加失败',
   cusTabel:'课程表',
+  setCusTable:'设置课表',
 
   //ClassMgt.vue
   className:'名称',

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

@@ -1,7 +1,7 @@
 export default {
   //ServiceList.vue
-  AEGMCPLY: 'AClass One',
-  RYGVCPLY: 'AClass One',
+  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',
@@ -28,13 +28,13 @@ export default {
   '解除授權後,可在教室中的電腦再次進行綁定授權。': 'After the authorization is cancelled, the binding authorization can be performed again on the computer in the classroom.',
   取消: 'Cancel',
   確定: 'OK',
-  Hiteach序號數: 'Hiteach serial number',
+  Hiteach序號數: 'HiTeach serial number',
   大量: 'Multi',
   單一: 'Single',
   授權: 'Authorization',
   可啟用裝置數: 'Number of devices that can be activated',
   已啟用裝置數: 'Number of activated devices',
-  管理Hiteach教室: 'Manage Hiteach classroom',
+  管理Hiteach教室: 'Manage HiTeach classroom',
   暂无数据: 'No data',
   序號到期日: 'Serial number expiration date: ',
   無到期日: 'No expiration date',

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

@@ -56,6 +56,11 @@ export default {
 	openStatus: '状态',
 	enable: '启用',
 	disable: '禁用',
+	webhook: "webhook",
+	domainName: "域名",
+	subNews: "订阅通知",
+	apiType1: "数据写入接口",
+	apiType2: "数据读取接口",
 	apiName: '接口名称',
 	apiAddress: '接口地址',
 	apiMethod: '请求方法',

+ 10 - 6
TEAMModelOS/ClientApp/src/locale/lang/en-US/stuAccount.js

@@ -1,7 +1,7 @@
 export default {
   // table title
   seatNo: '座号',
-  account: '账号资讯',
+  account: '账号/学号',
   stuName: '姓名',
   classroomCode: '班级',
   classroomName: '班级名称',
@@ -37,8 +37,8 @@ export default {
   delOk:'删除成功',
   isBottom:'已经到底了',
   edit:'修改',
-  adminClass:'行政班管理',
-  teachClass:'教學班管理',
+  adminClass:'行政班',
+  teachClass:'教學班',
   stuMgt:'學生管理',
 
   // AddStudent.vue
@@ -51,9 +51,9 @@ export default {
   stuNameHolder: '请输入学生名称',
   stuSeatNo: '座位号',
   stuSeatNoHolder: '请设置座位号',
-  classroomInfo: '教室信息',
-  classroomInfoHolder: '请选择教室',
-  newClassroom: '建立新教室',
+  classroomInfo: '班級',
+  classroomInfoHolder: '请选择班級',
+  newClassroom: '建立新班級',
   periodInfo: '学制',
   gradeInfo: '年级',
   submitAccount: '建立账号',
@@ -62,6 +62,9 @@ export default {
   chooseNum: '总计:',
   numUnit: '条',
   academicYear: '学年度',
+  noMatch:'暫無匹配數據',
+  stuIdErr:'學生賬號不能為空',
+  stuIdErr1:'學生賬號只能包含數字',
 
   // ImportStudent.vue
   importTitle: '导入学生名单',
@@ -91,6 +94,7 @@ export default {
   attrWarning:'警告:Excel 內栏位不完整!',
   setNoWarning:'警告:Excel 內的座位号重覆!',
   idWarning:'警告:Excel 內账号重复!',
+  idFormatWarning:'错误:学生账号只能包含数字',
   gradeWarning:'警告:年级错误',
   setNoErr:"错误:座位号已在校內重复",
   downloadText:'(下載名單模板)',

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

@@ -2,6 +2,8 @@ export default {
     preview:'P',
     title:'TEAM Model Cloud',
     loading:'加载中',
+    authErr:'权限不足!',
+    development:'功能正在开发中',
     menu:{
         school:'学校',
         private:'个人',

+ 10 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/task.js

@@ -13,4 +13,14 @@ export default {
     mLabel6:'人數',    
     markProg:'批閱進度',    
     mark:'批閱',
+    objectiveQu:'客观题已由系统自动完成评分。',
+    lastLabel1:'还剩',
+    lastLabel2:'人未阅,',
+    continue:'继续阅卷',
+    totalLabel1:'阅卷总量',
+    totalLabel2:'人,',
+    start:'开始阅卷',
+    noUnmark:'暂无未阅学生',
+    noMarking:'暂无进行中学生',
+    noMarked:'暂无已阅学生',
 }

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

@@ -1,4 +1,6 @@
 export default {
+  recent:'最近',
+  recentTips:'临时缓存最近上传的资源,最多保存20条。退出账号或更换电脑缓存记录将会被清空。',
   filterRes: '教材',
   filterPicture: '图片',
   filterVideo: '视频',
@@ -53,7 +55,7 @@ export default {
   specialChart:'不能包含特殊字符',
   noData:'暂无数据',
   applyPd:'适用学段:',
-  applySub:'适用学科',
-   applyGrade:'适用年级',
+  applySub:'适用学科',
+   applyGrade:'适用年级',
   public:'公共资源'
 }

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

@@ -111,7 +111,7 @@ export default {
     '6AIG9YGV': '苏格拉底报告',
     'IPALYEIY': '智慧教学服务空间',
     'ON6MBDOP': '智慧学校大数据管理服务',
-    'RYGVCPLY': 'AClass One',
+    'RYGVCPLY': 'AClass ONE',
     'RYG6BOPC6MDVCPLY': '教与学大数据管理服务',
-    'AEGMCPLY': 'AClass One 週期'
+    'AEGMCPLY': 'AClass ONE 週期'
 }

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

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

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

@@ -3,7 +3,7 @@ export default {
     searchHolder:'搜索',
     delBatch:'批量删除',
     delCus:'删除课程',
-    addCus:'添加课程',
+    addCus:'新增课程',
     editCus:'编辑课程',
     noTeacher:'暂无',
     cusName:'课程名称',
@@ -237,4 +237,17 @@ export default {
     scClass:'学校班级',
     customNameList:'自定义名单',
 
+    // JoinClass.vue
+    join:{
+        title:'加入课程名单',
+        errorInfo:'数据错误,请重新扫码',
+        teacherLabel:'教师:',
+        listLabel:'名单:',
+        joinBtn:'立即加入',
+        errorTile:'信息错误',
+        errorContent:'课程名单获取失败,请重新扫码加入!',
+        joinOk:'加入成功',
+        joinErr:'加入失败',
+        getListErr:'获取名单信息失败'
+    }
 }

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

@@ -1,4 +1,8 @@
 export default {
+	editor:{
+		uploadVideo:'上传本地视频',
+		uploadAudio:'上传本地音频'
+	}, 
     index:{
 		item:'试题',
 		paper:'试卷',

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

@@ -12,7 +12,8 @@ export default{
         finish:'已结束',
         endTime:'结束时间:',
         stop:'立即结束',
-        evType:'测试类型:',
+        evType:'评测类型:',
+        evMode:'评测模式:',
         stuCount:'施测人数:',
         nodata:'暂无评测',
         tab1:'评测数据',
@@ -212,15 +213,10 @@ export default{
     },
 
     mark:{
-        baseSetting:'基础设置',
-        markMode:'阅卷模式',
-        full:'完整阅卷',
-        question:'指定题目',
-        markNum:'阅卷次数',
-        allocation:'分配方式',
-        random:'随机分配',
-        class:'按班分配',
-        scoreDiff:'分差',
+        markTimes:'阅卷次数',
+        markNum1:'单评制',
+        markNum2:'双评制',
+        markNum3:'三评制',
         markRole:'阅卷角色',
         errRole:'异常处理',
         arb:'仲裁教师',
@@ -263,6 +259,74 @@ export default{
         progress:'进度',
         action:'操作',
         addTeaTitle:'添加阅卷老师',
-        markNum:'阅卷量'
+        markNum:'阅卷量',
+        noPublish:'暂未发布阅卷任务',
+        publish:'发布任务',
+        startTime:'开始时间',
+        endTime:'结束时间',
+        allocation:'分配方式',
+        allocationByStu:'按人分配',
+        allocationByQu:'按题分配',
+        openArb:'启用仲裁',
+        yes:'是',
+        no:'否',
+        allQu:'所有题目',
+        noSet:'暂未设置',
+        quNoSet:'题号设置',
+        startErr:'请设置阅卷开始时间',
+        endErr:'请设置阅卷结束时间',
+        typeErr:'请设置分配方式',
+        numErr:'请设置阅卷次数',
+        markerErr:'请设置阅卷老师',
+        markQuNo:'批阅题号',
+        rmvTitle:'移除老师',
+        rmvContent:'是否确认移除',
+        baseErr:'请完成阅卷基础设置',
+        teacherErr:'阅卷和相关老师设置',
+        saveOk:'保存成功!',
+        saveErr:'保存失败!',
+        //ByqU.vue & ByStu.vue
+        quit:'退出阅卷',
+        examName:'考试名称:',
+        reviewType:'阅卷方式:',
+        byQu:'按题阅卷',
+        byStu:'按人阅卷',
+        stuId:'学生Id',
+        score:'分数:',
+        curQu:'当前题号:',
+        quProg:'题目进度',
+        exception:'异常申报',
+        move:'移动',
+        text:'文字',
+        brush:'画笔',
+        arrow:'箭头',
+        oval:'椭圆',
+        rect:'方框',
+        seal:'印章',
+        clear:'清除批注',
+        marked:'已阅',
+        unmark:'未阅',
+        fullScore:'满分',
+        zeroScore:'零分',
+        submit:'提交分数',
+        setting1:'打分自动切换学生',
+        setting2:'完成批阅自动弹出切换',
+        setting3:'打分自动切换题目',
+        setting4:'完成阅卷自动获取新学生',
+        toggleQu:'切换题目',
+        toggleStu:'切换学生',
+        saveErr:'保存失败',
+        noSocreErr:'请先打分',
+        completeQu:'当前题目已阅完,请切换题目',
+        completeStu:'当前完成当前学生评分,如果继续评分,请切换学生',
+        noAnswer:'未作答',
+        stuInfoErr:'学生信息异常',
+        ummarkQu:'未阅题目',
+        unmarkContent:'题目尚未评分,是否跳转到对应题目继续评分?',
+        finished:'已阅完',
+        noUnMarkStu:'已无未阅学生,请挑选进行中的学生继续阅卷。',
+        completeTask:'您已完成阅卷任务',
+        // ProgPie.vue
+        marking:'进行中'
     }
 }

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

@@ -196,6 +196,7 @@ export default {
   addOk:'添加成功',
   addErr:'添加失败',
   cusTabel:'课程表',
+  setCusTable:'设置课表',
 
   //ClassMgt.vue
   className:'名称',

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

@@ -1,7 +1,7 @@
 export default {
   //ServiceList.vue
-  AEGMCPLY: 'AClass One', //AClass One 周期
-  RYGVCPLY: 'AClass One', //AClass One 无周期
+  AEGMCPLY: 'AClass ONE', //AClass One 周期
+  RYGVCPLY: 'AClass ONE', //AClass One 无周期
   IPALYEIY: '智慧教学服务空间',
   '6BOPC6MD': '教与学大数据管理服务',
   ON6MBDOP: '智慧学校大数据管理服务',
@@ -28,13 +28,13 @@ export default {
   '解除授權後,可在教室中的電腦再次進行綁定授權。': '解除授权后,可在教室中的电脑再次进行绑定授权。',
   取消: '取消',
   確定: '确定',
-  Hiteach序號數: 'Hiteach序号数',
+  Hiteach序號數: 'HiTeach序号数',
   大量: '大量',
   單一: '单一',
   授權: '授权',
   可啟用裝置數: '可启用装置数',
   已啟用裝置數: '已启用装置数',
-  管理Hiteach教室: '管理Hiteach教室',
+  管理Hiteach教室: '管理HiTeach教室',
   暂无数据: '暂无数据',
   序號到期日: '序号到期日:',
   無到期日: '无到期日',
@@ -52,7 +52,7 @@ export default {
 
   //SpaceStatus.vue
   智慧教学服務空間狀態: '智慧教学服务空间状态',
-  分配教空間: '分配教学空间',
+  分配教空間: '分配教学空间',
   空間總數: '空间总数',
   已使用空間總數: '已使用空间总数',
   空間使用狀況: '空间使用状况',
@@ -175,7 +175,7 @@ export default {
   '先輸入有效數字,並進行勾選,再套用': '先输入有效数字,并进行勾选,再套用',
 
   //store/spaceAuth.js
-  校已使用空間:'学校已使用空间',
+  校已使用空間:'学校已使用空间',
   已分配給教師空間:'已分配给教师空间',
   剩餘空間:'剩余空间'
 }

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

@@ -56,6 +56,11 @@ export default {
 	openStatus: '状态',
 	enable: '启用',
 	disable: '禁用',
+	webhook: "webhook",
+	domainName: "域名",
+	subNews: "订阅通知",
+	apiType1: "数据写入接口",
+	apiType2: "数据读取接口",
 	apiName: '接口名称',
 	apiAddress: '接口地址',
 	apiMethod: '请求方法',

+ 11 - 7
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/stuAccount.js

@@ -1,7 +1,7 @@
 export default {
   // table title
   seatNo: '座号',
-  account: '账号资讯',
+  account: '账号/学号',
   stuName: '姓名',
   classroomCode: '班级',
   classroomName: '班级名称',
@@ -37,8 +37,8 @@ export default {
   delOk:'删除成功',
   isBottom:'已经到底了',
   edit:'修改',
-  adminClass:'行政班管理',
-  teachClass:'教学班管理',
+  adminClass:'行政班',
+  teachClass:'教学班',
   stuMgt:'学生管理',
 
   // AddStudent.vue
@@ -51,9 +51,9 @@ export default {
   stuNameHolder: '请输入学生名称',
   stuSeatNo: '座位号',
   stuSeatNoHolder: '请设置座位号',
-  classroomInfo: '教室信息',
-  classroomInfoHolder: '请选择教室',
-  newClassroom: '建立新教室',
+  classroomInfo: '班级',
+  classroomInfoHolder: '请选择班级',
+  newClassroom: '建立新班级',
   periodInfo: '学段',
   gradeInfo: '年级',
   submitAccount: '建立账号',
@@ -61,7 +61,10 @@ export default {
   chooseInfo: '选取项目',
   chooseNum: '总计:',
   numUnit: '条',
-  academicYear: '学年度',
+  academicYear: '学级',
+  noMatch:'暂无匹配数据',
+  stuIdErr:'学生账号不能为空',
+  stuIdErr1:'学生账号只能包含数字',
 
   // ImportStudent.vue
   importTitle: '导入学生名单',
@@ -91,6 +94,7 @@ export default {
   attrWarning:'警告:Excel 內栏位不完整!',
   setNoWarning:'警告:Excel 內的座位号重覆!',
   idWarning:'警告:Excel 內账号重复!',
+  idFormatWarning:'错误:学生账号只能包含数字',
   gradeWarning:'警告:年级错误',
   setNoErr:"错误:座位号已在校內重复",
   downloadText:'(下载名单模板)',

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

@@ -39,6 +39,7 @@ export default{
 	isExistVolume:'已存在相同册别',
     tree:{
 		hasResource:'有关联资源',
+		hasCoEdit:'有共编权限',
 		edit:'编辑',
 		add:'添加',
 		remove:'删除',

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

@@ -2,6 +2,8 @@ export default {
     preview:'预览',
     title:'醍摩豆云平台',
     loading:'加载中',
+    authErr:'权限不足!',
+    development:'功能正在开发中',
     menu:{
         school:'学校',
         private:'个人',

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

@@ -13,4 +13,14 @@ export default {
     mLabel6:'人数',
     markProg:'批阅进度',
     mark:'批阅',
+    objectiveQu:'客观题已由系统自动完成评分。',
+    lastLabel1:'还剩',
+    lastLabel2:'人未阅,',
+    continue:'继续阅卷',
+    totalLabel1:'阅卷总量',
+    totalLabel2:'人,',
+    start:'开始阅卷',
+    noUnmark:'暂无未阅学生',
+    noMarking:'暂无进行中学生',
+    noMarked:'暂无已阅学生',
 }

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

@@ -1,4 +1,6 @@
 export default {
+  recent:'最近',
+  recentTips:'临时缓存最近上传的资源,最多保存20条。退出账号或更换电脑缓存记录将会被清空。',
   filterRes: '教材',
   filterPicture: '图片',
   filterVideo: '视频',
@@ -52,8 +54,8 @@ export default {
   delBatchTips2:'请先选择需要删除的文件!',
   specialChart:'不能包含特殊字符',
   noData:'暂无数据',
-  applyPd:'适用学段',
-  applySub:'适用学科',
+  applyPd:'适用学段',
+  applySub:'适用学科',
   applyGrade:'适用年级:',
   public:'公共资源'
 }

+ 6 - 8
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachermgmt.js

@@ -62,12 +62,12 @@ export default {
         'teacher':'教师'
     },
     authority:{
-        'classroom':'班级教室管理',
+        'classroom':'教室管理',
         'system':'学校基础数据管理',
         'studentAccount':'学生账号管理',
         'teachermgmt':'教师账号管理',
-        'classroom-read':'检视班级教室资料',
-        'classroom-upd':'变更班级教室设定',
+        'classroom-read':'检视教室资料',
+        'classroom-upd':'变更教室设定',
         'schoolSetting-read':'检视学校基础设定',
         'schoolSetting-upd':'变更学校基础设定',
         'student-read':'检视学生账号',
@@ -96,15 +96,13 @@ export default {
         'knowledge': '知识点库管理',
         'knowledge-read': '查看知识点库信息',
         'knowledge-upd': '修改知识点库信息',
-        'totalIndex': '学情分析',
+        'analysis': '学情分析',
         'analysis-read': '查看学校学情分析',
         'scboard': '统计分析',
         'scboard-read': '查看统计分析',
         'schoolAc': '学校活动',
         'schoolAc-read': '查看学校活动',
-        'schoolAc-upd':'发布学校活动',
-        'schoolEvaluation':'模拟评测数据',
-        'mock-eva':'一键模拟评测作答和评分数据'
+        'schoolAc-upd':'发布学校活动'
     },
     modal:{
         text1: '此账号权限已变更,是否要给此账号更加合适的职称',
@@ -131,7 +129,7 @@ export default {
             sendInvite:'发送邀请',
             backHome: '重新检索'
         },
-        content: '<span>请输入<span class="point">教师账号</span>、<span class="point">电话</span>或<span class="point">电子信箱</span >等资讯进行搜寻</span>',
+        content: '<span>请输入<span class="point">手机号</span>、<span class="point">醍摩豆Id</span>或<span class="point">电子信箱</span >等资讯进行搜寻</span>',
         skyBox:{
             text1: '本次搜寻结果',
             text2: '档案资料数',

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

@@ -109,7 +109,7 @@ export default {
     '6AIG9YGV': '蘇格拉底報告',
     'IPALYEIY': '智慧教學服務空間',
     'ON6MBDOP': '智慧學校大數據管理服務',
-    'RYGVCPLY': 'AClass One',
+    'RYGVCPLY': 'AClass ONE',
     'RYG6BOPC6MDVCPLY': '教與學大數據管理服務',
-    'AEGMCPLY': 'AClass One 週期'
+    'AEGMCPLY': 'AClass ONE 週期'
 }

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

@@ -72,6 +72,7 @@ export default {
         studentTableC4: '年級',
         studentTableC5: '組別',
         studentTableC6: '組名',
+        studentTableC7: '賬號/學號',
         addClassroomProp1: '選擇預設教室',
         addClassroomProp2: '新建個人教室',
         chooseClassroom: '請選擇系統的教室',

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

@@ -3,7 +3,7 @@ export default {
     searchHolder: '搜尋',
     delBatch: '批量刪除',
     delCus: '刪除課程',
-    addCus: '添加課程',
+    addCus: '新增課程',
     editCus: '編輯課程',
     noTeacher: '暫無',
     cusName: '課程名稱',
@@ -236,5 +236,18 @@ export default {
     nameListType:'類型',
     scClass:'學校班級',
     customNameList:'自定義名單',
-    
+
+    // JoinClass.vue
+    join:{
+        title:'加入課程名單',
+        errorInfo:'數據錯誤,請重新掃碼',
+        teacherLabel:'教師:',
+        listLabel:'名單:',
+        joinBtn:'立即加入',
+        errorTile:'信息錯誤',
+        errorContent:'課程名單獲取失敗,請重新掃碼加入! ',
+        joinOk:'加入成功',
+        joinErr:'加入失敗',
+        getListErr:'獲取名單信息失敗'
+    }  
 }

+ 40 - 36
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/evaluation.js

@@ -1,4 +1,8 @@
 export default {
+	editor: {
+		uploadVideo: '上傳本地視頻',
+		uploadAudio: '上傳本地音訊'
+	},
 	index: {
 		item: '試題',
 		paper: '試卷',
@@ -65,8 +69,8 @@ export default {
 	deleteFail: '刪除失敗',
 	editSuc: '修改成功',
 	backToTop: '跳回頂端',
-	cancelSuc:'取消成功',
-	addSuc:'新增成功',
+	cancelSuc: '取消成功',
+	addSuc: '新增成功',
 	newExercise: {
 		newSchoolItem: '新建學校題目',
 		newPrivateItem: '新建個人題目',
@@ -178,7 +182,7 @@ export default {
 		paperDetails: '試卷詳情',
 		paperAnalysis: '試卷分析',
 		setPaperScore: '設定試卷總分',
-		goAnswerSheet:'預覽答題卡'
+		goAnswerSheet: '預覽答題卡'
 	},
 	importFile: {
 		uploadSuc: '試卷檔案上傳解析成功!',
@@ -212,11 +216,11 @@ export default {
 		spc: '道',
 		goDetails: '查看詳情',
 		noOriginTips: '請先選擇題目來源',
-		tip1:'第',
-		tip2:'題綜合題的配分',
-		tip3:'不足',
-		tip4:'溢出',
-		tip5:'請檢查後重試!'
+		tip1: '第',
+		tip2: '題綜合題的配分',
+		tip3: '不足',
+		tip4: '溢出',
+		tip5: '請檢查後重試!'
 	},
 	points: {
 		addPoint: '新增知識點',
@@ -237,34 +241,34 @@ export default {
 		diffPie: '試卷難度分佈圖',
 		objectivePie: '試卷主客觀題目分佈圖'
 	},
-	getEmptyItems:'拿不到試題',
-	child:'小題',
-	typePieTitle:'題型分佈圖',
-	reImport:'重新匯入',
-	continueImport:'繼續預覽',
-	imgError:'圖片異常提醒',
-	imgErr1:'解析資料存在以下',
-	imgErr2:'處圖片異常,請選擇',
-	imgErr3:'忽略並繼續預覽',
-	imgErr4:'還是',
-	imgErr5:'修改後重新匯入試卷',
-	reImportTip:'請重新匯入正確格式的試卷!',
-	type1:'主觀題',
-	type2:'客觀題',
-	repairResourse:{
-	description:'資源描述',
-	link:'資源連結網址',
-	edit:'編輯',
-	deleteResource:'刪除',
-	addRepair:'增加補救資源',
-	type:'資源類型',
-	place1:'請輸入資源描述',
-	tip1:'(輸入後按Enter即可新增成功)',
-	place2:'請輸入資源網址,按Enter即可新增',
-	confirm:'確認',
-	isExistTip:'已存在相同連結網址!',
-	formatErrorTip:'請輸入正確格式的網址!',
-	noCompleteTip:'請填寫完整',
+	getEmptyItems: '拿不到試題',
+	child: '小題',
+	typePieTitle: '題型分佈圖',
+	reImport: '重新匯入',
+	continueImport: '繼續預覽',
+	imgError: '圖片異常提醒',
+	imgErr1: '解析資料存在以下',
+	imgErr2: '處圖片異常,請選擇',
+	imgErr3: '忽略並繼續預覽',
+	imgErr4: '還是',
+	imgErr5: '修改後重新匯入試卷',
+	reImportTip: '請重新匯入正確格式的試卷!',
+	type1: '主觀題',
+	type2: '客觀題',
+	repairResourse: {
+		description: '資源描述',
+		link: '資源連結網址',
+		edit: '編輯',
+		deleteResource: '刪除',
+		addRepair: '增加補救資源',
+		type: '資源類型',
+		place1: '請輸入資源描述',
+		tip1: '(輸入後按Enter即可新增成功)',
+		place2: '請輸入資源網址,按Enter即可新增',
+		confirm: '確認',
+		isExistTip: '已存在相同連結網址!',
+		formatErrorTip: '請輸入正確格式的網址!',
+		noCompleteTip: '請填寫完整',
 	},
 	completeCount: '填空數量',
 	addTip1: '當前配分超過試卷總分,請重新分配!',

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

@@ -213,15 +213,10 @@ export default {
     },
 
     mark: {
-        baseSetting: '基礎設定',
-        markMode: '閱卷模式',
-        full: '完整閱卷',
-        question: '指定題目',
-        markNum: '閱卷次數',
-        allocation: '分配方式',
-        random: '隨機分配',
-        class: '按班分配',
-        scoreDiff: '分差',
+        markTimes: '閱卷次數',
+        markNum1:'單評制',
+        markNum2:'雙評制',
+        markNum3:'三評制',
         markRole: '閱卷職務',
         errRole: '異常處理:',
         arb: '仲裁教師:',
@@ -264,6 +259,74 @@ export default {
         progress: '進度',
         action: '操作',
         addTeaTitle: '增加閱卷老師',
-        markNum: '閱卷量'
+        markNum: '閱卷量',
+        noPublish:'暫未發布閱卷任務',
+        publish:'發布任務',
+        startTime:'開始時間',
+        endTime:'結束時間',
+        allocation:'分配方式',
+        allocationByStu:'按人分配',
+        allocationByQu:'按題分配',
+        openArb:'啟用仲裁',
+        yes:'是',
+        no:'否',
+        allQu:'所有題目',
+        noSet:'暫未設置',
+        quNoSet:'題號設置',
+        startErr:'請設置閱卷開始時間',
+        endErr:'請設置閱卷結束時間',
+        typeErr:'請設置分配方式',
+        numErr:'請設置閱卷次數',
+        markerErr:'請設置閱卷老師',
+        markQuNo:'批閱題號',
+        rmvTitle:'移除老師',
+        rmvContent:'是否確認移除',
+        baseErr:'請完成閱卷基礎設置',
+        teacherErr:'閱捲和相關老師設置',
+        saveOk:'保存成功! ',
+        saveErr:'保存失敗! ',
+        //ByqU.vue & ByStu.vue
+        quit:'退出閱卷',
+        examName:'考試名稱:',
+        reviewType:'閱卷方式:',
+        byQu:'按題閱卷',
+        byStu:'按人閱卷',
+        stuId:'學生Id',
+        score:'分數:',
+        curQu:'當前題號:',
+        quProg:'題目進度',
+        exception:'異常申報',
+        move:'移動',
+        text:'文字',
+        brush:'畫筆',
+        arrow:'箭頭',
+        oval:'橢圓',
+        rect:'方框',
+        seal:'印章',
+        clear:'清除批註',
+        marked:'已閱',
+        unmark:'未閱',
+        fullScore:'滿分',
+        zeroScore:'零分',
+        submit:'提交分數',
+        setting1:'打分自動切換學生',
+        setting2:'完成批閱自動彈出切換',
+        setting3:'打分自動切換題目',
+        setting4:'完成閱卷自動獲取新學生',
+        toggleQu:'切換題目',
+        toggleStu:'切換學生',
+        saveErr:'保存失敗',
+        noSocreErr:'請先打分',
+        completeQu:'當前題目已閱完,請切換題目',
+        completeStu:'當前完成當前學生評分,如果繼續評分,請切換學生',
+        noAnswer:'未作答',
+        stuInfoErr:'學生信息異常',
+        ummarkQu:'未閱題目',
+        unmarkContent:'題目尚未評分,是否跳轉到對應題目繼續評分? ',
+        finished:'已閱完',
+        noUnMarkStu:'已無未閱學生,請挑選進行中的學生繼續閱卷。 ',
+        completeTask:'您已完成閱卷任務',
+        // ProgPie.vue
+        marking:'進行中'
     }
 }

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

@@ -7,10 +7,10 @@ export default {
   scType: '學校類型:',
   scType1: '國教(K-12)',
   scType2: '大專院校',
-  proSetting: '專業設置',
+  proSetting: '專業學科',
   curSemSta: '當前狀態:',
   schoolNameLabel: '學校名稱:',
-  addSubject: '添加學科',
+  addSubject: '新增學科',
   subType: '學科類型',
   subType1: '通用',
   subType2: '學科',
@@ -32,7 +32,7 @@ export default {
   startDate: '開始於',
   semesterDuration: '學期時長:',
   dayUnit: '天',
-  saveInfo: '變更',
+  saveInfo: '存儲變更',
   noSemester: '沒有設定學期',
   editLabel: '編輯',
   monthHolder: '月',
@@ -69,11 +69,11 @@ export default {
   examHolder: '設定考試類型…',
   noExam: '暫無考試類型',
   eugenicsLabel: '優生率:',
-  eugenicsTips: '優生率計算管道',
+  eugenicsTips: '優生率計算方式',
   incomeLable: '進線率:',
   incomeTips: '(進線人數)/(報名人數)×100%',
   touchLabel: '踩線生:',
-  touchTips: '踩線生計算管道',
+  touchTips: '踩線生計算方式',
   scoreUnit: '分',
   delExamTitle: '删除考試類型',
   delGradeTitle: '删除年級',
@@ -94,7 +94,7 @@ export default {
   subWarning: '學科名稱不能重複',
   exWarning: '考試名稱不能重複',
   majorWarning: '專業名稱不能重複',
-  addSemester: '添加學期',
+  addSemester: '新增學期',
   semesterName: '名稱',
   semStartAt: '開始於',
   admission: '入學期',
@@ -182,7 +182,7 @@ export default {
   bindingErr: 'Hiteach綁定失敗!',
   delClass: '删除班級',
   saveClassWarning: '當前教室數據尚未儲存。如果離開,修改的數據將不會儲存!',
-  addStuBtn: '添加學生',
+  addStuBtn: '新增學生',
   delStuBtn: '移除學生',
   editSeat: '修改座號',
   removeTile: '移除提醒',
@@ -196,6 +196,7 @@ export default {
   addOk: '添加成功',
   addErr: '添加失敗',
   cusTabel: '課程表',
+  setCusTable:'設置課表',
 
   //ClassMgt.vue
   className:'名稱',
@@ -203,7 +204,7 @@ export default {
   untimed:'未到入學時間',
   graduated:'已畢業',
   classLabel:'班級',
-  profession:'專業',
+  profession:'專業學科',
   noProfession:'暫未設置專業',
   all:'全部',
 }

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

@@ -1,7 +1,7 @@
 export default {
   //ServiceList.vue
-  AEGMCPLY: 'AClass One',
-  RYGVCPLY: 'AClass One',
+  AEGMCPLY: 'AClass ONE',
+  RYGVCPLY: 'AClass ONE',
   IPALYEIY: '智慧教學服務空間',
   '6BOPC6MD': '教與學大數據管理服務',
   ON6MBDOP: '智慧學校大數據管理服務',
@@ -28,13 +28,13 @@ export default {
   '解除授權後,可在教室中的電腦再次進行綁定授權。': '解除授權後,可在教室中的電腦再次進行綁定授權。',
   取消: '取消',
   確定: '確定',
-  Hiteach序號數: 'Hiteach序號數',
+  Hiteach序號數: 'HiTeach序號數',
   大量: '大量',
   單一: '單一',
   授權: '授權',
   可啟用裝置數: '可啟用裝置數',
   已啟用裝置數: '已啟用裝置數',
-  管理Hiteach教室: '管理Hiteach教室',
+  管理Hiteach教室: '管理HiTeach教室',
   暂无数据: '暫無資料',
   序號到期日: '序號到期日:',
   無到期日: '無到期日',

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

@@ -56,10 +56,15 @@ export default {
     openStatus: '狀態',
     enable: '啟用',
     disable: '禁用',
+    webhook: "webhook",
+    domainName: "域名",
+	subNews: "訂閱通知",
+	apiType1: "數據寫入接口",
+	apiType2: "數據讀取接口",
     apiName: '接口名稱',
     apiAddress: '接口地址',
     apiMethod: '請求方法',
-    apiParams: '参数示例',
+    apiParams: '參數示例',
     openKeep: '儲存平臺',
     edit: "編輯應用",
     unedit: '取消編輯',

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

@@ -1,9 +1,9 @@
 export default {
   // table title
   seatNo: '座號',
-  account: '帳號資訊',
+  account: '帳號/學號',
   stuName: '姓名',
-  classroomCode: '教室編碼',
+  classroomCode: '班級',
   classroomName: '教室名稱',
   period: '學制',
   grade: '年級',
@@ -37,8 +37,8 @@ export default {
   delOk: '刪除成功',
   isBottom: '已經到底了',
   edit:'修改',
-  adminClass:'行政班管理',
-  teachClass:'教學班管理',
+  adminClass:'行政班',
+  teachClass:'教學班',
   stuMgt:'學生管理',
 
   //AddStudent.vue
@@ -51,17 +51,20 @@ export default {
   stuNameHolder: '請輸入學生名稱',
   stuSeatNo: '座位號',
   stuSeatNoHolder: '請設定座位號',
-  classroomInfo: '教室資訊',
-  classroomInfoHolder: '請選擇教室',
-  newClassroom: '建立新教室',
-  periodInfo: '學制資訊',
+  classroomInfo: '班級',
+  classroomInfoHolder: '請選擇班級',
+  newClassroom: '建立新班級',
+  periodInfo: '學制',
   gradeInfo: '年級',
   submitAccount: '建立帳號',
   submitActive: '儲存',
   chooseInfo: '選取項目',
   chooseNum: '總計:',
   numUnit: '條',
-  academicYear: '學年度',
+  academicYear: '學級',
+  noMatch:'暫無匹配數據',
+  stuIdErr:'學生賬號不能為空',
+  stuIdErr1:'學生賬號只能包含數字',
 
   //ImportStudent.vue
   importTitle: '匯入學生名單',
@@ -91,6 +94,7 @@ export default {
   attrWarning:'警告:Excel 內欄位不完整! ',
   setNoWarning:'警告:Excel 內的座號重覆! ',
   idWarning:'警告:Excel 內帳號重複! ',
+  idFormatWarning:'錯誤:學生賬號只能包含數字',
   gradeWarning:'警告:年級錯誤',
   setNoErr:"錯誤:座位號已在校內重複",
   downloadText:'(下載名單模板)',

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

@@ -39,6 +39,7 @@ export default {
 	isExistVolume: '已存在相同册別',
 	tree: {
 		hasResource: '有關聯資源',
+		hasCoEdit:'有共編許可權',
 		edit: '編輯',
 		add: '添加',
 		remove: '删除',

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

@@ -2,6 +2,8 @@ export default {
     preview:'預覽',
     title:'醍摩豆雲平台',
     loading: '加載中',
+    authErr:'權限不足! ',
+    development:'功能正在開發中',
     menu: {
         school: '學校',
         private: '個人',

+ 10 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/task.js

@@ -13,4 +13,14 @@ export default {
     mLabel6:'人數',    
     markProg:'批閱進度',    
     mark:'批閱',
+    objectiveQu:'客觀題已由系統自動完成評分。 ',
+    lastLabel1:'還剩',
+    lastLabel2:'人未閱,',
+    continue:'繼續閱卷',
+    totalLabel1:'閱卷總量',
+    totalLabel2:'人,',
+    start:'開始閱卷',
+    noUnmark:'暫無未閱學生',
+    noMarking:'暫無進行中學生',
+    noMarked:'暫無已閱學生',
 }

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

@@ -1,4 +1,6 @@
 export default {
+  recent:'最近',
+  recentTips:'臨時緩存最近上傳的資源,最多保存20條。退出賬號或更換電腦緩存記錄將會被清空。 ',
   filterRes: '教材',
   filterPicture: '圖片',
   filterVideo: '影片',
@@ -53,7 +55,7 @@ export default {
   specialChart: '不能包含特殊字元',
   noData: '暫無資料',
   applyPd:'適用學段:',
-  applySub:'適用學科',
-  applyGrade:'適用年級',
+  applySub:'適用學科',
+  applyGrade:'適用年級',
   public:'公共資源'
 }

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

@@ -62,12 +62,12 @@ export default {
         'teacher':'教師'
     },
     authority:{
-        'classroom':'班級教室管理',
+        'classroom':'教室管理',
         'system':'學校基礎數據管理',
         'studentAccount':'學生帳號管理',
         'teachermgmt':'教師帳號管理',
-        'classroom-read':'檢視班級教室資料',
-        'classroom-upd':'變更班級教室設定',
+        'classroom-read':'檢視教室資料',
+        'classroom-upd':'變更教室設定',
         'schoolSetting-read':'檢視學校基礎設定',
         'schoolSetting-upd':'變更學校基礎設定',
         'student-read':'檢視學生帳號',
@@ -129,7 +129,7 @@ export default {
             sendInvite:'發送邀請',
             backHome: '重新檢索'
         },
-        content: '<span>請輸入<span class="point">教師帳號</span>、<span class="point">電話</span>或<span class="point">電子信箱</span>等資訊進行搜尋</span>',
+        content: '<span>請輸入<span class="point">手機號</span>、<span class="point">醍摩豆Id</span>或<span class="point">電子信箱</span>等資訊進行搜尋</span>',
         skyBox:{
             text1: '本次搜尋結果',
             text2: '檔案資料數',

+ 34 - 10
TEAMModelOS/ClientApp/src/router/routes.js

@@ -91,11 +91,11 @@ export const routes = [
 		path: '/joinclass',
 		component: resolve => require(['@/view/joinclass/JoinClass.vue'], resolve)
 	},
-	{
-		path: '/MarkView',
-		name:'FullMarkView',
-		component: resolve => require(['@/view/learnactivity/markpaper/MarkView.vue'], resolve)
-	},
+	// {
+	// 	path: '/MarkView',
+	// 	name:'FullMarkView',
+	// 	component: resolve => require(['@/view/learnactivity/markpaper/MarkView.vue'], resolve)
+	// },
 	{
 		path: '/schoolList',
 		component: Home,
@@ -238,11 +238,11 @@ export const routes = [
 			]
 		},
 		//废弃 阅卷和批注代码混合,不方便维护
-		{
-			path: 'MarkView',
-			name:'MarkView',
-			component: resolve => require(['@/view/learnactivity/markpaper/MarkView.vue'], resolve)
-		},
+		// {
+		// 	path: 'MarkView',
+		// 	name:'MarkView',
+		// 	component: resolve => require(['@/view/learnactivity/markpaper/MarkView.vue'], resolve)
+		// },
 		// 按人阅卷
 		{
 			path: 'ByStu',
@@ -359,6 +359,7 @@ export const routes = [
 				name: 'schoolBank',
 				component: resolve => require(['@/view/evaluation/bank/index.vue'], resolve),
 				meta: {
+					isKeep:true,
 					activeName: 'schoolBank'
 				},
 			},
@@ -367,6 +368,7 @@ export const routes = [
 				name: 'personalBank',
 				component: resolve => require(['@/view/evaluation/bank/index.vue'], resolve),
 				meta: {
+					isKeep:true,
 					activeName: 'personalBank'
 				}
 			}
@@ -377,6 +379,7 @@ export const routes = [
 			name: 'newSchoolPaper',
 			component: resolve => require(['@/view/evaluation/index/CreatePaper.vue'], resolve),
 			meta: {
+				isKeep:true,
 				activeName: 'schoolBank'
 			}
 		},
@@ -385,6 +388,7 @@ export const routes = [
 			name: 'newPrivatePaper',
 			component: resolve => require(['@/view/evaluation/index/CreatePaper.vue'], resolve),
 			meta: {
+				isKeep:true,
 				activeName: 'personalBank'
 			}
 		},
@@ -549,6 +553,7 @@ export const routes = [
 			name: 'schoolEvaluation',
 			component: resolve => require(['@/view/learnactivity/MgtSchoolEva.vue'], resolve),
 			meta: {
+				isKeep:true,
 				activeName: 'schoolEvaluation'
 			}
 		},
@@ -558,6 +563,7 @@ export const routes = [
 			name: 'privateEvaluation',
 			component: resolve => require(['@/view/learnactivity/MgtPrivEva.vue'], resolve),
 			meta: {
+				isKeep:true,
 				activeName: 'privateEvaluation'
 			}
 		},
@@ -654,6 +660,24 @@ export const routes = [
 				activeName: 'settings'
 			}
 		},
+		//设置
+		{
+			path: 'OpenPlat',
+			name: 'OpenPlat',
+			component: resolve => require(['@/view/settings/OpenMgmt2.vue'], resolve),
+			meta: {
+				activeName: 'OpenPlat'
+			}
+		},
+		//设置
+		{
+			path: 'userCenter',
+			name: 'userCenter',
+			component: resolve => require(['@/view/user/UserCenter.vue'], resolve),
+			meta: {
+				
+			}
+		},
 		//课堂记录
 		{
 			path: 'classRecord',

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

@@ -2,10 +2,9 @@ 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空间
+var PRIVATE_SPACE = 1024 * 1024 * 1024 * 1 //教师Blob个人空间
+var SCHOOL_SPACE = 1024 * 1024 * 1024 * 10 //学校Blob空间
 const DEFAULT_SCHOOL_CODE = 'SYSTEM_NO_SCHOOL' //尚未归属学校的默认学校编码
-const BLOB_URL = 'https://teammodelstorage.blob.core.chinacloudapi.cn'  //(废弃) 大陆和国际站的host 不同,不能在这里统一获取,需要从登录信息里面获取
 
 //文件类型,对应内容模块Blob目录
 const CONTENT_TYPES = {
@@ -122,7 +121,6 @@ const GLOBAL = {
 	PRIVATE_SPACE,
 	SCHOOL_SPACE,
 	DEFAULT_SCHOOL_CODE,
-	BLOB_URL,
 	EXAM_TYPE,
 	EXERCISE_TYPES,
 	EXERCISE_DIFFS,

+ 13 - 1
TEAMModelOS/ClientApp/src/store/module/user.js

@@ -155,8 +155,10 @@ export default {
         },
         getRooms: state => {
             return state.schoolProfile.school_rooms
+        },
+        getSchoolBase: state => {
+            return state.schoolProfile.school_base
         }
-
     },
     mutations: {
         setSchoolUserList(state, data) {
@@ -481,6 +483,16 @@ export default {
                 (resolve, reject) => {
                     apiTools.schoolUser.getSchoolAuthorityList().then(
                         res => {
+                            // 暂时去掉四类(课纲、内容、题库、知识点)校本资源的读取权限,老师加入学校默认会添加这四个权限
+                            let auth = ['content-read','exercise-read','knowledge-read','syllabus-read']
+                            for (let i = 0; i < res.authoritylist.length; i++) {
+                                if(auth.includes(res.authoritylist[i].rowKey)){
+                                    res.authoritylist.splice(i,1)
+                                    --i
+                                }
+                            }
+                            
+
                             //設定權限總列表
                             context.commit('setSchoolSettingAuthList', res.authoritylist)
                             //設定老師權限值

+ 3 - 1
TEAMModelOS/ClientApp/src/utils/blobTool.js

@@ -496,6 +496,7 @@ export default class BlobTool {
      * @param {boolean} handleSize 是否内部处理blobsize
      */
     copyFolder(targetFolder, sourceFolder, blobTool, handleSize = true) {
+		console.log(...arguments);
         return new Promise(async (r, j) => {
             let blobs = undefined
             let sasString = ''
@@ -510,6 +511,7 @@ export default class BlobTool {
                 }, false)
                 sasString = this.sasString
             }
+			console.log(blobs);
             //上传之前检查文件夹大小
             let beforeSize = 0
             let cont = ''
@@ -537,7 +539,7 @@ export default class BlobTool {
                                     }], cont)
                                 }
                             }
-                            r('复制结束后')
+                            r(blobItem)
                         }
                     })
                 })

+ 130 - 0
TEAMModelOS/ClientApp/src/utils/editorLangTw.js

@@ -0,0 +1,130 @@
+let editor_tw_config = {
+    wangEditor: {
+        插入: '插入',
+        默认: '默認',
+        创建: '創建',
+        修改: '修改',
+        如: '如',
+        请输入正文: '請輸入正文',
+        menus: {
+          title: {
+                标题: '標題',
+                加粗: '加粗',
+                字号: '字型大小',
+                字体: '字體',
+                斜体: '斜體',
+                下划线: '底線',
+                删除线: '删除線',
+                缩进: '縮進',
+                行高: '行高',
+                文字颜色: '文字顏色',
+                背景色: '背景色',
+                链接: '連結',
+                序列: '序列',
+                对齐: '對齊',
+                引用: '引用',
+                表情: '表情',
+                图片: '圖片',
+                视频: '視頻',
+                表格: '表格',
+                代码: '程式碼',
+                分割线: '分割線',
+                恢复: '恢復',
+                撤销: '撤銷',
+                全屏: '全屏',
+                代办事项: '代辦事項',
+            },
+            dropListMenu: {
+                设置标题: '設定標題',
+                背景颜色: '背景顏色',
+                文字颜色: '文字顏色',
+                设置字号: '設定字型大小',
+                设置字体: '設置字體',
+                设置缩进: '設定縮進',
+                对齐方式: '對齊管道',
+                设置行高: '設定行高',
+                序列: '序列',
+                head: {
+                    正文: '正文',
+                },
+                indent: {
+                    增加缩进: '新增縮進',
+                    减少缩进: '减少縮進',
+                },
+                justify: {
+                    靠左: '靠左',
+                    居中: '居中',
+                    靠右: '靠右',
+                },
+                list: {
+                    无序列表: '無序清單',
+                    有序列表: '有序列錶',
+                },
+            },
+            panelMenus: {
+                emoticon: {
+                    默认: '默認',
+                    新浪: '新浪',
+                    emoji: 'emoji',
+                    手势: '手勢',
+                },
+                image: {
+                    图片链接: '圖片連結',
+                    上传图片: '上傳圖片',
+                    网络图片: '網絡圖片',
+                },
+                link: {
+                    链接: '連結',
+                    链接文字: '連結文字',
+                    删除链接: '删除連結',
+                    查看链接: '查看連結',
+                },
+                video: {
+                    插入视频: '插入視頻',
+                },
+                table: {
+                    行: '行',
+                    列: '列',
+                    的: ' ',
+                    表格: '表格',
+                    添加行: '添加行',
+                    删除行: '删除行',
+                    添加列: '添加列',
+                    删除列: '删除列',
+                    设置表头: '設定表頭',
+                    取消表头: '取消表頭',
+                    插入表格: '插入表格',
+                    删除表格: '删除表格',
+                },
+                code: {
+                    删除代码: '删除程式碼',
+                    修改代码: '修改程式碼',
+                    插入代码: '插入代碼',
+                },
+            },
+        },
+        validate: {
+            张图片: '張圖片',
+            大于: '大於',
+            图片链接: '圖片連結',
+            不是图片: '不是圖片',
+            返回结果: '返回結果',
+            上传图片超时: '上傳圖片超時',
+            上传图片错误: '上傳圖片錯誤',
+            上传图片失败: '上傳圖片失敗',
+            插入图片错误: '插入圖片錯誤',
+            一次最多上传: '一次最多上傳',
+            下载链接失败: '下載連結失敗',
+            图片验证未通过: '圖片驗證未通過',
+            服务器返回状态: '服務器返回狀態',
+            上传图片返回结果错误: '上傳圖片返回結果錯誤',
+            请替换为支持的图片类型: '請替換為支持的圖片類型',
+            您插入的网络图片无法识别: '您插入的網絡圖片無法識別',
+            您刚才插入的图片链接未通过编辑器校验: '您剛才插入的圖片連結未通過編輯器校驗',
+        },
+    }
+}
+
+export {
+	editor_tw_config
+}

+ 20 - 2
TEAMModelOS/ClientApp/src/utils/editorTools.js

@@ -5,6 +5,8 @@ import E from 'wangeditor'
 import createKityformula from "./kityformula";
 import myscriptMath from "./myscript-math-web";
 import { app } from '@/boot-app.js'
+import { editor_tw_config } from './editorLangTw.js'
+import i18next from 'i18next'
 import {
 	Message,
 	Modal
@@ -17,11 +19,20 @@ import {
 export default {
 	/* 初始化自定义富文本配置项 */
 	initMyEditor(editor,vm,isOption) {
+		let curLang = localStorage.getItem('local') || 'zh-cn'
+		// 自定义语言
+		editor.config.languages['tw'] = editor_tw_config
+		// 选择语言
+		editor.config.lang = curLang === 'zh-tw' ? 'tw' : curLang === 'en-us' ? 'en' : 'zh'
+		// 引入 i18next 插件
+		editor.i18next = i18next
+		
 		// 初始化公式、视频、音频、画板功能
 		this.addFormula(vm,editor)
 		this.addVideoUpload(vm,editor)
 		this.addAudio(vm,editor)
 		this.addCanvas(vm,editor)
+		
 		editor.config.uploadImgMaxSize = 2 * 1024 * 1024 // 2M
 		editor.config.uploadImgShowBase64 = true;
 		editor.config.uploadImgMaxLength = 5 // 一次最多上传 5 个图片
@@ -48,6 +59,13 @@ export default {
 
 	/* 初始化自定义富文本简版配置项 */
 	initSimpleEditor(editor) {
+		let curLang = localStorage.getItem('local') || 'zh-cn'
+		// 自定义语言
+		editor.config.languages['tw'] = editor_tw_config
+		// 选择语言
+		editor.config.lang = curLang === 'zh-tw' ? 'tw' : curLang === 'en-us' ? 'en' : 'zh'
+		// 引入 i18next 插件
+		editor.i18next = i18next
 		editor.config.uploadImgMaxSize = 2 * 1024 * 1024 // 2M
 		editor.config.uploadImgShowBase64 = true;
 		editor.config.uploadImgMaxLength = 5 // 一次最多上传 5 个图片
@@ -101,7 +119,7 @@ export default {
 				const upFileId = 'upFileId' + Math.random().toString().slice(2);
 				var tabsConf = {
 					// tab 的标题
-					title: editor.i18next.t("menus.panelMenus.video.上传本地视频 "),
+					title: app.$t('evaluation.editor.uploadVideo'),
 					// 模板
 					tpl: '<div class="w-e-up-img-container">\n <div id="' + inputIFrameId +
 						'" class="w-e-up-btn">\n<i class="w-e-icon-upload2"></i>\n</div>\n <div style="display:none;">\n<input id="' +
@@ -222,7 +240,7 @@ export default {
 				const upFileId = 'upFileId' + Math.random().toString().slice(2);
 				var tabsConf = {
 					// tab 的标题
-					title: editor.i18next.t("menus.panelMenus.video.上传本地音频 "),
+					title: app.$t('evaluation.editor.uploadAudio'),
 					// 模板
 					tpl: '<div class="w-e-up-img-container">\n <div id="' + inputIFrameId +
 						'" class="w-e-up-btn">\n<i class="w-e-icon-upload2"></i>\n</div>\n <div style="display:none;">\n<input id="' +

+ 132 - 42
TEAMModelOS/ClientApp/src/utils/evTools.js

@@ -10,13 +10,11 @@ import { app } from '@/boot-app.js'
 
 
 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) => {
@@ -36,7 +34,7 @@ export default {
 					gradeIds:item.gradeIds,
 					subjectId:item.subjectId,
 					children:item.children || [],
-					scope:item.scope,
+					// scope:item.scope,
 					score: item.score||0,
 					blankCount: item.blankCount||1,
 					repair:item.repair,
@@ -53,15 +51,14 @@ export default {
 			r(itemJson)
 		})
 	},
-	
 	/* 获取保存在COSMOS里面的试题格式 */
-	createCosmosItem(item){
+	createCosmosItem(item,scope,code){
 		return new Promise((r,j) => {
 			let cosmosItem  = {
 				id:item.id,
 				pid:item.pid || null,
-				code:item.code,
-				scope:item.scope,
+				code:code || item.code,
+				scope:scope || item.scope,
 				score:item.score||0,
 				type:item.type,
 				objective:this.getItemType(item.type),
@@ -81,15 +78,14 @@ export default {
 			r(cosmosItem)
 		})
 	},
-	
 	/* 生成试卷的index.json文件格式 */
 	createBlobPaper(paper,slides){
 		return new Promise((r,j) => {
 			let paperItem  = {
 				id:paper.id,
 				name:paper.name,
-				code:paper.code,
-				scope:paper.scope,
+				// code:paper.code,
+				// scope:paper.scope,
 				multipleRule:paper.multipleRule,
 				slides:slides,
 				points:paper.points,
@@ -102,7 +98,6 @@ export default {
 			r(paperItem)
 		})
 	},
-	
 	/* 生成试卷保存在cosmos的数据结构 */
 	createCosmosPaper(paper){
 		return new Promise((r,j) => {
@@ -124,7 +119,42 @@ export default {
 			r(paperItem)
 		})
 	},
-	
+	/* 根据醍摩豆ID获取对应用户Blob内部的完整试题 */
+	getFullItemByTmdId(tmdId,blob){
+		return new Promise(async (r,j) => {
+			let privateSas = await this.getBlobPrivateSas(tmdId)
+			let fullPath = this.getBlobHost() +  '/' + tmdId + blob + privateSas
+			let jsonData = JSON.parse(await $tools.getFile(fullPath))
+			// 如果是综合题 那就拿到children里面的小题id集合 去换取小题的blobJSON文件 然后替换children的内容
+			if(jsonData.exercise.children.length && jsonData.exercise.type === 'compose'){
+				let childrenUrls = jsonData.exercise.children.map(i => this.getBlobHost() +  '/' + tmdId + '/item/' + i + '/' + i + '.json' + privateSas)
+				jsonData.exercise.children = await this.getFullChildren(childrenUrls,tmdId)
+			}
+			// 调整渲染试题数据结构
+			jsonData.exercise.question = jsonData.item[0].question
+			jsonData.exercise.blob = fullPath
+			jsonData.exercise.code = tmdId
+			jsonData.exercise.option = jsonData.item[0].option
+			jsonData.exercise.id = jsonData.id
+			jsonData.exercise.scope = 'private'
+			jsonData.exercise.pid = jsonData.pid
+			jsonData.exercise = await this.doAddHost(jsonData.exercise,null,tmdId)
+			r(jsonData.exercise)
+		})
+	},
+	/* 根据醍摩豆ID获取对应BLOB个人容器授权信息 */
+	getBlobPrivateSas(tmdId){
+		return new Promise((r,j) => {
+			$api.blob.blobSasR({
+				name:tmdId,
+				role:'teacher'
+			}).then(res => {
+				if(!res.error){
+					r('?' + res.sas)
+				}
+			})
+		})
+	},
 	/* 获取完整的试题数据 */
 	getFullItem(list,examScope){
 		console.log('接受到的examScope',examScope)
@@ -140,24 +170,31 @@ export default {
 						const blobHost = curScope === 'school' ?  JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8")).blob_uri :  JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8")).blob_uri
 						// 根据试题的Blob地址 去读取JSON文件
 						let sasString = curScope === 'school' ?  await $tools.getSchoolSas() : await $tools.getPrivateSas()
-						let jsonInfo = list[i].blob.includes('https://') ? await $tools.getFile(list[i].blob + sasString.sas) : await $tools.getFile(blobHost + list[i].blob + sasString.sas)
-						let jsonData = JSON.parse(jsonInfo)
-						// 如果是综合题 那就拿到children里面的小题id集合 去换取小题的blobJSON文件 然后替换children的内容
-						if(jsonData.exercise.children.length && jsonData.exercise.type === 'compose'){
-							let childrenUrls = jsonData.exercise.children.map(i => blobHost + '/item/' + i + '/' + i + '.json' + sasString.sas)
-							jsonData.exercise.children = await this.getFullChildren(childrenUrls,list[i].code)
+						try{
+							let jsonInfo = list[i].blob.includes('https://') ? await $tools.getFile(list[i].blob + sasString.sas) : await $tools.getFile(blobHost + list[i].blob + sasString.sas)
+							let jsonData = JSON.parse(jsonInfo)
+							// 如果是综合题 那就拿到children里面的小题id集合 去换取小题的blobJSON文件 然后替换children的内容
+							if(jsonData.exercise.children.length && jsonData.exercise.type === 'compose'){
+								let childrenUrls = jsonData.exercise.children.map(i => blobHost + '/item/' + i + '/' + i + '.json' + sasString.sas)
+								jsonData.exercise.children = await this.getFullChildren(childrenUrls,list[i].code)
+							}
+							// 调整渲染试题数据结构
+							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.scope = list[i].scope
+							jsonData.exercise.option = jsonData.item[0].option
+							jsonData.exercise.id = list[i].id
+							jsonData.exercise.pid = jsonData.pid
+							jsonData.exercise = await this.doAddHost(jsonData.exercise)
+							r(jsonData.exercise)
+						}catch(e){
+							console.log(e)
+							this.$Message.error(e)
 						}
-						// 调整渲染试题数据结构
-						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
-						jsonData.exercise.id = list[i].id
-						jsonData.exercise.pid = jsonData.pid
-						jsonData.exercise = await this.doAddHost(jsonData.exercise)
-						r(jsonData.exercise)
+						
 					}else{
 						r(null)
 					}
@@ -172,12 +209,11 @@ export default {
 			})
 		})
 	},
-	
-	/* 给富文本添加 */
-	doAddHost(exerciseItem,paperItem){
+	/* 给富文本添加 cntr是防止读取的是其他用户的BLOB */
+	doAddHost(exerciseItem,paperItem,cntr){
 		/* 如果操作的是试卷内的试题 则需要拿试卷的code来作为containerName */
 		let curScope = paperItem ? paperItem.scope : exerciseItem.scope
-		let container = curScope === 'school' ? store.state.userInfo.schoolCode : store.state.userInfo.TEAMModelId
+		let container = cntr || (curScope === 'school' ? store.state.userInfo.schoolCode : store.state.userInfo.TEAMModelId)
 		let isSubjective = exerciseItem.type === 'complete' || exerciseItem.type === 'subjective' || exerciseItem.type === 'compose'
 		let richTextObj = {
 			question: exerciseItem.question,
@@ -245,7 +281,6 @@ export default {
 			})
 		})
 	},
-	
 	/* 保存综合题小题 */
 	saveChildren(children,containerClient){
 		return new Promise((resolve,reject) => {
@@ -289,7 +324,6 @@ export default {
 		})
 		
 	},
-	
 	/* 获取综合题子题的Blob数据 */
 	getFullChildren(urls,code){
 		return new Promise((resolve,reject) => {
@@ -317,7 +351,66 @@ export default {
 			})
 		})
 	},
-	
+	/* 根据醍摩豆ID获取对应用户Blob内部的完整试卷 */
+	getFullPaperByTmdId(tmdId,blob){
+		return new Promise(async (r,j) => {
+			console.log('根据ID获取试题')
+			let privateSas = await this.getBlobPrivateSas(tmdId)
+			let fullPath = this.getBlobHost() +  '/' + tmdId + blob + '/index.json' + privateSas
+			try{
+				let jsonInfo = await $tools.getFile(fullPath)
+				let jsonData = JSON.parse(jsonInfo)
+				// 获取试卷包含的试题数据并包装好
+				if(jsonData.slides && jsonData.slides.length){
+					let promiseArr = []
+					let allItems = []
+					jsonData.item = []
+					const path = this.getBlobHost() +  '/' + tmdId + blob
+					jsonData.slides.forEach(async (item,index) => {
+						promiseArr.push(new Promise(async (resolve,reject) => {
+							try{
+								// 获取题目JSON并且包装成完整试题对象
+								let itemJson = JSON.parse(await $tools.getFile(path + '/' + item.url + privateSas))
+								itemJson.exercise.question = itemJson.item[0].question
+								itemJson.exercise.option = itemJson.item[0].option
+								itemJson.exercise.id = itemJson.id 
+								itemJson.exercise.pid = itemJson.pid 
+								itemJson.exercise.blob = path + '/' + item.url // 添加blob是方便在保存试卷是 refresh 与导入的试题区分开
+								itemJson.exercise.score = item.scoring ? item.scoring.score : 0
+								try{
+									itemJson.exercise = await this.doAddHost(itemJson.exercise,{ name : jsonData.name },tmdId) // 检测试题中的富文本 为有src为相对路径的音视频文件添加blob的HOST地址
+									resolve(itemJson.exercise)
+								}catch(e){
+									reject(e)
+								}
+							}catch(e){
+								reject(e)
+							}
+						}))
+					})
+					
+					Promise.all(promiseArr).then(res => {
+						res.forEach((resItem,resIndex) => {
+							resItem.children = []
+							if(resItem.pid){
+								let pItem = res.filter(i => i.id === resItem.pid)[0]
+								pItem.children.push(resItem)
+								pItem.score = pItem.score + resItem.score
+							}
+						})
+						jsonData.item = res.filter(i => !i.pid)
+						r(jsonData)
+					}).catch(e => {
+						// Message.error('试卷文件读取失败')
+						j(e)
+					})
+				}
+			}catch(e){
+				console.log(e)
+				j(e)
+			}
+		})
+	},
 	/* 获取完整的试卷数据 */
 	getFullPaper(paper,examScope){
 		console.log(paper)
@@ -385,8 +478,6 @@ export default {
 			}
 		})
 	},
-	
-	
 	/* 获取完整的试卷数据 */
 	getStuPaper(paper, examScope) {
 		let curScope = examScope || paper.scope
@@ -458,18 +549,17 @@ export default {
 			}
 		})
 	},
-	
-	// 提取富文本内容中的文本
+	/* 提取富文本内容中的文本 */
 	getSimpleText(html) {
 		var r = /<\/?(img)[^>]*>/gi;
 		return html.replace(r, "");
 	},
-	
+	/* 判断是否为客观题 */
 	getItemType(type){
 		const objective = ['single','multiple','judge']
 		return objective.includes(type)
 	},
-	
+	/* 获取img标签内的src */
 	getImgSrc(richtext) {
 	    let imgList = [];
 	    richtext.replace(/<video [^>]*src=['"]([^'"]+)[^>]*>/g, (match, capture) => {

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

@@ -249,7 +249,7 @@ function findChartIndex(str, cha, num) {
 }
 
 /**
- * 根据班级学年年级名称
+ * 根据学年获取年级名称
  * @param data 学校基础数据 schoolProfile.school_base
  * @param curPd 当前学段id
  * @param year 学年
@@ -283,6 +283,36 @@ function getGradeNameByYear(data, curPd, year) {
         return '- -'
     }
 }
+/**
+ * 根据班级学年年级名称
+ * @param data 学校基础数据 schoolProfile.school_base
+ * @param curPd 当前学段id
+ * @param grade 年级index
+ */
+function getYearByGrade(data, curPd, grade) {
+    let date = new Date()
+    let curYear = date.getFullYear()
+    let month = date.getMonth() + 1
+    if (grade > -1 && data && data.period && curPd) {
+        let pData = data.period.find(item => {
+            return item.id == curPd
+        })
+        if (pData) {
+            let start = pData.semesters.find(item => {
+                return item.start == 1
+            })
+            // 根据入学月份确定当前年级和学级的关系
+            if (start && month < start.month) {
+                curYear--
+            }
+            return curYear - grade
+        } else {
+            return curYear
+        }
+    } else {
+        return curYear
+    }
+}
 
 export default {
     groupBy,
@@ -302,5 +332,6 @@ export default {
     formatBytes,
     uuid,
     findChartIndex,
-    getGradeNameByYear
+    getGradeNameByYear,
+    getYearByGrade
 }

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

@@ -1,6 +1,9 @@
 import $api from '@/api'
 import store from '@/store'
 import { app } from '@/boot-app.js'
+import {
+	Message
+} from 'view-design'
 /**
  * 校验blob授权是否过期
  * */
@@ -272,7 +275,19 @@ export default {
 			xhr.open('get', url); //url填写后台的接口地址,如果是post,在formData append参数(参考原文地址)
 			// xhr.responseType = 'arraybuffer';
 			xhr.onload = function(e) {
-				resolve(e.currentTarget.response)
+				switch (e.currentTarget.status){
+					case 200:
+						resolve(e.currentTarget.response)
+						break;
+					case 404:
+						Message.error('未访问到资源!')
+						break;
+					case 403:
+						Message.error('授权异常,无法访问!')
+						break;		
+					default:
+						break;
+				}
 			};
 			xhr.send(formData);
 		})
@@ -423,6 +438,7 @@ export default {
 	 * 获取单个文件授权
 	 */
 	getFileSas(param) {
+		console.log('获取单个文件授权',param)
 		return new Promise((r, j) => {
 			$api.blob.urlSasR({
 				url: param

+ 21 - 12
TEAMModelOS/ClientApp/src/view/Home.vue

@@ -4,9 +4,10 @@
         <BaseLayout>
             <!-- 头部右侧个人中心部分 -->
             <div class="header-right-box fl-around" slot="header-content">
-                <Icon custom="iconfont icon-home" :color="routerName == 'homePage' ? '#1CC0F3':'#d0d0d0'" @click="toHome" />
+                <Icon style="display:block" custom="iconfont icon-home" :color="routerName == 'homePage' ? '#1CC0F3':'#d0d0d0'" @click="toHome" />
                 <BaseNotification :msgs="msgs"></BaseNotification>
-                <Icon type="ios-settings" :color="routerName == 'settings' ? '#1CC0F3':'#d0d0d0'" @click="toSettings" />
+                <span class="header-split"></span>
+                <!-- <Icon type="ios-settings" :color="routerName == 'settings' ? '#1CC0F3':'#d0d0d0'" @click="toSettings" /> -->
                 <!-- 问题答疑页面暂未开发 暂时注释 -->
                 <!-- <Icon type="md-help-circle" :color="routerName == 'feedback' ? '#1CC0F3':'#d0d0d0'" @click="toFeedback"/> -->
                 <BaseUserPoptip @logout="basicMenu('quit')"></BaseUserPoptip>
@@ -28,7 +29,7 @@ export default {
     components: {},
     data() {
         return {
-			msgs:[],
+            msgs: [],
             isShowMock: false,
             isOpenDrawer: false,
             routerName: '',
@@ -58,14 +59,14 @@ export default {
                 schoolCode: this.$GLOBAL.DEFAULT_SCHOOL_CODE
             })
         }
-		
-		this.$api.service.getNotification({
-			"from":"ies5:" + user_profile.defaultschool || user_profile.schools[0].schoolId,
-			"receiver": user.id
-		}).then(res => {
-			console.log('端外通知',res)
-			this.msgs = res.msgs
-		})
+
+        this.$api.service.getNotification({
+            "from": "ies5:" + user_profile.defaultschool || user_profile.schools[0].schoolId,
+            "receiver": user.id
+        }).then(res => {
+            console.log('端外通知', res)
+            this.msgs = res.msgs
+        })
 
 
     },
@@ -128,11 +129,19 @@ export default {
 </script>
 
 <style scoped>
+.header-split {
+    display: block;
+    width: 1px;
+    background: #797979;
+    height: 30px;
+}
 .header-right-box {
-    width: 400px;
+    width: 240px;
     margin: 12px;
     line-height: 1.5;
     float: right;
+    height: 45px;
+    margin-right: 20px;
 }
 
 .header-right-box .ivu-icon {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/answersheet/BaseEditor.vue

@@ -354,6 +354,7 @@
 						let curEditorH = editorDom.clientHeight; // 默认200px
 						let leftHeight = paperH - curEditorY - lastBottomGap - SVG_BORDER_MB;
 						let fixHeight = curEditorH - leftHeight + 20
+						// console.log(itemOrder, '距离第一页顶点的Y', Y);
 						if(itemOrder === 6){
 							console.log(itemOrder, 'rectTop', rectTop);
 							console.log(itemOrder, 'scrollDis', scrollDis);
@@ -766,7 +767,6 @@
 			items: {
 				handler(n, o) {
 					if (n.length) {
-						console.log(n)
 						let objectiveArr = ["complete"];
 						this.completeItems = n.filter((item) =>
 							objectiveArr.includes(item.type)

+ 28 - 4
TEAMModelOS/ClientApp/src/view/answersheet/index.vue

@@ -139,6 +139,10 @@
 				type: String,
 				default: "",
 			},
+			paper:{
+				type:Object,
+				default:() => {}
+			}
 		},
 		components: {
 			SheetObjective,
@@ -186,7 +190,8 @@
 			};
 		},
 		created() {
-			let routerPaper = this.$route.params.paper
+			let routerPaper = this.$route.params.paper || this.paper
+			console.log(routerPaper)
 			if (routerPaper) {
 				this.$store.commit('clearFixArr')
 				this.$store.commit('clearPage')
@@ -255,12 +260,23 @@
 				})
 			},
 			goBack() {
-				this.$router.push({
-					name: this.fromRouter || 'schoolBank',
-					params: {
+				let params = {}
+				let curEditPaper = localStorage.getItem('c_edit_paper')
+				if(this.$route.params.paper && (this.fromRouter === 'newSchoolPaper' || this.fromRouter === 'newPrivatePaper') && curEditPaper){
+					params = {
+						paper:JSON.parse(curEditPaper)
+					}
+				}
+				if(this.$route.params.paper && (this.fromRouter === 'schoolBank' || this.fromRouter === 'personalBank')){
+					params = {
 						tabName: 'paper'
 					}
+				}
+				this.$router.push({
+					name: this.fromRouter || 'schoolBank',
+					params: params
 				})
+				// this.$router.go(-1)
 			},
 			reload() {
 				this.isRouterAlive = false;
@@ -376,6 +392,14 @@
 				vm.fromRouter = from.name
 			})
 		},
+		beforeRouteLeave(to, from, next) {
+			if(to.name === 'newSchoolPaper' || to.name === 'newPrivatePaper' || to.name === 'schoplBank' || to.name === 'personalBank'){
+				console.error(to)
+				// 设置下一个路由的 meta
+				to.meta.isKeep = true;  // 让 A 缓存,即不刷新
+			}
+			next();
+		},
 		computed: {
 			getPage() {
 				return this.$store.state.answerSheet.pages;

+ 27 - 21
TEAMModelOS/ClientApp/src/view/evaluation/bank/TestPaperList.vue

@@ -1,7 +1,11 @@
 <template>
 	<div class="pl-container" ref="plContainer">
 		<!-- 条件筛选部分 -->
-		<BaseFilter ref="baseFilter" @onChange="onFilterChange" :filterCounts="filterCounts" :isFilterPaper="isFilterPaper"  v-if="!isPreview"></BaseFilter>
+		<BaseFilter ref="baseFilter" @onChange="onFilterChange" :filterCounts="filterCounts"
+		 :isFilterPaper="isFilterPaper"
+		 @onSearchChange="onSearchChange"
+		 @onCloseSearch="onCloseSearch"
+		   v-if="!isPreview"></BaseFilter>
 
 		<!-- 空数据展示 -->
 		<div v-if="paperList.length === 0" class="no-data-text">
@@ -27,6 +31,8 @@
 								<span v-show="gIndex !== paper.gradeIds.length - 1"> / </span></span></span>
 						<span class="info-item">{{$t('evaluation.paperList.itemCount')}}:<span
 								class="info-bold">{{ paper.scoring ? paper.scoring.length : 0 }}</span></span>
+						<span class="info-item">{{$t('evaluation.filter.useCount')}}:<span
+								class="info-bold">{{ paper.useCount || 0 }}</span></span>		
 						<!-- <span class="info-item">难度系数:<span class="info-bold">{{ paper.item ? handleDiffCalc(paper.item) : 0 }}</span></span> -->
 					</div>
 					<div class="paper-item-tools" v-if="!chooseModel">
@@ -142,6 +148,7 @@
 				filterParams: {},
 				findCountParams: {},
 				originList: [],
+				originRes:[],
 				schoolInfo: {},
 				filterSort: 'createTime',
 				evaluationInfo: null,
@@ -170,6 +177,9 @@
 			this.isShowSchoolBank = this.$route.name === "schoolBank";
 
 		},
+		activated() {
+			this.isShowSchoolBank = this.$route.name === "schoolBank";
+		},
 		methods: {
 			
 			onCheckPaper(item){
@@ -277,6 +287,7 @@
 					this.getItemsCount(list,filterKey)
 					this.paperList = list
 					this.originList = list
+					this.originRes = JSON.parse(JSON.stringify(list))
 					this.totalNum = list.length
 					this.pageChange(1)
 					setTimeout(() => {
@@ -291,6 +302,20 @@
 				})
 			},
 			
+			/* 搜索词汇发生变化 */
+			onSearchChange(val) {
+				this.originList = this.originRes.filter(i => i.name.indexOf(val) > -1)
+				this.totalNum = this.originList.length
+				this.pageChange(1)
+			},
+			/* 关闭搜索 */
+			onCloseSearch() {
+				this.$refs.baseFilter.searchVal = ''
+				this.originList = JSON.parse(JSON.stringify(this.originRes))
+				this.totalNum = this.originList.length
+				this.pageChange(1)
+			},
+			
 			/* 获取所有学段下的试题总数 */
 			getPeriodCount(papers){
 				let periodIdArr = this.periodList.map(i => i.id)
@@ -349,24 +374,7 @@
 				console.log('要下载的试卷', fullPaperJson)
 			},
 			
-			// async renderAnswerSheet(paper){
-			// 	this.dataLoading = true
-			// 	try{
-			// 		let fullPaperJson = this.fullPaperJson.id === paper.id ? this.fullPaperJson : await this.$evTools.getFullPaper(paper)
-			// 		// this.isShowSheet = true
-			// 		this.dataLoading = false
-			// 		this.$router.push({
-			// 			name: 'answerSheet',
-			// 			params: {
-			// 				paper: fullPaperJson
-			// 			}
-			// 		})
-			// 	}catch(e){
-			// 		this.$Message.error(this.$t('evaluation.paperList.paperErrorTip'))
-			// 		this.dataLoading = false
-			// 	}
-				
-			// },
+
 
 			/**
 			 * 删除试卷
@@ -495,8 +503,6 @@
 				this.schoolInfo = schoolProfile.school_base
 				this.periodList = this.schoolInfo.period
 			}
-
-
 		},
 		computed: {
 			isSchool() {

+ 15 - 4
TEAMModelOS/ClientApp/src/view/evaluation/bank/index.vue

@@ -66,8 +66,6 @@
 				isShowBackList:false,
 			}
 		},
-		created() {
-		},
 		methods: {
 			onBackToTop(){
 				this.$refs.bankContainer.scrollIntoView()
@@ -146,12 +144,25 @@
 				return this.$store.state.totalAnalysis.paperScrollTop
 			},
 		},
+		beforeRouteLeave(to, from, next) {
+			if(to.name === 'newSchoolPaper' || to.name === 'newPrivatePaper'){
+				console.error(to)
+				// 设置下一个路由的 meta
+				to.meta.isKeep = false;  // 让 A 缓存,即不刷新
+			}
+			next();
+		},
 		watch: {
 			paperScrollTop: {
 				handler(n) {
-					console.log(n)
+					// console.log(n)
 				}
-			}
+			},
+			$route( to , from ){   
+			   if(from.name !== 'answerSheet' && (to.name === 'schoolBank' || to.name === 'personalBank')){
+				  this.onShowPaperList()
+			   }
+			 }
 		}
 	}
 </script>

+ 1 - 0
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseExerciseList.vue

@@ -720,6 +720,7 @@
 						this.pageScrollTo(0)
 						this.$nextTick(() => {
 							// this.$MathJax.MathQueue(this.$refs.mathJaxContainer);
+							// this.onConfirmTypeScore()
 						})
 					}
 				},

+ 0 - 0
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseFilter.vue


Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä