Browse Source

Merge branch 'develop3.0' of http://106.12.23.251:10080/TEAMMODEL/TEAMModelOS into develop3.0

zhouj1203@hotmail.com 5 năm trước cách đây
mục cha
commit
d82d4c7784
82 tập tin đã thay đổi với 2688 bổ sung1390 xóa
  1. 1 0
      TEAMModelOS.SDK/Context/Configuration/BaseConfigModel.cs
  2. 1 1
      TEAMModelOS.SDK/Module/AzureBlob/Implements/AzureBlobDBRepository.cs
  3. 3 6
      TEAMModelOS.SDK/Module/AzureCosmosDBV3/AzureCosmosDBV3Repository.cs
  4. 1 2
      TEAMModelOS.SDK/Module/AzureCosmosDBV3/IAzureCosmosDBV3Repository.cs
  5. 5 0
      TEAMModelOS.Service/Models/Learn/HomeWork.cs
  6. 1 1
      TEAMModelOS.Service/Models/Syllabus/SyllabusVolume.cs
  7. 22 38
      TEAMModelOS.Service/Services/ChangeFeed/ChangeFeedInvoke.cs
  8. 4 2
      TEAMModelOS.Service/Services/ChangeFeed/IChangeFeedInvoke.cs
  9. 2 1
      TEAMModelOS.Service/Services/ChangeFeed/IChangeFeedService.cs
  10. 10 0
      TEAMModelOS.Service/Services/ChangeFeed/IChangeService.cs
  11. 8 2
      TEAMModelOS.Service/Services/ChangeFeed/KnowledgeChangeFeed.cs
  12. 23 0
      TEAMModelOS.Service/Services/ChangeFeed/SyllabusVolumeChangeFeed.cs
  13. 5 9
      TEAMModelOS.Service/TEAMModelOS.Model.xml
  14. 1 0
      TEAMModelOS/ClientApp/package.json
  15. 58 0
      TEAMModelOS/ClientApp/src/access/index.js
  16. 1 1
      TEAMModelOS/ClientApp/src/api/classMgmt.js
  17. 110 102
      TEAMModelOS/ClientApp/src/api/index.js
  18. 6 0
      TEAMModelOS/ClientApp/src/api/learnActivity.js
  19. 6 0
      TEAMModelOS/ClientApp/src/api/login.js
  20. 9 0
      TEAMModelOS/ClientApp/src/api/schoolList.js
  21. 6 0
      TEAMModelOS/ClientApp/src/api/teachMgmt.js
  22. BIN
      TEAMModelOS/ClientApp/src/assets/image/FFFFFFFF.png
  23. BIN
      TEAMModelOS/ClientApp/src/assets/image/headerT.png
  24. 3 52
      TEAMModelOS/ClientApp/src/boot-app.js
  25. 22 10
      TEAMModelOS/ClientApp/src/common/UploadFile.vue
  26. 4 0
      TEAMModelOS/ClientApp/src/components/learnactivity/BaseHwForm.less
  27. 19 6
      TEAMModelOS/ClientApp/src/components/learnactivity/BaseHwForm.vue
  28. 22 8
      TEAMModelOS/ClientApp/src/components/learnactivity/BaseHwTable.vue
  29. 48 0
      TEAMModelOS/ClientApp/src/components/public/main/index.less
  30. 42 23
      TEAMModelOS/ClientApp/src/components/public/main/index.vue
  31. 4 0
      TEAMModelOS/ClientApp/src/icons.js
  32. 8 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/error.js
  33. 9 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/index.js
  34. 10 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/login.js
  35. 21 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolList.js
  36. 42 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/teachermgmt.js
  37. 8 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/error.js
  38. 9 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/index.js
  39. 10 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/login.js
  40. 21 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/schoolList.js
  41. 42 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachermgmt.js
  42. 8 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/error.js
  43. 9 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/index.js
  44. 10 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/login.js
  45. 21 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/schoolList.js
  46. 42 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/teachermgmt.js
  47. 85 0
      TEAMModelOS/ClientApp/src/mock/index.js
  48. 0 1
      TEAMModelOS/ClientApp/src/router/_import_file.js
  49. 8 4
      TEAMModelOS/ClientApp/src/router/index.js
  50. 38 11
      TEAMModelOS/ClientApp/src/router/routes.js
  51. 82 0
      TEAMModelOS/ClientApp/src/service/User.js
  52. 40 0
      TEAMModelOS/ClientApp/src/utils/formRule.js
  53. 1 9
      TEAMModelOS/ClientApp/src/view/404.vue
  54. 30 2
      TEAMModelOS/ClientApp/src/view/login/Index.less
  55. 122 54
      TEAMModelOS/ClientApp/src/view/login/Index.vue
  56. 32 0
      TEAMModelOS/ClientApp/src/view/schoolList/Index.less
  57. 287 0
      TEAMModelOS/ClientApp/src/view/schoolList/Index.vue
  58. 17 7
      TEAMModelOS/ClientApp/src/view/selflearning/LearnProgress.less
  59. 134 36
      TEAMModelOS/ClientApp/src/view/selflearning/LearnProgress.vue
  60. 4 0
      TEAMModelOS/ClientApp/src/view/selflearning/ManageHomeWork.less
  61. 30 7
      TEAMModelOS/ClientApp/src/view/selflearning/ManageHomeWork.vue
  62. 16 10
      TEAMModelOS/ClientApp/src/view/selflearning/ManageSelfLearn.vue
  63. 10 13
      TEAMModelOS/ClientApp/src/view/smartclassdashboard/Index.vue
  64. 9 9
      TEAMModelOS/ClientApp/src/view/smartschooldashboard/Index.vue
  65. 31 34
      TEAMModelOS/ClientApp/src/view/teachermgmt/Index.less
  66. 33 43
      TEAMModelOS/ClientApp/src/view/teachermgmt/Index.vue
  67. 80 0
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/personnel/Index.less
  68. 92 0
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/personnel/Index.vue
  69. 111 0
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/userList/Index.less
  70. 417 0
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/userList/Index.vue
  71. 0 69
      TEAMModelOS/ClientApp/src/view/teachermgmt/menu/accountmgmt/Index.less
  72. 0 187
      TEAMModelOS/ClientApp/src/view/teachermgmt/menu/accountmgmt/Index.vue
  73. 0 111
      TEAMModelOS/ClientApp/src/view/teachermgmt/menu/authorization/Index.less
  74. 0 454
      TEAMModelOS/ClientApp/src/view/teachermgmt/menu/authorization/Index.vue
  75. 46 33
      TEAMModelOS/Controllers/Learn/HomeWorkController.cs
  76. 165 25
      TEAMModelOS/Controllers/Test/TestAPIController.cs
  77. 18 0
      TEAMModelOS/Models/HomeWorkDto.cs
  78. 1 1
      TEAMModelOS/Properties/launchSettings.json
  79. 15 0
      TEAMModelOS/ServiceProviderFactory.cs
  80. 13 4
      TEAMModelOS/Startup.cs
  81. 2 1
      TEAMModelOS/appsettings.Development.json
  82. 2 1
      TEAMModelOS/appsettings.json

+ 1 - 0
TEAMModelOS.SDK/Context/Configuration/BaseConfigModel.cs

@@ -1,4 +1,5 @@
 using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
 
 namespace TEAMModelOS.SDK.Context.Configuration
 {

+ 1 - 1
TEAMModelOS.SDK/Module/AzureBlob/Implements/AzureBlobDBRepository.cs

@@ -30,7 +30,7 @@ namespace TEAMModelOS.SDK.Module.AzureBlob.Implements
         public AzureBlobDBRepository(IConfiguration configuration, IWebHostEnvironment env, AzureBlobOptions options, AzureBlobOptions azureBlobOptions)
         {
             Configuration = configuration;
-            BaseConfigModel.SetBaseConfig(Configuration, env.ContentRootPath, env.WebRootPath);
+           // BaseConfigModel.SetBaseConfig(Configuration, env.ContentRootPath, env.WebRootPath);
             _options = options;
             if (!string.IsNullOrEmpty(options.ConnectionString))
             {

+ 3 - 6
TEAMModelOS.SDK/Module/AzureCosmosDBV3/AzureCosmosDBV3Repository.cs

@@ -96,7 +96,7 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
         }
 
 
-        public async Task InitializeDatabase()
+        public async Task<Dictionary<string, CosmosModelInfo>> InitializeDatabase()
         {
             try
             {
@@ -187,6 +187,7 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
                     Container leaseContainer = await database.CreateContainerIfNotExistsAsync(leaseProperties, throughput: CollectionThroughput);
                     DocumentCollectionDict.TryAdd(leaseId, new CosmosModelInfo { container = leaseContainer, cache = false, monitor = false });
                 }
+                return DocumentCollectionDict;
             }
             catch (CosmosException e)
             {
@@ -194,11 +195,7 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
             }
         }
 
-        public Dictionary<string, CosmosModelInfo> GetCosmosModelInfo()
-        {
-            return this.DocumentCollectionDict;
-        }
-
+      
 
 
         private string GetPartitionKey<T>()

+ 1 - 2
TEAMModelOS.SDK/Module/AzureCosmosDBV3/IAzureCosmosDBV3Repository.cs

@@ -78,11 +78,10 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
         Task<List<T>> FindByDict<T>(Dictionary<string, object> dict, string partitionKey = null, List<string> propertys = null) where T : ID;
         Task<List<dynamic>> FindByDict(string CollectionName, Dictionary<string, object> dict, string partitionKey = null, List<string> propertys = null);
         Task<List<dynamic>> FindCountByDict(string CollectionName, Dictionary<string, object> dict, string partitionKey = null);
-        Task InitializeDatabase();
+        Task<Dictionary<string,CosmosModelInfo>> InitializeDatabase();
         Task<T>FindById<T>(string id) where T : ID;
         Task<List<T>> FindByIds<T>(List<string> ids) where T : ID;
         Task<dynamic> FindById(string CollectionName, string id);
         Task<List<dynamic>> FindByIds (string CollectionName, List<string> ids);
-        Dictionary<string, CosmosModelInfo> GetCosmosModelInfo();
     }
 }

+ 5 - 0
TEAMModelOS.Service/Models/Learn/HomeWork.cs

@@ -76,6 +76,11 @@ namespace TEAMModelOS.Service.Models.Learn
         public List<ProcessRes> resource { get; set; }
 
 
+        /// <summary>
+        /// 状态 
+        /// </summary>
+        public int state { get; set; }
+
         //public Subdto subdto { get; set; }
 
         /// <summary>

+ 1 - 1
TEAMModelOS.Service/Models/Syllabus/SyllabusVolume.cs

@@ -10,7 +10,7 @@ using ProtoBuf;
 
 namespace TEAMModelOS.Service.Models.Syllabus
 {
-    [CosmosDB(RU = 400, Name = "SyllabusVolume")]
+    [CosmosDB(RU = 400, Name = "SyllabusVolume",Monitor =true)]
     [ProtoContract]
     public class SyllabusVolume :ID
     {

+ 22 - 38
TEAMModelOS.Service/Services/ChangeFeed/ChangeFeedInvoke.cs

@@ -1,7 +1,9 @@
 using DocumentFormat.OpenXml.Drawing;
 using Microsoft.Azure.Cosmos;
+using Microsoft.Extensions.DependencyInjection;
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Reflection;
 using System.Text;
 using System.Text.Json;
@@ -20,8 +22,16 @@ namespace TEAMModelOS.Service.Services.ChangeFeed
             azureCosmosDBV3Repository = _IAzureCosmosDBV3Repository;
         }
 
-        public async  Task MonitorChangeFeed() {
-           Dictionary<string,CosmosModelInfo> dict =  azureCosmosDBV3Repository.GetCosmosModelInfo();
+        public void     MonitorChangeFeed(Dictionary<string , CosmosModelInfo> dict, IServiceCollection _services) {
+            var serviceCollection = new Microsoft.Extensions.DependencyInjection.ServiceCollection();
+            ServiceProvider serviceProvider = _services.BuildServiceProvider();  
+            List<ServiceDescriptor> services = new List<ServiceDescriptor>();
+            Type type = typeof(IChangeFeedService<>);
+            foreach (ServiceDescriptor service in _services) {
+                if (type.Name.Equals(service.ServiceType.Name)) {
+                    services.Add(service);
+                }
+            }
             foreach (string CollectionName in dict.Keys)
             {
                 if (CollectionName.Equals("AleaseContainer")) 
@@ -31,51 +41,25 @@ namespace TEAMModelOS.Service.Services.ChangeFeed
                 if (dict[CollectionName].monitor) {
                     ChangeFeedProcessor changeFeedProcessor = dict[CollectionName]
                         .container
-                        .GetChangeFeedProcessorBuilder<object>(CollectionName, async (changes, token) => await ProcessChanges(changes, CollectionName, dict[CollectionName].type))
+                        .GetChangeFeedProcessorBuilder<object>(CollectionName, async (changes, token) => 
+                        await ProcessChanges(changes,  dict[CollectionName].type , services, serviceProvider))
                         .WithInstanceName(CollectionName)
                         .WithLeaseContainer(dict["AleaseContainer"].container)
                         .Build();
-                     await changeFeedProcessor.StartAsync();
+                       changeFeedProcessor.StartAsync();
                 }
-               
             }
         }
-        /// <summary>
-        /// 获取到监听更改的数据
-        /// </summary>
-        /// <param name="changes"></param>
-        /// <param name="type"></param>
-        /// <param name="CollectionName"></param>
-        /// <returns></returns>
-        private async Task ProcessChanges(IReadOnlyCollection<object> changes,  string CollectionName,Type type)
+        private async Task ProcessChanges(IReadOnlyCollection<object> changes, Type type, 
+            List<ServiceDescriptor> services, ServiceProvider serviceProvider)
         {
-            Assembly assembly = Assembly.GetAssembly(typeof(IChangeFeedService<>));
-            Type[] types = assembly.GetTypes();
-            List<Type> list = new List<Type>();
-            foreach (Type item in types)
-            {
-                if (item.IsInterface) continue;//判断是否是接口
-                Type[] ins = item.GetInterfaces();
-                foreach (Type ty in ins)
-                {
-                    Type t = typeof(IChangeFeedService<>);
-                    t = t.MakeGenericType(type);
-                    if (ty == t)
-                    {
-                        list.Add(item);
-                    }
-                }
-            }
-            foreach (Type item in list) {
-                object obj = Activator.CreateInstance(item);//创建一个obj对象
-                MethodInfo mi = item.GetMethod("Processor");
+            foreach (ServiceDescriptor service in services) {
+                var obj = serviceProvider.GetService(service.ServiceType);
+                MethodInfo mi = service.ServiceType.GetMethod("Processor");
                 Type t = typeof(IReadOnlyCollection<>);
                 t = t.MakeGenericType(type);
-               // object objt = Activator.CreateInstance(t);
-                object bjt= JsonSerializer.Deserialize(changes.ToApiJson(), t);
-                mi.Invoke(obj, new object []{ bjt });//调用方法
-               // mi = item.GetMethod("BaseClass_VoidPublic");
-               // string s = mi.Invoke(obj, null) as string;//调用有返回值的方法,使用 as 关键字 转换返回的类型
+                object bjt = JsonSerializer.Deserialize(changes.ToApiJson(), t);
+                mi.Invoke(obj, new object[] { bjt });//调用方法
             }
         }
     }

+ 4 - 2
TEAMModelOS.Service/Services/ChangeFeed/IChangeFeedInvoke.cs

@@ -1,13 +1,15 @@
-using System;
+using Microsoft.Extensions.DependencyInjection;
+using System;
 using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
 using TEAMModelOS.SDK.Context.Configuration;
+using TEAMModelOS.SDK.Module.AzureCosmosDBV3;
 
 namespace TEAMModelOS.Service.Services.ChangeFeed
 {
    public interface IChangeFeedInvoke :IBusinessService
     {
-          Task MonitorChangeFeed();
+          void MonitorChangeFeed(Dictionary<string, CosmosModelInfo> dict , IServiceCollection _services);
     }
 }

+ 2 - 1
TEAMModelOS.Service/Services/ChangeFeed/IChangeFeedService.cs

@@ -2,11 +2,12 @@
 using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
+using TEAMModelOS.SDK.Context.Configuration;
 
 namespace TEAMModelOS.Service.Services.ChangeFeed
 {
     public interface IChangeFeedService<T>
     {
-        void Processor(IReadOnlyCollection<T> changes);
+        Task Processor(IReadOnlyCollection<T> changes);
     }
 }

+ 10 - 0
TEAMModelOS.Service/Services/ChangeFeed/IChangeService.cs

@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.Service.Services.ChangeFeed
+{
+    public  interface IChangeService
+    {
+    }
+}

+ 8 - 2
TEAMModelOS.Service/Services/ChangeFeed/KnowledgeChangeFeed.cs

@@ -3,14 +3,20 @@ using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
 using TEAMModelOS.SDK.Helper.Common.JsonHelper;
+using TEAMModelOS.SDK.Module.AzureCosmosDBV3;
 using TEAMModelOS.Service.Models.Syllabus;
 
 namespace TEAMModelOS.Service.Services.ChangeFeed
 {
-    public class KnowledgeChangeFeed : IChangeFeedService<Knowledge>
+    public class KnowledgeChangeFeed : IChangeFeedService<Knowledge>, IChangeService
     {
-        public void Processor(IReadOnlyCollection<Knowledge> changes)
+        private IAzureCosmosDBV3Repository cosmosDBV3Repository;
+        public KnowledgeChangeFeed(IAzureCosmosDBV3Repository azureCosmos) {
+            cosmosDBV3Repository = azureCosmos;
+        }
+        public async  Task Processor(IReadOnlyCollection<Knowledge> changes)
         {
+            //List<Knowledge> s = await cosmosDBV3Repository.FindAll<Knowledge>();
             Console.WriteLine(changes.ToApiJson());
         }
     }

+ 23 - 0
TEAMModelOS.Service/Services/ChangeFeed/SyllabusVolumeChangeFeed.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.Helper.Common.JsonHelper;
+using TEAMModelOS.SDK.Module.AzureCosmosDBV3;
+using TEAMModelOS.Service.Models.Syllabus;
+
+namespace TEAMModelOS.Service.Services.ChangeFeed
+{
+    class SyllabusVolumeChangeFeed : IChangeFeedService<SyllabusVolume>, IChangeService
+    {
+        private IAzureCosmosDBV3Repository cosmosDBV3Repository;
+        public SyllabusVolumeChangeFeed(IAzureCosmosDBV3Repository azureCosmos)
+        {
+            cosmosDBV3Repository = azureCosmos;
+        }
+        public async Task Processor(IReadOnlyCollection<SyllabusVolume> changes)
+        {
+            Console.WriteLine(changes.ToApiJson());
+        }
+    }
+}

+ 5 - 9
TEAMModelOS.Service/TEAMModelOS.Model.xml

@@ -314,6 +314,11 @@
             作业附件
             </summary>
         </member>
+        <member name="P:TEAMModelOS.Service.Models.Learn.HomeWork.state">
+            <summary>
+            状态 
+            </summary>
+        </member>
         <member name="P:TEAMModelOS.Service.Models.Learn.HomeWork.other">
             <summary>
             
@@ -1112,15 +1117,6 @@
             1默认为普通页面,2为题目
             </summary>
         </member>
-        <member name="M:TEAMModelOS.Service.Services.ChangeFeed.ChangeFeedInvoke.ProcessChanges(System.Collections.Generic.IReadOnlyCollection{System.Object},System.String,System.Type)">
-            <summary>
-            获取到监听更改的数据
-            </summary>
-            <param name="changes"></param>
-            <param name="type"></param>
-            <param name="CollectionName"></param>
-            <returns></returns>
-        </member>
         <member name="M:TEAMModelOS.Service.Services.Exam.Implements.HtmlAnalyzeService.ConvertTest(System.String)">
             <summary>
             解析题型

+ 1 - 0
TEAMModelOS/ClientApp/package.json

@@ -9,6 +9,7 @@
   },
   "dependencies": {
     "@ckeditor/ckeditor5-build-inline": "^12.3.1",
+    "@lywzx/vue.access.control": "^1.0.10",
     "@vue/eslint-config-standard": "^4.0.0",
     "animate.css": "^3.7.2",
     "axios": "^0.19.0",

+ 58 - 0
TEAMModelOS/ClientApp/src/access/index.js

@@ -0,0 +1,58 @@
+import VueAccessControl, {LoginMiddleware} from '@lywzx/vue.access.control';
+import Vue from 'vue';
+import { User } from '../service/User';
+
+Vue.use(VueAccessControl, {
+    vueRouter: true,
+    loginRoute: { // 登入路由
+        path: '/login'
+      },
+    // globalMiddleWares: ['login'],
+    // foreignKeyName: 'user_id',
+    // notLoginRoleName: 'Guest',
+    permissionDenyRedirectRoute: {  // 權限拒絕重定向路由
+      path: '/404'
+    },
+    defaultRoute: {  // 基本路由
+      path: '/selectModule'
+    },
+});
+
+LoginMiddleware.handleExtend = function(next, ...arg) {
+  let token = localStorage.getItem('token')
+  let toNextPath = arg[1].path
+  let userAccess, userInfo
+
+  if(localStorage.userAccess){
+    userAccess = JSON.parse(decodeURIComponent(localStorage.userAccess,"utf-8"))
+  }
+  if(localStorage.userInfo){
+    userInfo = JSON.parse(decodeURIComponent(localStorage.userInfo,"utf-8"))
+  }
+  
+  if (token && userAccess && userInfo) {
+    if(!userInfo.joinSchool.length && toNextPath !== '/schoolList'){
+      window.location.href = '/schoolList'
+    } else if(toNextPath === '/login' && userAccess.isLogin){
+      window.location.href = '/home'
+    } else {
+      User.freshLogin(token).then(() => {
+        next(true);
+      }).catch(() => {
+        next(false);
+      });        
+    }      
+  } else {
+    next(false);
+  }
+};
+
+const access = new VueAccessControl.Access({
+    routes: []
+    //routes: AsyncTeacherRoute.concat(AsyncStudentRoute),
+});
+  
+
+User.$access = access;
+
+export default access;

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

@@ -1,6 +1,6 @@
 import { fetch, post } from '@/filters/http'
 export default {
   GetTestIoTData: function(item) {
-    return fetch('/api/testAPI/GetTestIoTData/' + item.schoolshortcode)
+    return fetch('/api/testAPI/GetTestIoTData?schoolshortcode=' + item.schoolshortcode)
   }
 }

+ 110 - 102
TEAMModelOS/ClientApp/src/api/index.js

@@ -10,119 +10,127 @@ import knowledge from './knowledge'
 import teachContent from './teachContent'
 import uploadFile from './uploadFile'
 import courseMgmt from './courseMgmt'
+import login from './login'
+import schoolList from './schoolList'
 import newEvaluation from './newEvaluation'
 import learnActivity from './learnActivity'
+import teachMgmt from './teachMgmt'
 export default {
-    learnActivity,
-    ClassMgmt,
-    stuAccount,
-    syllabus,
-    knowledge,
-    schoolSetting,
-    totalAnalysis,
-    talMgmt,
-    teachContent,
-    // cloudApi,
-    uploadFile,
-    courseMgmt,
-    newEvaluation,
-    // 获取登录跳转链接
-    getLoginLink: function(data) {
-        return post('api/login/login', data)
-    },
-    // 验证登录
-    checkLogin: function(data) {
-        return post('api/login/CheckLogin', data)
-    },
-    // 获取登录人员角色列表
-    getLoginRoles: function(data) {
-        return post('api/role/GetLoginRoles', data)
-    },
-    // 查找地区对应学校列表
-    getSchoolList: function(data) {
-        return post('api/School/getSchool', data)
-    },
-    // 根据当前登录用户获取已授权的AI智慧学校
-    getAuthSchool: function(data) {
-        return post('api/School/AuthorizedAISchool', data)
-    },
-    // 获取全部科目
-    FindSubjectsByDict: function(data) {
-        return post('api/subject/FindSubjectsByDict', data)
-    },
-    // 获取当前学校全部科目
-    FindSchoolSubjectsByDict: function(data) {
-        return post('api/subject/FindSchoolSubjectsByDict', data)
-    },
-    // 获取当前学校全部册别
-    FindSchoolVolumesByDict: function(data) {
-        return post('api/volume/FindSchoolVolumesByDict', data)
-    },
-    // 获取当前学校全部学段
-    FindSchoolPeriodsByDict: function(data) {
-        return post('api/period/FindSchoolPeriodsByDict', data)
-    },
-    // 获取当前学校全部年级
-    FindSchoolGradesByDict: function(data) {
-        return post('api/grade/FindSchoolGradesByDict', data)
-    },
-    // 获取当前学校全部学期
-    FindSchoolTermsByDict: function(data) {
-        return post('api/term/FindSchoolTermsByDict', data)
-    },
+  learnActivity,
+  ClassMgmt,
+  stuAccount,
+  syllabus,
+  knowledge,
+  schoolSetting,
+  totalAnalysis,
+  talMgmt,
+  teachContent,
+  // cloudApi,
+  uploadFile,
+  courseMgmt,
+  newEvaluation,
+  login,
+  schoolList,
+  teachMgmt,
+  // 获取登录跳转链接
+  getLoginLink: function (data) {
+    return post('api/login/login', data)
+  },
+  // 验证登录
+  checkLogin: function (data) {
+    return post('api/login/CheckLogin', data)
+  },
+  // 获取登录人员角色列表
+  getLoginRoles: function (data) {
+    return post('api/role/GetLoginRoles', data)
+  },
+  // 查找地区对应学校列表
+  getSchoolList: function (data) {
+    return post('api/School/getSchool', data)
+  },
+  // 根据当前登录用户获取已授权的AI智慧学校
+  getAuthSchool: function (data) {
+    return post('api/School/AuthorizedAISchool', data)
+  },
+  // 获取全部科目
+  FindSubjectsByDict: function (data) {
+    return post('api/subject/FindSubjectsByDict', data)
+  },
+  // 获取当前学校全部科目
+  FindSchoolSubjectsByDict: function (data) {
+    return post('api/subject/FindSchoolSubjectsByDict', data)
+  },
+  // 获取当前学校全部册别
+  FindSchoolVolumesByDict: function (data) {
+    return post('api/volume/FindSchoolVolumesByDict', data)
+  },
+  // 获取当前学校全部学段
+  FindSchoolPeriodsByDict: function (data) {
+    return post('api/period/FindSchoolPeriodsByDict', data)
+  },
+  // 获取当前学校全部年级
+  FindSchoolGradesByDict: function (data) {
+    return post('api/grade/FindSchoolGradesByDict', data)
+  },
+  // 获取当前学校全部学期
+  FindSchoolTermsByDict: function (data) {
+    return post('api/term/FindSchoolTermsByDict', data)
+  },
 
-    // 获取登录人员身份信息
-    getLoginClaim: function(data) {
-        return post('api/role/GetLoginClaim', data)
-    },
 
-    // 新建习题保存到题库
-    SaveItemBank: function(data) {
-        return post('api/evaluation/ItemBank', data)
-    },
+  // 获取登录人员身份信息
+  getLoginClaim: function (data) {
+      return post('api/role/GetLoginClaim', data)
+  },
 
-    // 新建试卷到试卷
-    SaveTestPaper: function(data) {
-        return post('api/Evaluation/testPaper', data)
-    },
+  // 新建习题保存到题
+  SaveItemBank: function (data) {
+      return post('api/evaluation/ItemBank', data)
+  },
 
-    // 新建试卷到试卷库
-    SaveAnalyzeHtml: function(data) {
-        return post('/api/ImportExercise/AnalyzeHtml', data)
-    },
+  // 新建试卷到试卷库
+  SaveTestPaper: function (data) {
+      return post('api/Evaluation/testPaper', data)
+  },
 
-    // 获取所有学校信息
-    GetAllSchool: function(data) {
-        return post('api/school/GetAllSchool', data)
-    },
+  // 新建试卷到试卷库
+  SaveAnalyzeHtml: function (data) {
+      return post('/api/ImportExercise/AnalyzeHtml', data)
+  },
 
-    // 根据条件获取学段
-    FindPeriodsByDict: function(data) {
-        return post('api/period/FindPeriodsByDict', data)
-    },
+  // 获取所有学校信息
+  GetAllSchool: function (data) {
+      return post('api/school/GetAllSchool', data)
+  },
 
-    // 根据条件获取年级
-    FindGradesByDict: function(data) {
-        return post('api/grade/FindGradesByDict', data)
-    },
-    // 根据条件获取学科
-    FindSubjectsByDict: function(data) {
-        return post('api/subject/FindSubjectsByDict', data)
-    },
+  // 根据条件获取学段
+  FindPeriodsByDict: function (data) {
+      return post('api/period/FindPeriodsByDict', data)
+  },
 
-    /*
-     *评测
-     */
-    // 上传图片
-    UploadFile: function(data) {
-        return post('/api/file/uploadFile', data)
-    },
+  // 根据条件获取年级
+  FindGradesByDict: function (data) {
+      return post('api/grade/FindGradesByDict', data)
+  },
+  // 根据条件获取学科
+  FindSubjectsByDict: function (data) {
+      return post('api/subject/FindSubjectsByDict', data)
+  },
 
-    /**
-     * 通用查询接口
-     */
-    FindCollection: function(data) {
-        return post('/api/Common/FindCollection', data)
-    }
 
+  /*
+    *评测
+    */
+  // 上传图片
+  UploadFile: function (data) {
+      return post('/api/file/uploadFile', data)
+  },
+
+  /**
+   * 通用查询接口
+   */
+  FindCollection: function (data) {
+      return post('/api/Common/FindCollection', data)
+  }
+  
 }

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

@@ -97,6 +97,12 @@ export default {
         return post('/api/HomeWork/FindClassroom', data)
     },
     /*
+    * 查询作业下的所有学生数据
+    */
+    FindStudentByHwId: function (data) {
+        return post('/api/HomeWork/FindStudent', data)
+    },
+    /*
     *新增或者编辑自主学子活动
     */
     SaveSelfLearn: function (data) {

+ 6 - 0
TEAMModelOS/ClientApp/src/api/login.js

@@ -0,0 +1,6 @@
+import { fetch, post } from '@/filters/http'
+export default {
+  Verification: function(item) {
+    return post('http://test.com/Mocklogin', {id: item.id, pass: item.pass, identity: item.identity})
+  }
+}

+ 9 - 0
TEAMModelOS/ClientApp/src/api/schoolList.js

@@ -0,0 +1,9 @@
+import { fetch, post } from '@/filters/http'
+export default {
+  Join: function(item) {
+    return post('http://test.com/joinSchool', {id: item.id, schoolCode: item.schoolCode})
+  },
+  List: function() {
+    return fetch('http://test.com/schoolList')
+  },  
+}

+ 6 - 0
TEAMModelOS/ClientApp/src/api/teachMgmt.js

@@ -0,0 +1,6 @@
+import { fetch, post } from '@/filters/http'
+export default {
+GetTeacherList: function(token) {
+    return post('http://test.com/teacherList')
+  }
+}

BIN
TEAMModelOS/ClientApp/src/assets/image/FFFFFFFF.png


BIN
TEAMModelOS/ClientApp/src/assets/image/headerT.png


+ 3 - 52
TEAMModelOS/ClientApp/src/boot-app.js

@@ -24,6 +24,7 @@ import 'element-ui/lib/theme-chalk/tree.css'
 import 'element-ui/lib/theme-chalk/icon.css'
 import animated from 'animate.css'
 import VueLogger from 'vuejs-logger'
+import access from './access/index';
 import _ from 'lodash'
 
 require('video.js/dist/video-js.css')
@@ -57,7 +58,7 @@ Vue.prototype.$post = post
 Vue.prototype.$get = fetch
 
 // 工具类
-Vue.prototype.$Mock = mockTools
+// Vue.prototype.$Mock = mockTools
 Vue.prototype.$jwtDecode = jwtDecode
 Vue.prototype.$JSONPath = JSONPath
 Vue.prototype.$echarts = echarts
@@ -68,62 +69,11 @@ Vue.prototype._ = _
 // Registration of global components
 Vue.component('icon', FontAwesomeIcon)
 
-const _import = require('./router/_import_file.js')// 获取组件的方法
-var getRouter // 用来获取后台拿到的路由
-
-// 動態加路由
-// if (!getRouter) {
-//    if (!getObjArr('router')) {
-//        axios.get('/api/testAPI/GetTestAuth').then(res => {
-//            getRouter = res.data.data;
-//            saveObjArr('router', getRouter) //存储路由到localStorage
-//            getRouter = filterAsyncRouter(getRouter) //过滤路由
-//            // 存入vuex
-//            store.state.authorization.antRouter = getRouter;
-//            router.addRoutes(getRouter) //动态添加路由
-//        });
-//    } else {
-//        getRouter = getObjArr('router')//拿到路由
-//        getRouter = filterAsyncRouter(getRouter) //过滤路由
-//        // 存入vuex
-//        store.state.authorization.antRouter = getRouter;
-//        router.addRoutes(getRouter) //动态添加路由
-//    }
-// }
-
 router.beforeEach((to, from, next) => {
     document.body.scrollTop = 0
     next()
 })
 
-function saveObjArr(name, data) { // 存储数组对象的方法
-    sessionStorage.setItem(name, JSON.stringify(data))
-}
-
-function getObjArr(name) { // 获取数组对象的方法
-    return JSON.parse(window.sessionStorage.getItem(name))
-}
-
-function filterAsyncRouter(routers) {
-    let newRouter = []
-    routers.forEach(function(item) {
-        let page = {
-            name: '',
-            path: '',
-            component: '',
-            meta: {
-                access: []
-            }
-        }
-        page.name = item.component
-        page.path = item.path
-        page.meta.access = item.access
-        page.component = _import(item.component)
-        newRouter.push(page)
-    })
-    return newRouter
-}
-
 router.afterEach((to, from, next) => {
     document.body.scrollTop = 0
 })
@@ -135,6 +85,7 @@ Vue.use(ViewUI, {
 sync(store, router)
 
 const app = new Vue({
+    access,
     store,
     router,
     i18n,

+ 22 - 10
TEAMModelOS/ClientApp/src/common/UploadFile.vue

@@ -1,6 +1,6 @@
-<template>
-    <div>
-        <Upload type="drag" action="" multiple :before-upload="beforeUpload" class="upload-wrap" :format="format" :max-size="maxSize" :on-format-error="onFormatError" :on-exceeded-size="sizeError">
+<template>
+    <div class="upload-file-box">
+        <Upload type="drag" action="" multiple :before-upload="beforeUpload" class="upload-wrap">
             <p style="margin:20px 0px; margin-top:80px;font-size:30px;">{{$t('teachContent.uploadText')}}</p>
             <Icon type="ios-cloud-upload" size="80" style="margin-bottom:80px;" />
         </Upload>
@@ -51,7 +51,7 @@
                 type: Number
             },
             maxSize: {
-                default: 4,
+                default: 2 * 1024 * 1024,
                 type: Number
             },
             format: {
@@ -62,12 +62,6 @@
             }
         },
         methods: {
-            onFormatError() {
-                this.$Message.error("含不支持的文件类型")
-            },
-            sizeError() {
-                this.$Message.error("文件大小超出限制")
-            },
             checkSize() {
 
             },
@@ -236,6 +230,24 @@
             },
             beforeUpload(file) {
                 let url = file.name
+                if (file.size > this.maxSize) {
+                    this.$Message.error({
+                        content: "鏂囦欢澶у皬瓒呭嚭闄愬埗",
+                        duration:3
+                    })
+                    return false
+                }
+
+                let extension = file.name.substring(file.name.lastIndexOf('.') + 1, file.name.length)
+                console.log(extension)
+                if (this.format.length > 0 && this.format.indexOf(extension) == -1) {
+                    this.$Message.error({
+                        content: "文件类型不支持",
+                        duration:3
+                    })
+                    return false
+                }
+                
                 this.$api.uploadFile.getContainerSAS().then(
                     (res) => {
                         if (res.error == null) {

+ 4 - 0
TEAMModelOS/ClientApp/src/components/learnactivity/BaseHwForm.less

@@ -44,6 +44,10 @@
         color: @primary-textColor;
     }
 
+    .ivu-select-multiple .ivu-select-selection{
+        height:auto;
+    }
+
     .ivu-tag {
         border: none;
         background: @primary-color;

+ 19 - 6
TEAMModelOS/ClientApp/src/components/learnactivity/BaseHwForm.vue

@@ -45,6 +45,12 @@
                 </Upload>
             </FormItem>
 
+            <FormItem label="作业记录" prop="isReset" v-show="editable && isEdit">
+                <CheckboxGroup v-model="hwForm.isReset">
+                    <Checkbox label="reset">清空作业提交记录</Checkbox>
+                </CheckboxGroup>
+            </FormItem>
+
             <FormItem label="其他" prop="other">
                 <CheckboxGroup v-model="hwForm.other">
                     <Checkbox label="view">开放观摩</Checkbox>
@@ -52,7 +58,7 @@
                 </CheckboxGroup>
             </FormItem>
 
-            <FormItem v-if="editable">
+            <FormItem v-show="editable">
                 <Button type="primary" class="btn-save" @click="handleSubmit('hwForm')" :loading="isBtnLoading">保存</Button>
                 <Button @click="handleReset('hwForm')" class="btn-reset" style="margin-left: 8px">重置</Button>
             </FormItem>
@@ -94,6 +100,7 @@
                     publishModel:'0',
                     startTime:'',
                     description: '',
+                    isReset:[],
                     other: []
                 },
                 defaultParams: {
@@ -136,6 +143,7 @@
                     if (valid && this.getSimpleText(this.hwForm.description)) {
                         let params = Object.assign({}, this.defaultParams)
                         let target = []
+                        let isReset = this.hwForm.isReset.length > 0
                         params.scopeCode = this.userInfo.TEAMModelId
                         params.name = this.hwForm.name
                         params.publishModel = this.hwForm.publishModel
@@ -156,13 +164,14 @@
                                 scopeCode: this.classRooms.filter(i => i.classroomCode === item)[0].scopeCode
                             })
                         })
-
                         params.target = target
                         this.isBtnLoading = true
-                        this.saveorUpdataHw(params).then(res => {
+                        this.saveorUpdataHw({ homeWork: params, reset: isReset }).then(res => {
                             this.$Message.success(this.isEdit ? '修改成功!' : '添加成功!')
                             this.$emit('onAddSuccess')
                             this.isBtnLoading = false
+                        }).catch(error => {
+                            console.log(error)
                         })
                     } else {
                         this.$Message.error('请将信息填写完整')
@@ -200,6 +209,8 @@
              */
             handleReset(name) {
                 this.$refs[name].resetFields();
+                this.descriptionEditor.txt.clear()
+
             },
 
             /** 附件上传之前钩子 限制附件上传个数 */
@@ -242,7 +253,8 @@
                     startTime: item.publishModel === '0' ? '' : new Date(item.startTime),
                     endTime: new Date(item.endTime),
                     description: item.description,
-                    other:item.other
+                    other: item.other,
+                    isReset:[]
                 }
                 this.descriptionEditor.txt.html(item.description)
             }
@@ -271,9 +283,10 @@
                         this.isEdit = true
                         this.editInfo = newValue
                     } else {
-                        /** 新增重置 */
+                        /** 新增 */
                         this.handleReset('hwForm')
-                        this.descriptionEditor.txt.clear()
+                        this.isEdit = false
+                        this.editInfo = null
                     }
                 },
                 deep: true

+ 22 - 8
TEAMModelOS/ClientApp/src/components/learnactivity/BaseHwTable.vue

@@ -67,20 +67,27 @@
                     },
                     {
                         title: '班级',
-                        key: 'className'
+                        render: (h, params) => {
+                            return h('span',params.row.classroom.name)
+                        },
                     },
                     {
                         title: '学号',
-                        key: 'id'
+                        key: 'studentId'
                     },
                     {
                         title: '是否提交',
-                        key: 'isSubmit',
-                        width:100
+                        width:100,
+                        render: (h, params) => {
+                            return h('span',params.row.submissionBool ? '是' : '否')
+                        },
                     },
                     {
                         title: '提交时间',
-                        key: 'submitTime'
+                        key: 'submitTime',
+                        render: (h, params) => {
+                            return h('span',params.row.submissionBool ? params.row.submissionTime : '-')
+                        },
                     },
                     {
                         title: '分数',
@@ -141,14 +148,24 @@
             }
         },
         methods: {
+
+            /**
+             * 全选操作
+             * @param status
+             */
             handleSelectAll(status) {
                 this.$refs.selection.selectAll(status);
             },
 
+            /**
+             * 选择常用评语
+             * @param e
+             */
             onChooseComment(e) {
                 this.currentComment = e.target.innerText
             },
 
+            /** 设置作业点评分数 */
             onSetScore() {
                 if (!this.currentComment || !this.currentScore) {
                     this.$Message.warning('请填写完整!')
@@ -163,10 +180,7 @@
                 handler(newValue) {
                     /** 编辑回显 */
                     if (newValue) {
-                        console.log(newValue)
                         this.tableData = newValue
-                    } else {
-                        /** 新增重置 */
                     }
                 },
                 deep: true

+ 48 - 0
TEAMModelOS/ClientApp/src/components/public/main/index.less

@@ -48,6 +48,54 @@
   border-radius: 4px;
   overflow: hidden;
   height: 100%;
+  .flexBox{
+    display: flex;
+    .item{
+      display: flex;      
+      align-items: center;
+      &.flex-grow-1{
+        flex-grow: 1;
+      }
+      &.flex-grow-2{
+        flex-grow: 2;
+      }
+      &.right{
+        justify-content: flex-end;
+      }
+      .userControl{
+        padding: 0 15px;
+        .joinedSchool{
+          background-color: #f8f8f9;
+          max-height: 350px;
+          overflow: auto;
+          padding-right: 0;
+          padding-left: 0;
+          .jSchool{
+            padding: 0 16px;
+            &:hover{
+              background-color: rgba(227, 229, 232, 0.5);
+            }
+            .box{
+              display:flex;
+              align-items: center;
+              border-bottom: 1px #c5c8ce solid;
+              width:100%;
+              padding: 4px 0;
+              img{
+                width: 25px;margin-right: 16px;border-radius: 20px;height: 25px;display: block;
+              }
+              .detail{
+                overflow: hidden;
+                white-space: nowrap;
+                text-overflow: ellipsis;
+                max-width: 260px;
+              }
+            }            
+          }
+        }
+      }
+    }
+  }
 }
 .layout-header-bar{
   background: #fff!important;

+ 42 - 23
TEAMModelOS/ClientApp/src/components/public/main/index.vue

@@ -114,28 +114,47 @@
             </Sider>
             <Layout>
                 <Header :style="{padding: 0}" class="layout-header-bar">
-                    <Icon @click.native="collapsedSider" :class="rotateIcon" :style="{margin: '0 20px'}" type="md-menu" size="24"></Icon>
-                    <h2 style="font-size: 1.6em;color:#d0b772;display: inline-block;vertical-align: middle;">醍摩豆智慧雲平台雲平台雲平台</h2>
-                    <Dropdown trigger="click" placement="bottom-end" style="    float: right;padding: 0 10px;vertical-align: middle;">
-                        <a style="display: inline-block;vertical-align: middle;height: 35px;" href="javascript:void(0)">
-                            <img style="width: 35px;cursor: pointer;" src="@/assets/image/touxiang.png">
-                        </a>
-                        <DropdownMenu slot="list">
-                            <DropdownItem disabled style="color: #515a6e;cursor: pointer;text-align: left;">
-                                <img style="width: 35px;display:inline-block;margin-right: 16px;border-radius: 50%;" src="@/assets/image/touxiang.png">
-                                <div style="display:inline-block;text-align:left;">
-                                    <h3>Osbert#1234</h3>
-                                    <h3>Osbert@habook.com.tw</h3>
-                                </div>
-                            </DropdownItem>
-                            <DropdownItem disabled divided style="color: #515a6e;cursor: pointer;text-align: left;">
-                                <Icon size="15" :type="switch1 ? 'ios-moon-outline' : 'ios-sunny'" style="margin-right: 15px;" />深色主題
-                                <i-switch v-model="switch1" @on-change="themeChange" style="margin-left: 10px;float:right;"></i-switch>
-                            </DropdownItem>
-                            <DropdownItem divided style="text-align: left;"><Icon size="15" type="md-settings" style="margin-right: 15px;" />選項</DropdownItem>
-                            <DropdownItem divided style="text-align: left;"><Icon size="15" type="md-log-out" style="margin-right: 15px;" />登出</DropdownItem>
-                        </DropdownMenu>
-                    </Dropdown>
+                    <div class="flexBox">
+                        <div class="item flex-grow-2">
+                            <Icon @click.native="collapsedSider" :class="rotateIcon" :style="{margin: '0 20px'}" type="md-menu" size="24"></Icon>
+                            <h2 style="font-size: 1.6em;color:#d0b772;display: inline-block;vertical-align: middle;">醍摩豆智慧雲平台雲平台雲平台</h2>
+                        </div>
+                        <div class="item flex-grow-1 right">
+                            <div class="userControl">
+                                <Dropdown trigger="click" placement="bottom-end">
+                                    <a style="display: inline-block;vertical-align: middle;height: 35px;" href="javascript:void(0)">
+                                        <img style="width: 35px;cursor: pointer;" src="@/assets/image/touxiang.png">
+                                    </a>
+                                    <DropdownMenu slot="list" style="width: 350px;">
+                                        <DropdownItem disabled style="color: #515a6e;cursor: pointer;display:flex;align-items: center;">
+                                            <img style="width: 50px;margin-right: 16px;border-radius: 50%;" src="@/assets/image/touxiang.png">
+                                            <div style="text-align:left;">
+                                                <h3>Osbert#1234</h3>
+                                                <h3>Osbert@habook.com.tw</h3>
+                                            </div>
+                                        </DropdownItem>
+                                        <DropdownItem class="scrollstyle joinedSchool">
+                                            <div class="jSchool" v-for="(item, key) in userInfo.joinSchool" :key="key">
+                                                <div class="box">
+                                                    <img :src="item.avatar">
+                                                    <div class="detail">
+                                                        <h4>{{item.name}}</h4>
+                                                        <small>{{item.shortCode}}</small>
+                                                    </div>
+                                                </div>                                                
+                                            </div>                                                
+                                        </DropdownItem>
+                                        <DropdownItem disabled divided style="color: #515a6e;cursor: pointer;text-align: left;margin-top: 0;">
+                                            <Icon size="15" :type="switch1 ? 'ios-moon-outline' : 'ios-sunny'" style="margin-right: 15px;" />深色主題
+                                            <i-switch v-model="switch1" @on-change="themeChange" style="margin-left: 10px;float:right;"></i-switch>
+                                        </DropdownItem>
+                                        <DropdownItem divided style="text-align: left;"><Icon size="15" type="md-settings" style="margin-right: 15px;" />選項</DropdownItem>
+                                        <DropdownItem divided style="text-align: left;"><Icon size="15" type="md-log-out" style="margin-right: 15px;" />登出</DropdownItem>
+                                    </DropdownMenu>
+                                </Dropdown>
+                            </div>                            
+                        </div>
+                    </div>                                        
                 </Header>
                 <Content :style="{background: '#fff', minHeight: '260px'}">
                     <router-view/>
@@ -156,6 +175,7 @@ export default {
         }
     },
     computed: {
+        userInfo() { return this.$access.getExtendInfo('userInfo');},
         rotateIcon() {
             return [
                 'menu-icon',
@@ -170,7 +190,6 @@ export default {
         }
     },
     created() {
-
     },
     methods: {
         themeChange(status) {

+ 4 - 0
TEAMModelOS/ClientApp/src/icons.js

@@ -7,6 +7,10 @@ library.add(
   require('@fortawesome/free-solid-svg-icons').faHome,
   require('@fortawesome/free-solid-svg-icons').faList,
   require('@fortawesome/free-solid-svg-icons').faSpinner,
+  require('@fortawesome/free-solid-svg-icons').faShieldAlt,
+  require('@fortawesome/free-solid-svg-icons').faTrash,
+  require('@fortawesome/free-solid-svg-icons').faFileAlt,
+  require('@fortawesome/free-solid-svg-icons').faBell,
   // Brands
   require('@fortawesome/free-brands-svg-icons').faFontAwesome,
   require('@fortawesome/free-brands-svg-icons').faMicrosoft,

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

@@ -0,0 +1,8 @@
+export default {
+    required : 'Required',
+    format:{
+        default: 'wrong format',
+        email: 'Wrong Email format',
+    },
+    alphanumeric: 'Only enter English & numbers'
+}

+ 9 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/index.js

@@ -9,6 +9,11 @@ import schoolBaseInfo from './schoolBaseInfo'
 import totalAnalysis from './totalAnalysis'
 import courseManage from './courseManage'
 import teachContent from './teachContent'
+import login from './login'
+import error from './error'
+import schoolList from './schoolList'
+import teachermgmt from './teachermgmt'
+
 export default {
   schoolBaseInfo,
   schoolMgmt,
@@ -21,6 +26,10 @@ export default {
   courseManage,
   common,
   teachContent,
+  login,
+  error,
+  schoolList,
+  teachermgmt,
   test: 'test',
   formConfigP: {
     input: 'Please Enter ',

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

@@ -0,0 +1,10 @@
+export default {
+    teacher: 'Teacher',
+    student: 'Student',
+    forgetId: 'Forgot ID/password?',
+    login: 'Sign in',
+    relatedLink: 'Related Link',
+    link1: 'AClassONE Web',
+    id: 'TEAMModelID/Cellphone/Email',
+    pass: 'password'
+}

+ 21 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolList.js

@@ -0,0 +1,21 @@
+export default {
+    title1: 'Apply to join school',
+    placeholder:{
+        search: 'Please enter the school short code, school code or school name to search ...',
+        area: 'Area',
+        province: 'Province',
+        city: 'City'
+    },
+    btn:{
+        apply: 'Application',
+        pending: 'Pending',
+        logout: 'Sign out'
+    },
+    columns:{
+        name: 'School Name',
+        area: 'Area',
+        PRVN: 'PRVN',
+        shortCode: 'Short code',
+        code: 'Code'
+    }
+}

+ 42 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/teachermgmt.js

@@ -0,0 +1,42 @@
+export default {
+    page:{
+        text1: '教師帳號管理',
+        text2: '添加教師帳號'
+    },
+    blurryFilter: '請輸入關鍵字或帳號資訊...',
+    mulitSet: '權限管理',
+    table:{
+        text1: '上線',
+        text2: '次',
+        th1: '帳號資訊',
+        th2: '用戶名稱',
+        th3: '職稱',
+        th4: '手機資訊',
+        th5: '信箱資訊',
+        th6: '登入與在線狀況',
+    },
+    authSet:{
+        title:'權限設定',
+        subTitle: '變更帳號',
+        area1:{
+            title:'區、班、校管理頁面',
+            read: '允許檢視區、班、校管理頁面',
+            auth1: '允許編輯學制內容,包括年級、學期科目資訊'
+        },
+        reset: '重置',
+        save: '保存'
+    },
+    model:{
+        delTeacher:{
+            title: '刪除老師',
+            text1: '請問您確定要刪除',
+        },
+        warning:{
+            title: '提醒',
+            text1: '請先勾選左側的老師'
+        }
+    },
+    message:{
+        info1:'刪除成功'
+    }
+}

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

@@ -0,0 +1,8 @@
+export default {
+    required : '不能为空',
+    format:{
+        default: '格式错误',
+        email: 'Email格式错误',
+    },
+    alphanumeric: '只能输入英数字'
+}

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

@@ -9,6 +9,11 @@ import schoolBaseInfo from './schoolBaseInfo'
 import totalAnalysis from './totalAnalysis'
 import courseManage from './courseManage'
 import teachContent from './teachContent'
+import login from './login'
+import error from './error'
+import schoolList from './schoolList'
+import teachermgmt from './teachermgmt'
+
 export default {
   schoolBaseInfo,
   classMgmt,
@@ -21,6 +26,10 @@ export default {
   unit,
   common,
   teachContent,
+  login,
+  error,
+  schoolList,
+  teachermgmt,
   test: '测试',
   formConfigP: {
     input: '请输入',

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

@@ -0,0 +1,10 @@
+export default {
+    teacher: '老师',
+    student: '学生',
+    forgetId: '忘记帐号/密码?',
+    login: '登入',
+    relatedLink: '相关连结',
+    link1: 'AClassONE智慧学伴网页版',
+    id: '醍摩豆ID/手机/Email',
+    pass: '密码'
+}

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

@@ -0,0 +1,21 @@
+export default {
+    title1: '申请加入学校',
+    placeholder:{
+        search: '请输入学校简码、学校代码或校名称进行检索...',
+        area: '地区别',
+        province: '省分',
+        city: '县市'
+    },
+    btn:{
+        apply: '申请加入',
+        pending: '待审核',
+        logout: '登出'
+    },
+    columns:{
+        name: '学校名称',
+        area: '地区别',
+        PRVN: '省县市',
+        shortCode: '简码',
+        code: '代码'
+    }
+}

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

@@ -0,0 +1,42 @@
+export default {
+    page:{
+        text1: '教師帳號管理',
+        text2: '添加教師帳號'
+    },
+    blurryFilter: '請輸入關鍵字或帳號資訊...',
+    mulitSet: '權限管理',
+    table:{
+        text1: '上線',
+        text2: '次',
+        th1: '帳號資訊',
+        th2: '用戶名稱',
+        th3: '職稱',
+        th4: '手機資訊',
+        th5: '信箱資訊',
+        th6: '登入與在線狀況',
+    },
+    authSet:{
+        title:'權限設定',
+        subTitle: '變更帳號',
+        area1:{
+            title:'區、班、校管理頁面',
+            read: '允許檢視區、班、校管理頁面',
+            auth1: '允許編輯學制內容,包括年級、學期科目資訊'
+        },
+        reset: '重置',
+        save: '保存'
+    },
+    model:{
+        delTeacher:{
+            title: '刪除老師',
+            text1: '請問您確定要刪除',
+        },
+        warning:{
+            title: '提醒',
+            text1: '請先勾選左側的老師'
+        }
+    },
+    message:{
+        info1:'刪除成功'
+    }
+}

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

@@ -0,0 +1,8 @@
+export default {
+    required : '不能為空',
+    format:{
+        default: '格式錯誤',
+        email: 'Email格式錯誤',
+    },
+    alphanumeric: '只能輸入英數字'
+}

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

@@ -9,6 +9,11 @@ import schoolBaseInfo from './schoolBaseInfo'
 import totalAnalysis from './totalAnalysis'
 import courseManage from './courseManage'
 import teachContent from './teachContent'
+import login from './login'
+import error from './error'
+import schoolList from './schoolList'
+import teachermgmt from './teachermgmt'
+
 export default {
   schoolBaseInfo,
   schoolMgmt,
@@ -21,6 +26,10 @@ export default {
   unit,
   common,
   teachContent,
+  login,
+  error,
+  schoolList,
+  teachermgmt,
   test: '測試',
   formConfigP: {
     input: '請輸入',

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

@@ -0,0 +1,10 @@
+export default {
+    teacher: '老師',
+    student: '學生',
+    forgetId: '忘記帳號/密碼?',
+    login: '登入',
+    relatedLink: '相關連結',
+    link1: 'AClassONE智慧學伴網頁版',
+    id: '醍摩豆ID/手機/Email',
+    pass: '密碼'
+}

+ 21 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/schoolList.js

@@ -0,0 +1,21 @@
+export default {
+    title1: '申請加入學校',
+    placeholder:{
+        search: '請輸入學校簡碼、學校代碼或校名稱進行檢索...',
+        area: '地區別',
+        province: '省分',
+        city: '縣市'
+    },
+    btn:{
+        apply: '申請加入',
+        pending: '待審核',
+        logout: '登出'
+    },
+    columns:{
+        name: '學校名稱',
+        area: '地區別',
+        PRVN: '省縣市',
+        shortCode: '簡碼',
+        code: '代碼'
+    }
+}

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

@@ -0,0 +1,42 @@
+export default {
+    page:{
+        text1: '教師帳號管理',
+        text2: '添加教師帳號'
+    },
+    blurryFilter: '請輸入關鍵字或帳號資訊...',
+    mulitSet: '權限管理',
+    table:{
+        text1: '上線',
+        text2: '次',
+        th1: '帳號資訊',
+        th2: '用戶名稱',
+        th3: '職稱',
+        th4: '手機資訊',
+        th5: '信箱資訊',
+        th6: '登入與在線狀況',
+    },
+    authSet:{
+        title:'權限設定',
+        subTitle: '變更帳號',
+        area1:{
+            title:'區、班、校管理頁面',
+            read: '允許檢視區、班、校管理頁面',
+            auth1: '允許編輯學制內容,包括年級、學期科目資訊'
+        },
+        reset: '重置',
+        save: '保存'
+    },
+    model:{
+        delTeacher:{
+            title: '刪除老師',
+            text1: '請問您確定要刪除',
+        },
+        warning:{
+            title: '提醒',
+            text1: '請先勾選左側的老師'
+        }
+    },
+    message:{
+        info1:'刪除成功'
+    }
+}

+ 85 - 0
TEAMModelOS/ClientApp/src/mock/index.js

@@ -83,3 +83,88 @@ export default {
     }]
     })
 }
+
+/*
+* id: 登入ID
+* pass: 密碼
+* identity: T OR S // 身分
+* 如果 joinSchool 學校,預設給第一個 學校簡碼的權限
+*/
+Mock.mock('http://test.com/Mocklogin', 'post',{
+  "data": {
+    'id':  /[a-z]{2}[A-Z]{2}[0-9]/,
+    'TEAMModelId': function(){ // 隨機ID
+        return this.id + '#' + (10000 - Math.ceil(Math.random() * (Math.random() * 10000)))
+    },
+    'name': '@cname',  // 中文名称
+    'emal': /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/,
+    'joinSchool|10':  // 已加入的學校List P.S. 先預設一個
+      [
+        {
+          'avatar': '@dataImage("100x100")',
+          'name': '@ctitle(10,20)',
+          'shortCode': '@word(5, 10)',
+          'code': /\d{10,10}/
+        }        
+      ],
+    'applicationSchool':  // 申請中的學校List
+      [
+        
+      ],
+    'roles': ['admin', 'student,'], // 角色
+    'permissions': ['TRM_Read'],  // 權限
+    'identity': 'T', // T: 老師, S: 學生
+    'studentURL': function(){ // 連到Aclassone
+      if(this.identity == 'S'){ 
+        return 'http://ies.habook.com.tw/cms/aclass_one/home/index'
+      } 
+    }
+  }
+})
+
+/*
+* id
+* schoolcode
+*/
+Mock.mock('http://test.com/joinSchool', 'post', function(option){
+  let params = JSON.parse(option.body).params  
+  let userInfo = JSON.parse(decodeURIComponent(localStorage.userInfo,"utf-8"));
+  userInfo.applicationSchool.push(params.schoolCode)
+  return {
+    data: {
+      states: 0,
+      userInfo: userInfo
+    }
+  }
+})
+
+Mock.mock('http://test.com/schoolList', 'get',{
+  "data|50": [{
+    'avatar': '@dataImage("100x100")',
+    'name': '@ctitle(10,20)',
+    'area|1': ['大陸', '國際'],
+    'PRVN|1': ['新疆 / 伊犁', '臺灣 / 台北', '北京 / 北京'],
+    'shortCode': '@word(5, 10)',
+    'code': /\d{10,10}/
+  }]
+})
+
+/*
+* token
+* id
+*/
+Mock.mock('http://test.com/teacherList', 'post',{
+  "data|50": [{
+    'id':  /[a-z]{2}[A-Z]{2}[0-9]/,
+    'TEAMModelId': function(){ // 隨機ID
+        return this.id + '#' + (10000 - Math.ceil(Math.random() * (Math.random() * 10000)))
+    },
+    'name': '@ctitle(10,20)',
+    'jobTitle|1': ['工程師', '資訊組長', '身教組長', '教務主任', '活動統籌', '註冊組長', '教務組長', '體育組長'],
+    'roles|1': ['teacher', 'admin'], // 角色
+    'permissions|1-3': ['teacherMgmt_read', 'teacherMgmt_crt','teacher1','teacher2','teacher3','teacher4','teacher5','teacher6','teacher7'],  // 權限
+    'cellphone|1': ['','0911234567', '123234234234', '23423423','0982348833'],
+    'email|1': ['', '123@gmai.com', 'mmm@outlook.com', '3434@baidu.com', '234234@habook.com.tw'],
+    'loginCount|1-999': 999 
+  }]
+})

+ 0 - 1
TEAMModelOS/ClientApp/src/router/_import_file.js

@@ -1 +0,0 @@
-module.exports = file => require('@/view/' + file + '/Index.vue').default // vue-loader at least v13.0.0+

+ 8 - 4
TEAMModelOS/ClientApp/src/router/index.js

@@ -1,6 +1,7 @@
 import Vue from 'vue'
 import VueRouter from 'vue-router'
 import { routes } from './routes'
+import { afterEach, beforeEach } from '@lywzx/vue.access.control';
 
 Vue.use(VueRouter)
 let router = new VueRouter(
@@ -18,9 +19,12 @@ let router = new VueRouter(
 )
 
 // 解决NavigationDuplicated 报错
-  const originalPush = VueRouter.prototype.push
-  VueRouter.prototype.push = function push(location) {
-    return originalPush.call(this, location).catch(err => err)
-  }
+const originalPush = VueRouter.prototype.push
+VueRouter.prototype.push = function push(location) {
+  return originalPush.call(this, location).catch(err => err)
+}
+
+router.beforeEach(beforeEach.bind(router));
+router.afterEach(afterEach.bind(router));
 
 export default router

+ 38 - 11
TEAMModelOS/ClientApp/src/router/routes.js

@@ -1,26 +1,53 @@
-import Login from '@/view/login/Index.vue'
-import ServerSideLogin from '@/view/serverside/login'
-import Main from '@/components/public/main'
+import ServerSideLogin from '@/view/serverside/login.vue'
+import Main from '@/components/public/main/index.vue'
+import Home from '@/view/Home.vue'
 // import HTTP404 from '@/view/404'
 // import { resolve } from 'url'
 
 export const routes = [
     { path: '*', redirect: '/404' },
-    { name: '404', path: '/404', component: resolve => require(['@/view/404'], resolve) },
-    { name: 'index', path: '', redirect: '/home' },
-    { name: 'selectModule', path: '/selectModule', redirect: '/home' },
-    { name: 'login', path: '/login', component: Login },
+    { name: '404', path: '/404', component: resolve => require(['@/view/404.vue'], resolve) },
+    { name: 'index', path: '', redirect: '/home' },  
+    { name: 'selectModule',path: '/selectModule',redirect: '/home' },
+    {
+        name: 'login',
+        path: '/login',
+        meta: {
+        middleware: ['login?']
+        },
+        component: resolve => require(['@/view/login/Index.vue'], resolve),
+    },
+    {
+        path: '/schoolList',
+        component: Main,
+        children:[
+        {
+            name: 'schoolList',
+            path: '/',
+            meta: {      
+            middleware: ['login', 'role:teacher|admin']
+            },
+            component: resolve => require(['@/view/schoolList/Index.vue'], resolve),
+        }
+        ]    
+    },
     { name: 'ServerSideLogin', path: '/serverside/login', component: ServerSideLogin },
     { name: 'smartschooldashboard', path: '/smartschooldashboard', component: resolve => require(['@/view/smartschooldashboard/Index.vue'], resolve) },
     { name: 'smartclassdashboard', path: '/smartclassdashboard', component: resolve => require(['@/view/smartclassdashboard/Index.vue'], resolve) },
     { name: 'embedschooldashboard', path: '/embedclassdashboard/:schoolshortcode', component: resolve => require(['@/view/smartclassdashboard/Index.vue'], resolve) }, // IES 呼叫專用
     { // 共用組件試用
         path: '/teachermgmt',
-        component: Main,
+        component: Home,
         children: [
-            {
-                path: '/',
-                component: () => import('@/view/teachermgmt/Index.vue')
+            {          
+            path: '/',
+            name: 'teachermgmt',
+            meta: {
+                // middleware: ['login']
+                // middleware: ['login', 'can:admin|superadmin.*|TRM_read']
+                middleware: ['login', 'can:admin.*|TRM_read']
+            },
+            component: () => import('@/view/teachermgmt/Index.vue')
             }
         ]
     },

+ 82 - 0
TEAMModelOS/ClientApp/src/service/User.js

@@ -0,0 +1,82 @@
+export class User {
+
+    static model = {
+        login: null,
+        logout: null,
+        userInfo: null
+    }
+
+    /**
+     * @type Access
+     */
+    static $access;
+
+    static async login(userInfo) {
+      let userAccess = {
+          userId: userInfo.TEAMModelId,
+          roles: userInfo.roles,
+          permissions: userInfo.permissions,
+          isLogin: true
+      }      
+      localStorage.setItem('token', Date.now()); // 暫時給一個TOken 判斷用
+      localStorage.setItem('userAccess', encodeURIComponent(JSON.stringify(userAccess), 'utf-8')); // 權限
+      localStorage.setItem('userInfo', encodeURIComponent(JSON.stringify(userInfo), 'utf-8')); // 基本信息
+
+      return new Promise(function(resolve, reject) {
+          User.$access.reset();
+          // 配置登录用户的角色用对应的权限信息
+          User.$access.setLoginUserInfo(userAccess);
+          // 配置角色基本信息
+          User.$access.setExtendInfo({
+              'userAccess': userAccess,
+              'userInfo' : userInfo
+            });
+          resolve(true);
+      });
+    }
+    
+    // 刷新登录信息,这个方法可以获取至当前登录用户的角色及权限等信息
+    static freshLogin(token) {        
+      return new Promise(function(resolve, reject) {
+          // 把信息放到access当中,类似vuex状态管理,在组件中,可以通过`computed`再获取到信息 
+            // computed: {
+            //    user() { return this.$access.getExtendInfo('userInfo');}
+            // }
+            //
+          let userAccess = JSON.parse(decodeURIComponent(localStorage.userAccess,"utf-8"));
+          let userInfo = JSON.parse(decodeURIComponent(localStorage.userInfo,"utf-8"));
+
+          setTimeout(() => {
+            User.$access.reset();
+            // 配置角色基本信息
+            User.$access.setExtendInfo({
+              'userAccess': userAccess,
+              'userInfo' : userInfo
+            });
+            // 配置登录用户的角色用对应的权限信息
+            User.$access.setLoginUserInfo(userAccess);
+            resolve();
+        }, 100);
+      });
+    }
+    
+    // 用户退出登录
+    static logout() {
+      return new Promise(function(resolve) {
+        setTimeout(() => {
+          localStorage.removeItem('token');
+          localStorage.removeItem('userAccess');
+          localStorage.removeItem('userInfo');          
+          // 重置登录状态
+          User.$access.reset();
+          // 清空登录信息
+          User.$access.setExtendInfo({
+            'userAccess': {},
+            'userInfo' : {}
+          });          
+          window.location.href = '/'
+          resolve(true);
+        }, 1000);
+      });
+    }
+}

+ 40 - 0
TEAMModelOS/ClientApp/src/utils/formRule.js

@@ -0,0 +1,40 @@
+export class formRule {
+    static validatePass = (rule, value, callback) => {
+        if (value === '') {
+            callback(new Error(this.$t('error_1')));
+        } else if (value.search(/^\+/) == 0) {
+            callback(new Error(this.$t('error_26')));
+        } else {
+            // if(this.clientType != 'student' && value.indexOf('@') >=0){ //是否為Email
+            //     var emailRule = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/;
+            //     if(value.search(emailRule)!= -1){
+            //         callback();
+            //     } else {
+            //         callback(new Error(this.$t('error_4')));
+            //     }
+            // } else {
+            callback();
+            // }
+            //都不是就是HabookID
+        }
+    };
+    static validatePasswordCheck = (rule, value, callback) => {
+        if (value === '') {
+            callback(new Error(this.$t('error_1')));
+        }
+        else if (!(/^[A-Za-z0-9]+$/.test(value))) {
+            callback(new Error(this.$t('error_5')));
+        }
+        else {
+            callback();
+        }
+    };
+    static validateStationCheck = (rule, value, callback) => {
+        if (value === '') {
+            callback(new Error(this.$t('error_1')));
+        }
+        else {
+            callback();
+        }
+    };
+}

+ 1 - 9
TEAMModelOS/ClientApp/src/view/404.vue

@@ -1,17 +1,9 @@
 <template>
     <div class="none-container">
-        <img src="../assets/image/404.png" width="40%"/>
+        <img  src="../assets/image/404.png" width="40%"/>        
     </div>
 </template>
 
-<script>
-export default {
-  data() {
-    return {}
-  }
-}
-</script>
-
 <style>
   .none-container {
     width:100%;

+ 30 - 2
TEAMModelOS/ClientApp/src/view/login/Index.less

@@ -8,8 +8,36 @@
         -webkit-justify-content: center;
                 justify-content: center;
         .center-box{
-            width: 64%;
-            height: 53%;
+            width: 550px;
+            text-align: center;            
+            .loginBox{
+                background-color: #425953a1;
+                margin-top: 20px;
+                padding: 15px;
+                border: 2px solid #fff;
+                border-radius: 20px;
+                .demo{
+                    margin: 30px 0;
+                    width: 500px;
+                    margin: auto;
+                    &-carousel{
+                        text-align: center;
+                        color: #fff;
+                        padding: 10px;
+                        img{
+                            width: 100px;
+                            display: block;
+                            margin: auto;
+                        }
+                        span{
+                            display: block;
+                            width: 150px;
+                            margin: auto;
+                            font-size: 2em;
+                        }
+                    }
+                }
+            }   
         } 
     }
     &-footer{

+ 122 - 54
TEAMModelOS/ClientApp/src/view/login/Index.vue

@@ -6,79 +6,147 @@
   <div id="login" class="login backdrop-light">
     <div class="login-body">
       <div class="center-box">
-        <img style="width:33%;" src="@/assets/mark.svg"/>
-        <h2 style="color:#c5b381e0;">歡迎來到醍摩豆雲平台 ! 請選擇您的身分進行登入 !</h2>
-        <Row style="margin-top: 50px;">
-          <Col :span="12" style="border-right: 1px solid #fff;">
-            <div style="width: 450px;margin: auto;">
-              <div style="padding: 5px 0;" >
-                <h1 style="color: #fefefe;font-weight: 100;display: inline-block;vertical-align: middle;">教師身分登入 | </h1>
-                <div style="display: inline-block;vertical-align: middle;">
-                  <a style="margin: 0 10px;"><img style="width: 30px;" src="@/assets/image/touxiang.png"></a>
-                  <a style="margin: 0 10px;"><img style="width: 30px;" src="@/assets/image/touxiang.png"></a>
-                  <a style="margin: 0 10px;"><img style="width: 30px;" src="@/assets/image/touxiang.png"></a>
+        <img style="width:400px" src="@/assets/mark.svg"/>
+        <!-- <h2 style="color:#c5b381e0;">歡迎來到醍摩豆雲平台 ! 請選擇您的身分進行登入 !</h2> -->
+        <div class="loginBox">
+          <Carousel class="demo" v-model="identity" arrow="always" dots="none">
+            <CarouselItem >
+                <div class="demo-carousel">
+                  <img src="@/assets/image/headerT.png">
+                  <span>{{ $t('login.teacher') }}</span>
                 </div>
-              </div>
-              <div style="padding: 5px 0;" >
-                <Input v-model="value" placeholder="醍摩豆帳號" />
-              </div>
-              <div style="padding: 5px 0;" >
-                <Input v-model="value" placeholder="密碼"/>
-              </div>
-              <div style="padding: 1px 0;" >
-                <Checkbox v-model="single" style="color: #fefefe;">記住我的登入資訊</Checkbox><a>  | 忘記帳號/密碼?</a>
-              </div>
-              <div style="padding: 5px 0;text-align: right;" >
-                <Button style="width: 150px;background-color: #082835;color:#fefefe;">登入</Button>
-              </div>
-            </div>
-          </Col>
-          <Col :span="12">
-            <div style="width: 450px;margin: auto;">
-              <div style="padding: 5px 0;" >
-                <h1 style="color: #fefefe;font-weight: 100;display: inline-block;vertical-align: middle;">學生身分登入 | </h1>
-                <div style="display: inline-block;vertical-align: middle;">
-                  <a style="margin: 0 10px;"><img style="width: 30px;" src="@/assets/image/touxiang.png"></a>
-                  <a style="margin: 0 10px;"><img style="width: 30px;" src="@/assets/image/touxiang.png"></a>
-                  <a style="margin: 0 10px;"><img style="width: 30px;" src="@/assets/image/touxiang.png"></a>
+            </CarouselItem>
+            <CarouselItem>
+                <div class="demo-carousel">
+                  <img src="@/assets/image/FFFFFFFF.png">
+                  <span>{{ $t('login.student') }}</span>
                 </div>
-              </div>
-              <div style="padding: 5px 0;" >
-                <Input v-model="value" placeholder="醍摩豆帳號" />
-              </div>
-              <div style="padding: 5px 0;" >
-                <Input v-model="value" placeholder="密碼"/>
-              </div>
-              <div style="padding: 1px 0;" >
-                <Checkbox v-model="single" style="color: #fefefe;">記住我的登入資訊</Checkbox><a>  | 忘記帳號/密碼?</a>
-              </div>
-              <div style="padding: 5px 0;text-align: right;" >
-                <Button style="width: 150px;background-color: #082835;color:#fefefe;">登入</Button>
-              </div>
-            </div>
-          </Col>
-        </Row>
+            </CarouselItem>
+          </Carousel>
+            <Form ref="loginForm" :model="loginForm" :rules="loginRule" style="width: 450px;margin: auto;" @keydown.enter.native="loginSubmit('loginForm')">
+              <FormItem class="ItemPadding" prop="id" >
+                <Input v-model="loginForm.id" :placeholder="$t('login.id')"></Input>
+              </FormItem>
+              <FormItem class="ItemPadding" style="margin-bottom: 5px;" prop="pass">
+                <Input password type="password" v-model="loginForm.pass" :placeholder="$t('login.pass')" /></Input>
+              </FormItem>
+              <div style="text-align: right;"><a>{{ $t('login.forgetId') }}</a></div>
+              <!-- <FormItem class="ItemPadding" prop="single" style="text-align: right;">
+                <Checkbox v-model="loginForm.single" style="color: #fefefe;">記住我的登入資訊</Checkbox><a>  | 忘記帳號/密碼?</a>
+              </FormItem> -->
+              <FormItem class="ItemPadding" style="margin-top: 50px;">
+                <Button long style="background-color: #082835;color:#fefefe;" @click="loginSubmit('loginForm')">{{ $t('login.login') }}</Button>
+              </FormItem>
+            </Form>
+        </div>
       </div>
     </div>
     <div class="login-footer">
       <h2 class="footer-title">
-        相關連結
+        {{ $t('login.relatedLink') }}
       </h2>
-      <a class="link">AClassONE智慧學伴網頁版</a><span class="demarcation">&nbsp;&nbsp;|&nbsp;&nbsp;</span><a class="link">AClassONE智慧學伴網頁版</a><span class="demarcation">&nbsp;&nbsp;|&nbsp;&nbsp;</span><a class="link">AClassONE智慧學伴網頁版</a>
+      <a class="link">{{ $t('login.link1') }}</a><span class="demarcation">&nbsp;&nbsp;|&nbsp;&nbsp;</span><a class="link">{{ $t('login.link1') }}</a><span class="demarcation">&nbsp;&nbsp;|&nbsp;&nbsp;</span><a class="link">{{ $t('login.link1') }}</a>
       <h5 style="position: absolute;bottom:0;width: 100%;padding: 7px;color: #515a6e;">&copy; HABOOL Group 2019</h5>
     </div>
   </div>
 </template>
 
 <script>
+import { User } from '@/service/User'
+
 export default {
   data() {
+    const validatePass = (rule, value, callback) => {
+      if (value === '') {
+          callback(new Error(this.$t('error.required')));
+      } else if (value.search(/^\+/) == 0) {
+          callback(new Error(this.$t('error.format.default')));
+      } else {
+        if(value.indexOf('@') >=0){ //是否為Email
+            var emailRule = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/;
+            if(value.search(emailRule)!= -1){
+                callback();
+            } else {
+                callback(new Error(this.$t('error.format.email')));
+            }
+        } else {
+          callback();
+        }
+        //都不是就是HabookID
+      }
+    };
+    const validatePasswordCheck = (rule, value, callback) => {
+        if (value === '') {
+            callback(new Error(this.$t('error.required')));
+        }
+        else if (!(/^[A-Za-z0-9]+$/.test(value))) {
+            callback(new Error(this.$t('error.alphanumeric')));
+        }
+        else {
+            callback();
+        }
+    };    
     return {
-
+      identity: 0,
+      single: '',
+      loginForm: {
+          id: '',
+          pass: '',
+      },
+      loginRule: {
+          id: [
+              { validator: validatePass, trigger: 'blur' },
+          ],
+          pass: [
+              { validator: validatePasswordCheck, trigger: 'blur' },
+          ]
+      }
+    }
+  },
+  computed: {
+    userAccess() { return this.$access.getExtendInfo('userAccess');},
+    userInfo() { return this.$access.getExtendInfo('userInfo');},
+    converIdentity(){
+      switch (this.identity) {
+        case 0:
+          return 'T'
+          break;    
+        case 1:
+          return 'S'
+          break;   
+      }
     }
+  },
+  created() {
+    
   },
   methods: {
-
+    loginSubmit: function(name){
+      this.$refs[name].validate((valid) => {
+        if (valid) {
+          this.$api.login.Verification({id: this.loginForm.id, pass: this.loginForm.pass, identity: this.converIdentity}).then(res => {
+            let result = res.data
+            switch (result.identity) {
+              // 學生
+              case 'S':
+                window.location.href = result.studentURL ; // 連到指定的網站
+              break;        
+              // 老師
+              default:
+                User.login(result).then(res => {
+                  if(result.joinSchool.length){
+                    this.$router.push({ path: '/home' })                  
+                  } else {
+                    // 跳至選擇學校頁面
+                    this.$router.push({ path: '/schoolList' })
+                  }                    
+                })
+              break;
+            }    
+          })
+        }
+      })
+    }
   }
 }
 </script>

+ 32 - 0
TEAMModelOS/ClientApp/src/view/schoolList/Index.less

@@ -0,0 +1,32 @@
+#schoolList{
+    width: 100%;
+    max-width: 1300px;
+    margin: 20px auto 0 auto;
+    padding-bottom: 30px;
+    background-color:  #1A1A1A;
+    border: 1px solid #f8f8f975;
+    border-radius: 10px;
+    text-align: center;
+    .title{
+        h1{
+            text-align: center;
+            padding: 30px 20px;
+            color: #d0b772;
+            font-weight: 300;
+        }
+    }
+    .tableBox{
+        display: block;
+        padding: 0 20px;
+        border-top: 1px solid #929090;
+        border-bottom: 1px solid #929090;
+    }
+    .application{
+        color: #e8eaec;
+        background-color: #0dcaaf;
+        border: 0;
+    }
+    .logoutbtn{
+        margin-top: 20px;
+    }    
+}

+ 287 - 0
TEAMModelOS/ClientApp/src/view/schoolList/Index.vue

@@ -0,0 +1,287 @@
+<style lang="less" scoped>
+  @import './Index.less';
+</style>
+
+<template>
+    <div id="schoolList">
+        <div class="title">
+            <h1>{{ $t('schoolList.title1')}}</h1>
+        </div>
+        <Row class="filterBox" type="flex" justify="center" :gutter="16">
+            <Col span="11">
+                <Input v-model="filterText" class="search" suffix="ios-search" :placeholder="$t('schoolList.placeholder.search')" />
+            </Col>
+            <Col span="3">
+                <Select class="select" v-model="area" :placeholder="$t('schoolList.placeholder.area')" clearable>
+                    <Option v-for="item in areaList" :value="item.value" :key="item.value" >{{ item.label }}</Option>
+                </Select>
+            </Col>
+            <Col span="5">
+                <Select class="select" v-model="province" :placeholder="$t('schoolList.placeholder.province')" clearable>
+                    <Option v-for="item in provinceList" :value="item.value" :key="item.value">{{ item.label }}</Option>
+                </Select>
+            </Col>
+            <Col span="5">
+                <Select class="select" v-model="city" :placeholder="$t('schoolList.placeholder.city')" clearable>
+                    <Option v-for="item in cityList" :value="item.value" :key="item.value">{{ item.label }}</Option>
+                </Select>
+            </Col>
+        </Row>                  
+        <span class="tableBox">
+            <Table height="550" class="vue-table scrollstyle" :columns="columns" :data="filteredRows">
+                <template slot-scope="{ row }" slot="avatar">
+                    <img :src="row.avatar" width="30" style="border-radius: 15px;border 1px #fff;">
+                </template>
+                <template slot-scope="{ row }" slot="shortCode">
+                    <span>{{ row.shortCode |  upper}}</span>
+                </template>
+                <template slot-scope="{ row }" slot="action">                
+                    <Button v-if="applicationSchool && userInfo.applicationSchool.indexOf(row.shortCode) < 0" class="appButton application" size="small" @click="applicationSchool(row.shortCode)">{{ $t('schoolList.btn.apply') }}</Button> 
+                    <Button v-else class="verifyButton" size="small" disabled>{{ $t('schoolList.btn.pending') }}</Button>
+                </template>
+            </Table>
+        </span>
+        <Button class="application logoutbtn" size="large" @click="logout()">{{ $t('schoolList.btn.logout') }}</Button> 
+    </div>
+</template>
+
+<script>
+import { User } from '@/service/User'
+
+export default {
+  data() {   
+    return {         
+        columns: [
+            {
+                title: ' ',
+                slot: 'avatar',
+                width: 150,
+                align: 'center'
+            },
+            {
+                title: this.$t('schoolList.columns.name'),
+                key: 'name'
+            },
+            {
+                title: this.$t('schoolList.columns.area'),
+                width: 150,
+                key: 'area'
+            },
+            {
+                title: this.$t('schoolList.columns.PRVN'),
+                width: 150,
+                key: 'PRVN'
+            },
+            {
+                title: this.$t('schoolList.columns.shortCode'),
+                width: 150,
+                slot: 'shortCode',
+            },
+            {
+                title: this.$t('schoolList.columns.code'),
+                width: 150,
+                key: 'code'
+            },
+            {
+                title: ' ',
+                slot: 'action',
+                width: 150,
+                align: 'center'
+            }
+        ],
+        schoolList: [           
+        ],
+        area: '',
+        province: '',
+        city: '',
+        areaList: [
+            {
+                value: '國際',
+                label: '國際'
+            },
+            {
+                value: '大陸',
+                label: '大陸'
+            }            
+        ],
+        provinceList:[
+            {
+                value: '臺灣',
+                label: '臺灣'
+            },
+            {
+                value: '北京',
+                label: '北京'
+            },
+            {
+                value: '新疆',
+                label: '新疆'
+            },
+        ],
+        cityList: [
+            {
+                value: '北京',
+                label: '北京'
+            },
+            {
+                value: '伊犁',
+                label: '伊犁'
+            },
+            {
+                value: '台北',
+                label: '台北'
+            },
+        ],        
+        filterText: ''
+    }
+
+  },
+  filters: {
+        upper: function (value) {
+            if (!value) return '';
+            value = value.toString();
+            return value.toUpperCase();
+        }
+    },
+  computed: {
+    userAccess() { return this.$access.getExtendInfo('userAccess');},
+    userInfo() { return this.$access.getExtendInfo('userInfo');},
+    filteredRows: function(){
+
+        var result = this.schoolList;
+
+        // 所以這裡將 filterText 與 rows[n].name 通通轉小寫方便比對。
+        let filterText = this.filterText.trim().toLowerCase()
+        let areaText = this.area
+        let provinceText = this.province
+        let cityText = this.city
+
+        if(filterText){
+            result = result.filter(function(item, index, array){
+                let name = item.name.toString().toLowerCase()
+                let code = item.code.toString().toLowerCase()
+                let shortCode = item.shortCode.toString().toLowerCase()
+                return ((name.indexOf(filterText) > -1) || (code.indexOf(filterText) > -1) || (shortCode.indexOf(filterText) > -1))
+            });
+        } 
+        
+        if(areaText){
+            result = result.filter(function(item, index, array){
+                let area = item.area
+                return area === areaText
+            });
+        }
+
+        if(provinceText){
+            result = result.filter(function(item, index, array){
+                let PRVN = item.PRVN
+                return PRVN.indexOf(provinceText) >= 0
+            });
+        }
+
+        if(cityText){
+            result = result.filter(function(item, index, array){
+                let PRVN = item.PRVN
+                return PRVN.indexOf(cityText) >= 0
+            });
+        }
+        
+        return result
+    }
+  },
+  created() {
+      this.$api.schoolList.List().then(res => {
+        this.schoolList = res.data
+      })      
+  },
+  methods: {
+    applicationSchool: function(schoolCode){
+        this.$api.schoolList.Join({id: this.userInfo.TEAMModelId, schoolCode: schoolCode}).then(result => {
+            User.login(result.data.userInfo)
+        })
+    },
+    logout(){
+        User.logout()
+    }
+  }
+}
+</script>
+<style lang="less">
+.vue-table .ivu-table{
+    background-color: #1A1A1A;    
+    tr{
+        background: -webkit-linear-gradient(left,#212121,#000000);
+        background: -o-linear-gradient(right,#212121,#000000);
+        background: -moz-linear-gradient(right,#212121,#000000);
+        background: linear-gradient(to right,#212121,#000000);
+    }
+    th{
+        color: #e8eaec;
+        background-color: inherit;
+        border-color: #929090;
+    }
+    td {
+        color: #e8eaec;
+        background-color: #1A1A1A;
+        border-color: #929090;
+        .appButton{
+            font-size: 10px;
+            padding: 0 15px;
+        }
+        .verifyButton{
+            color: #ccc;
+            background-color: #666;
+            border: 0;
+            font-size: 10px;
+            padding: 0 15px;
+        }
+    }
+    &:before{
+        background: none;            
+    }
+    .ivu-table-overflowY::-webkit-scrollbar {
+        width: 5px;
+    }
+    .ivu-table-overflowY::-webkit-scrollbar-track {
+        background-color: #f8f8f975;
+    }
+    .ivu-table-overflowY::-webkit-scrollbar-thumb {
+        border-radius: 10px;
+        background: #969e85;
+    }
+    .ivu-table-overflowY::-webkit-scrollbar-thumb:hover {
+        background: #555; 
+    }
+    .ivu-table-overflowY::-webkit-scrollbar-button {
+    // display: none;
+    }
+}
+.filterBox{
+    padding: 0 20px;
+    margin: 20px 0;
+    .search{
+        .ivu-input{
+            color: #ccc;
+            background-color: transparent;
+        }
+    }
+    .select{
+        color: #ccc;
+        .ivu-select-selection{
+            background-color: transparent;
+        }
+        .ivu-select-dropdown{            
+            background-color: #1a1a1a;
+            .ivu-select-item-selected{
+                background-color: #515a6e;
+            }
+            .ivu-select-item{
+                color: #ccc;
+                &:hover{
+                    background-color: #515a6e;
+                }
+            }
+        }
+    }
+}
+</style>

+ 17 - 7
TEAMModelOS/ClientApp/src/view/selflearning/LearnProgress.less

@@ -8,17 +8,27 @@
 .learn-progress-container {
     width: 100%;
     height: 100%;
-    .learn-progress-main{
-        width:100%;
-        height:~"calc(100% - 45px)";
-        padding-right:10px;
+
+    .learn-progress-main {
+        width: 100%;
+        height: ~"calc(100% - 45px)";
+        padding-right: 10px;
+        .whole-progress-wrap{
+            width:100%;
+            height:300px;
+            display:flex;
+            flex-direction:row;
+        }
     }
 }
 .learn-progress-filter {
     width: 100%;
-    height: 45px;
-    line-height: 45px;
-    /*border-bottom:1px solid @borderColor;*/
+    height: 40px;
+    line-height: 40px;
+    background: rgba(50, 50, 50, .9);
+    padding-left: 10px;
+    border-radius: 5px;
+    margin-bottom: 20px;
 
     .filter-label {
         color: white;

+ 134 - 36
TEAMModelOS/ClientApp/src/view/selflearning/LearnProgress.vue

@@ -1,38 +1,53 @@
 <template>
     <div class="learn-progress-container">
-        <div class="learn-progress-filter dark-iview-select">
-            <span class="filter-label">搜学生:</span>
-            <Select v-model="model11" filterable style="display:inline-block;width:200px;" size="small">
-                <Option v-for="item in studentList" :value="item.value" :key="item.value">{{ item.label }}</Option>
-            </Select>
-            <span  class="filter-label" style="margin-left:30px;">选班级:</span>
-            <Select v-model="model11" filterable style="display:inline-block;width:200px;" size="small">
-                <Option v-for="item in classroomList" :value="item.value" :key="item.value">{{ item.label }}</Option>
-            </Select>
-            <div class="right-filter-wrap">
-                <div class="radio-box-wrap">
-                    <div :class="currentView == 0 ? 'radio-box-item active-radio-box-item':'radio-box-item'" @click="setCurrentView(0)">
-                        <Tooltip content="活动进度总览" placement="bottom" theme="light">
-                            <Icon type="md-list" size="15" />
-                        </Tooltip>
-                    </div>
-                    <div :class="currentView == 1 ? 'radio-box-item active-radio-box-item':'radio-box-item'" @click="setCurrentView(1)">
-                        <Tooltip content="学习自学概况" placement="bottom" theme="light">
-                            <Icon type="md-person" size="15" />
-                        </Tooltip>
-                    </div>
-                </div>
-            </div>
-        </div>
+        
         <div class="learn-progress-main dark-iview-table">
-            <Table :columns="columns" :data="data" :show-header="false">
+            <!--<Table v-if="currentView == 0" :columns="columns" :data="data" :show-header="true">
                 <template slot-scope="{ row, index }" slot="progress">
                     <Progress style="width:200px;" :percent="row.progress" :stroke-width="16" text-inside />
                 </template>
                 <template slot-scope="{ row, index }" slot="action">
-                    <Icon type="ios-people" size="22" style="cursor:pointer;"/>
+                    <Icon type="ios-people" size="22" style="cursor:pointer;" />
                 </template>
-            </Table>
+            </Table>-->
+            <vuescroll>
+                <div class="whole-progress-wrap">
+
+                </div>
+                <div class="learn-progress-filter dark-iview-select">
+                    <span class="filter-label">搜学生:</span>
+                    <Select v-model="model11" filterable style="display:inline-block;width:200px;" size="small">
+                        <Option v-for="item in studentList" :value="item.value" :key="item.value">{{ item.label }}</Option>
+                    </Select>
+                    <span class="filter-label" style="margin-left:30px;">选班级:</span>
+                    <Select v-model="model11" filterable style="display:inline-block;width:200px;" size="small">
+                        <Option v-for="item in classroomList" :value="item.value" :key="item.value">{{ item.label }}</Option>
+                    </Select>
+                    <div class="right-filter-wrap">
+                        <div class="radio-box-wrap">
+                            <div :class="currentView == 0 ? 'radio-box-item active-radio-box-item':'radio-box-item'" @click="setCurrentView(0)">
+                                <Tooltip content="活动进度总览" placement="bottom" theme="light">
+                                    <Icon type="md-list" size="15" />
+                                </Tooltip>
+                            </div>
+                            <div :class="currentView == 1 ? 'radio-box-item active-radio-box-item':'radio-box-item'" @click="setCurrentView(1)">
+                                <Tooltip content="学习自学概况" placement="bottom" theme="light">
+                                    <Icon type="md-person" size="15" />
+                                </Tooltip>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <Table :columns="studentColumns" :data="studentData" :show-header="true">
+                    <template slot-scope="{ row, index }" slot="isComplete">
+                        <Icon size="20" type="md-checkmark" color="aqua" v-if="row.isComplete == 1" />
+                        <span v-else>--</span>
+                    </template>
+                    <template slot-scope="{ row, index }" slot="action">
+                        <Icon type="ios-document" size="22" style="cursor:pointer;" />
+                    </template>
+                </Table>
+            </vuescroll>
         </div>
     </div>
 </template>
@@ -40,17 +55,20 @@
     export default {
         data() {
             return {
+                model11:'',
                 currentView: 0,
                 studentList: [],
                 classroomList: [],
                 columns: [
                     {
                         title: '学习阶段',
-                        key: 'name'
+                        key: 'name',
+                        //align:'center'
                     },
                     {
                         title: '完成进度',
-                        slot: 'progress'
+                        slot: 'progress',
+                        align:'center'
                     },
                     {
                         title: '操作',
@@ -61,25 +79,105 @@
                 data: [
                     {
                         name: '一次函数基础',
-                        progress: 50,
-
+                        progress: 50
                     },
                     {
-                        name: '一次函数基础',
+                        name: '一次函数进阶',
                         progress: 50,
 
                     },
                     {
-                        name: '一次函数基础',
+                        name: '一次函数高阶',
                         progress: 50,
 
                     },
                     {
-                        name: '一次函数基础',
+                        name: '一次函数总结',
                         progress: 50,
-
                     },
-                ]
+                ],
+                studentData: [
+                    {
+                        name: '张飞',
+                        isComplete: 1
+                    },
+                    {
+                        name: '孔子',
+                        isComplete: 0,
+                    },
+                    {
+                        name: '柏拉图',
+                        isComplete: 1,
+                    },
+                    {
+                        name: '苏格拉底',
+                        isComplete: 1,
+                    },
+                    {
+                        name: '杜威',
+                        isComplete: 0,
+                    },
+                    {
+                        name: '老夫子',
+                        isComplete: 1,
+                    },
+                    {
+                        name: '张飞',
+                        isComplete: 1
+                    },
+                    {
+                        name: '孔子',
+                        isComplete: 0,
+                    },
+                    {
+                        name: '柏拉图',
+                        isComplete: 1,
+                    },
+                    {
+                        name: '苏格拉底',
+                        isComplete: 1,
+                    },
+                    {
+                        name: '杜威',
+                        isComplete: 0,
+                    },
+                    {
+                        name: '老夫子',
+                        isComplete: 1,
+                    }
+                ],
+                studentColumns: [
+                    {
+                        title: '姓名',
+                        key: 'name',
+                        //align:'center'
+                    },
+                    {
+                        title: '一次函数初阶',
+                        slot: 'isComplete',
+                        align:'center'
+                    },
+                    {
+                        title: '一次函数进阶',
+                        slot: 'isComplete',
+                        align:'center'
+                    },
+                    {
+                        title: '一次函数高阶',
+                        slot: 'isComplete',
+                        align:'center'
+                    },
+                    {
+                        title: '一次函数总结',
+                        slot: 'isComplete',
+                        align:'center'
+                    },
+                    {
+                        title: '操作',
+                        slot: 'action',
+                        width:150
+                    }
+                ],
             }
         },
         methods: {

+ 4 - 0
TEAMModelOS/ClientApp/src/view/selflearning/ManageHomeWork.less

@@ -98,6 +98,10 @@
     .hw-info-box {
         width: 30%;
         border-right: 1px solid @borderColor;
+
+        .hw-info-wrap{
+            color:#AAAAAA !important;
+        }
     }
 
     .hw-data-box {

+ 30 - 7
TEAMModelOS/ClientApp/src/view/selflearning/ManageHomeWork.vue

@@ -7,6 +7,7 @@
                 <Icon type="md-add" class="to-create-icon" @click="goToCreate" />
             </div>
             <vuescroll>
+                <Loading :top="200" bgColor="rgba(103, 103, 103, 0.27)" type="1" v-show="isLoadList"></Loading>
                 <div class="hw-item-wrap">
                     <div v-if="hwList.length === 0">
                         <EmptyBox :top="50"></EmptyBox>
@@ -61,12 +62,12 @@
         <!-- 完善试卷信息 -->
         <Modal v-model="addHwModal"
                class-name="hw-modal"
-               title="新增作业"
+               :title="isEdit ? '修改作业' : '新增作业'"
                footer-hide
                width="600px">
             <div class="hw-modal-box">
                 <vuescroll>
-                    <BaseHwForm @onAddSuccess="onAddSuccess" :editItem="editItem" editable></BaseHwForm>
+                    <BaseHwForm @onAddSuccess="onAddSuccess" :editItem="editItem" :editable="editable" ref="editForm"></BaseHwForm>
                 </vuescroll>
             </div>
         </Modal>
@@ -74,12 +75,16 @@
 </template>
 <script>
     import EmptyBox from '@/common/EmptyData'
+    import Loading from '@/common/Loading'
     import BaseHwForm from '@/components/learnactivity/BaseHwForm'
     import BaseHwTable from '@/components/learnactivity/BaseHwTable'
     export default {
-        components: { BaseHwForm, BaseHwTable, EmptyBox },
+        components: { BaseHwForm, BaseHwTable, EmptyBox, Loading },
         data() {
             return {
+                isLoadList:false,
+                isEdit: false,
+                editable:false,
                 hwList: [],
                 studentsList:[],
                 currentHw: {},
@@ -89,31 +94,46 @@
             }
         },
         methods: {
+            /** 新增作业 */
             goToCreate() {
+                this.$refs.editForm.handleReset('hwForm')
+                this.isEdit = false
                 this.editItem = null
+                this.editable = true
                 this.addHwModal = true
-
             },
 
+            /** 获取作业列表 */
             getHomeWorkList() {
+                this.isLoadList = true
                 let params = { scopeCode:this.$store.state.userInfo.TEAMModelId }
                 this.$api.learnActivity.FindHomeWork(params).then(res => {
                     if (!res.error && res.result.data) {
                         this.hwList = res.result.data
-                        this.onHwClick(res.result.data[0],0)
+                        this.onHwClick(res.result.data[0], 0)
+                        this.isLoadList = false
                     } else {
                         this.$Message.error('获取数据失败')
                     }
                 })
             },
 
-            onHwClick(item,index) {
+            /**
+             * 作业点击事件
+             * @param item
+             * @param index
+             */
+            onHwClick(item, index) {
                 this.currentHw = item
                 this.activeHwIndex = index
                 this.getHwStudents(item.id)
             },
 
 
+            /**
+             * 获取作业关联的学生清单
+             * @param hwId 作业ID
+             */
             getHwStudents(hwId) {
                 this.$api.learnActivity.FindStudentByHwId({ homeWorkId: hwId }).then(res => {
                     if (!res.error && res.result.data) {
@@ -124,13 +144,16 @@
                 })
             },
 
+            /** 作业编辑事件 */
             onEditHw() {
                 this.editItem = this.currentHw
+                this.isEdit = true
+                this.editable = true
                 this.addHwModal = true
             },
 
 
-
+            /** 新增作业成功回调 */
             onAddSuccess() {
                 this.addHwModal = false
                 this.getHomeWorkList()

+ 16 - 10
TEAMModelOS/ClientApp/src/view/selflearning/ManageSelfLearn.vue

@@ -30,6 +30,10 @@
                         <Icon type="ios-create-outline" size="20" />
                         编辑内容
                     </span>
+                    <span class="main-bar-action-btn">
+                        <Icon type="ios-send" size="20" />
+                        发布活动
+                    </span>
                 </div>
             </div>
             <div class="self-learn-main-body">
@@ -39,7 +43,8 @@
                             <div class="base-info-box-header">
                                 <span>基础信息</span>
                             </div>
-                            <div class="base-info-detail">
+                            <NoData v-if="selfLearnList.length == 0"></NoData>
+                            <div v-else class="base-info-detail">
                                 <div class="base-info-item">
                                     <span class="base-info-label">
                                         名称:
@@ -61,14 +66,7 @@
                                 <div class="base-info-item">
                                     <span class="base-info-label">
                                         学科:
-                                        
-
-                                        
-
                                     </span>
-                                    
-
-                                    
                                     <p class="base-info-value">
                                         {{selfLearnList[currentLearnIndex].subjectCode}}
                                     </p>
@@ -115,7 +113,8 @@
                                             学习阶段
                                         </span>
                                     </div>
-                                    <div class="learn-steps-detail">
+                                    <NoData v-if="selfLearnList.length == 0"></NoData>
+                                    <div v-else class="learn-steps-detail">
                                         <div v-for="(item,index) in selfLearnList[currentLearnIndex].steps" @click="selectStep(index)" :class="currentStepIndex == index ? 'self-learn-step-item block-bg block-bg-active':'self-learn-step-item block-bg'">
                                             <span>
                                                 {{item.name}}
@@ -129,7 +128,8 @@
                                             学习内容
                                         </span>
                                     </div>
-                                    <div class="learn-content-detail">
+                                    <NoData v-if="selfLearnList.length == 0"></NoData>
+                                    <div v-else class="learn-content-detail">
                                         <vuescroll>
                                             <p class="self-learn-content-label">
                                                 内容:{{selfLearnList.length == 0 ? 0 : selfLearnList[currentLearnIndex].steps[currentStepIndex].resource.length}}
@@ -161,6 +161,12 @@
                @on-ok="confirmEdit">
             <p>确认跳转到自主学习活动编辑页面?</p>
         </Modal>
+        <Modal v-model="editStatus"
+               title="编辑内容"
+               class-name="dark-iview-modal"
+               @on-ok="confirmEdit">
+            <p>确认跳转到自主学习活动编辑页面?</p>
+        </Modal>
     </div>
 </template>
 <script>

+ 10 - 13
TEAMModelOS/ClientApp/src/view/smartclassdashboard/Index.vue

@@ -496,13 +496,13 @@
 </template>
 
 <script>
-import RingPie from '@/components/smartclassdashboard/RingPie'
-import LegendPie from '@/components/smartclassdashboard/LegendPie'
-import ClassLine from '@/components/smartclassdashboard/ClassLine'
-import ClassBar from '@/components/smartclassdashboard/ClassBar'
-import FloorPlan from '@/components/smartclassdashboard/FloorPlan'
+import RingPie from '@/components/smartclassdashboard/RingPie.vue'
+import LegendPie from '@/components/smartclassdashboard/LegendPie.vue'
+import ClassLine from '@/components/smartclassdashboard/ClassLine.vue'
+import ClassBar from '@/components/smartclassdashboard/ClassBar.vue'
+import FloorPlan from '@/components/smartclassdashboard/FloorPlan.vue'
 import { mapState } from 'vuex'
-import * as d3 from 'd3'
+
 export default {
   name: 'smart-dashboard',
   data() {
@@ -744,20 +744,17 @@ export default {
     let _this = this
     if (this.isExistShortCode) {
       this.$api.ClassMgmt.GetTestIoTData({ schoolshortcode: this.$route.params.schoolshortcode }).then(res => {
-        console.log(res)
-        _this.$store.state.classMgmt.data = res
+        console.log(res.result.data)
+        _this.$store.state.classMgmt.data = res.result.data
       })
     } else {
       this.$api.ClassMgmt.GetTestIoTData({ schoolshortcode: 'ydzt' }).then(res => {
-        console.log(res)
-        _this.$store.state.classMgmt.data = res
+        console.log(res.result.data)
+        _this.$store.state.classMgmt.data = res.result.data
       })
     }
   },
   mounted() {
-    this.$nextTick(() => {
-
-    })
   }
 }
 </script>

+ 9 - 9
TEAMModelOS/ClientApp/src/view/smartschooldashboard/Index.vue

@@ -531,14 +531,14 @@
 </template>
 
 <script>
-import AccountLine from '@/components/smartschooldashboard/AccountLine'
-import TeachScienceBar from '@/components/smartschooldashboard/TeachScienceBar'
-import ClassTypePie from '@/components/smartschooldashboard/ClasstypePie'
-import RingPie from '@/components/smartschooldashboard/RingPie'
-import CourseBar from '@/components/smartschooldashboard/CourseBar'
-import FinishPercentPie from '@/components/smartschooldashboard/FinishPercentPie'
-import TotalLine from '@/components/smartschooldashboard/TotalLine'
-import ClassResourceBar from '@/components/smartschooldashboard/ClassResourceBar'
+import AccountLine from '@/components/smartschooldashboard/AccountLine.vue'
+import TeachScienceBar from '@/components/smartschooldashboard/TeachScienceBar.vue'
+import ClassTypePie from '@/components/smartschooldashboard/ClasstypePie.vue'
+import RingPie from '@/components/smartschooldashboard/RingPie.vue'
+import CourseBar from '@/components/smartschooldashboard/CourseBar.vue'
+import FinishPercentPie from '@/components/smartschooldashboard/FinishPercentPie.vue'
+import TotalLine from '@/components/smartschooldashboard/TotalLine.vue'
+import ClassResourceBar from '@/components/smartschooldashboard/ClassResourceBar.vue'
 import { mapState } from 'vuex'
 
 export default {
@@ -572,7 +572,7 @@ export default {
   methods: {
   },
   created() {
-    console.log(this.test)
+    
   }
 }
 </script>

+ 31 - 34
TEAMModelOS/ClientApp/src/view/teachermgmt/Index.less

@@ -1,39 +1,36 @@
-#teachermgmt{    
-    width: 100%;
-    height: 100%;
-    color: #fff;
-    padding: 1%;
-    overflow-x: auto;
-    overflow-y: hidden;
-    .main{
-        white-space: nowrap;
-        display: -webkit-box;
-        display: -ms-flexbox;
-        display: flex;
-        height:95%;
-        .pane{
-            height: 100%;
-            padding:10px;
-            background-color: #282828;
-            border:1px solid #666;
-            position: relative;
-            z-index:10;
-            &-box{
-                overflow: auto;
-                height: 88%;
-                &-colum{
-                    padding: 15px 10px 10px 15px;
-                    background-color: #66666629;
-                    cursor: pointer;
-                    margin-bottom: 5px;
-                    &:hover, &.active{
-                        background: -webkit-linear-gradient(right, rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: -o-linear-gradient(right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: -moz-linear-gradient(right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: linear-gradient(to right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                    }
+#teachermgmt{
+    .mgmt-top {
+        width: 100%;
+        height: 50px;
+        border-bottom: 1px solid #303030;
+        padding: 0px 20px;
+        background-color: #282828;
+        .tab-box {
+            display: inline-block;
+            width: 30%;
+            .pane{
+                font-weight: bold;
+                margin-right: 50px;
+                color: #777777;
+                line-height: 50px;
+                padding: 5px 0;
+                cursor: pointer;
+                vertical-align: middle;
+                &.active{
+                    color: #e2e2e2;
+                    border-bottom: 1px #777777 solid;
                 }
             }
         }
     }
+    .mgmt-main {
+        height: calc(100% - 50px);
+        width: 100%;     
+    }
+}
+.opacity-enter-active, .opacity-leave-active {
+    transition: all 0.3s;
+}
+.opacity-enter, .opacity-leave-to /* .list-leave-active below version 2.1.8 */ {
+    opacity: 0;
 }

+ 33 - 43
TEAMModelOS/ClientApp/src/view/teachermgmt/Index.vue

@@ -2,65 +2,55 @@
   @import './Index.less';
 </style>
 
+<style lang="less">
+.badgesty{
+  margin-left: 6px;
+  box-shadow: none;
+}
+</style>    
+
 <template>
     <div id="teachermgmt" class="backdrop">
-        <Row class="main">
-            <Col class="pane" :span="3">
-                 <Row class="scrollstyle pane-box">
-                    <Col>
-                        <div class="pane-box-colum" @click="paneBtn('AccountMgmt')"  :class="{ 'active': menuStr === 'AccountMgmt' }">
-                            AccountMgmt 帳號管你
-                        </div>
-                        <div class="pane-box-colum" @click="paneBtn('Authorization')" :class="{ 'active': menuStr === 'Authorization' }">
-                            Authorization 權限管你
-                        </div>
-                    </Col>
-                </Row>
-            </Col>
-            <transition name="leftInOut">
-                <div v-on:closeComp="close()" :is="menu"></div>
-            </transition>
-        </Row>
+      <div class="mgmt-top">
+        <div class="tab-box">
+          <span class="pane" @click="paneBtn('userList')" :class="{ 'active': compts === 'userList' }" >{{$t('teachermgmt.page.text1')}}</span>
+          <span class="pane" @click="paneBtn('personnel')" :class="{ 'active': compts === 'personnel' }">{{$t('teachermgmt.page.text2')}} <Badge :count="5" class-name="badgesty"></Badge></span>
+        </div>
+      </div>
+      <div class="mgmt-main">
+
+        <transition name="opacity" mode="out-in">
+            <div :is="compts"></div>
+        </transition>
+
+      </div>
     </div>
 </template>
 
 <script>
-
-import AccountMgmt from './menu/accountmgmt/Index.vue'
-import Authorization from './menu/authorization/Index.vue'
+import userList from './components/userList/Index.vue'
+import personnel from './components/personnel/Index.vue'
 
 export default {
   data() {
     return {
-        menu: '',
-        menuStr: ''
+        compts: 'userList'
     }
   },
   components: {
-    AccountMgmt,
-    Authorization
+    userList,
+    personnel
   },
   computed: {
+    user() { return this.$access.getExtendInfo('userInfo');}
   },
   methods: {
-    async paneBtn(pane) {
-        if (this.menu != '' && this.menu != pane) {
-           this.menu = ''
-           this.menuStr = pane
-           await this.sleep(700)
-           this.menu = pane
-        } else {
-            this.menu = pane
-            this.menuStr = pane
-        }
-    },
-    sleep(time) {
-        return new Promise((resolve) => setTimeout(resolve, time))
-    },
-    close(e) {
-        this.menu = ''
-        this.menuStr = ''
-    }
-  }
+    paneBtn(pane) {
+      this.compts = pane       
+    },    
+  },
+  mounted() {
+    console.log(this.user)
+  },
 }
 </script>

+ 80 - 0
TEAMModelOS/ClientApp/src/view/teachermgmt/components/personnel/Index.less

@@ -0,0 +1,80 @@
+.personnel{
+    width: 100%;
+    height: 100%;
+    position: relative;
+    overflow-x: hidden;
+    .users{
+        float: left;
+        width: 35%;
+        height: 100%;
+        border-right: 1px solid #464646;        
+        .sort-box{
+            padding-left: 20px;
+            border-bottom: 1px solid #464646;
+            .title{
+                color: #777777;
+                height: 46px;
+                line-height: 46px;
+                border-bottom: 1px solid #464646;
+            }            
+            .sort{
+                color: #777777;
+                height: 25px;
+                line-height: 25px;
+                font-size: 12px;
+                background: -webkit-linear-gradient(left,#252525,#1b1b1b);
+                background: -o-linear-gradient(right,#252525,#1b1b1b);
+                background: -moz-linear-gradient(right,#252525,#1b1b1b);
+                background: linear-gradient(to right,#252525,#1b1b1b);
+            }
+        }
+        .details{
+            &-box{
+                padding-left: 20px;
+                .detail{
+                    padding: 20px 20px 20px 5px;
+                    border-bottom: 1px solid #464646;
+                    display: flex;                
+                    &-info{
+                        width: 75%;
+                        .title{
+                            width: 90%;
+                            color: #fefefe;
+                            font-size: 17px;
+                            height: 25px;
+                            line-height: 25px;
+                        }
+                        .sub-title{
+                            font-size: 13px;
+                            color: #777777;
+                            .typeInfo{
+                                margin-top: 10px;
+                                .icon{
+                                    color: #fefefe;
+                                    margin-right: 5px;
+                                }
+                            }
+                        }
+                    }
+                    &-ctr{
+                        width: 25%;
+                        .time{
+                            color: #777777;
+                            font-size: 12px;
+                            height: 25px;
+                            line-height: 25px;
+                        }
+                        .btns{
+
+                        }
+                    }
+                }
+            }
+        }
+    }
+    .addTeacher{
+        float: left;
+        width: 65%;
+        height: 100%;
+    }
+}

+ 92 - 0
TEAMModelOS/ClientApp/src/view/teachermgmt/components/personnel/Index.vue

@@ -0,0 +1,92 @@
+<style lang="less" scoped>
+  @import './Index.less';
+</style>
+
+<style lang="less">
+.sort-dropdown{
+    .ivu-select-dropdown{        
+        background-color: #2d2d2d;
+        border-radius: 2px;
+        border: 1px #464646 solid;
+        .ivu-dropdown-menu{
+            li {
+                color: #ccc;
+                font-size: 12px!important;
+            }
+        }
+    }
+}
+</style>
+
+<template>
+    <div class="personnel">
+        <div class="users">
+            <div class="sort-box">
+                <div class="title">{{'申請審核'}}</div>
+                <div class="sort">
+                    <Dropdown class="sort-dropdown" trigger="click" placement="bottom-start">
+                        <span>
+                            {{'顯示時間排序'}}
+                            <Icon type="ios-arrow-down"></Icon>
+                        </span>
+                        <DropdownMenu class="sdfsdf" slot="list">
+                            <DropdownItem>{{ '顯示時間排序' }}</DropdownItem>
+                            <DropdownItem>{{ '顯示老師申請' }}</DropdownItem>
+                            <DropdownItem>{{ '顯示學校邀請' }}</DropdownItem>
+                        </DropdownMenu>
+                    </Dropdown>
+                </div>                
+            </div>
+            <div class="details">
+                <div class="details-box scrollstyle">
+
+                    <div class="detail">
+                        <div class="detail-info">
+                            <div class="title ellipsis">
+                                {{ 'mia_spoelstra#3927' }}
+                            </div>
+                            <span class="sub-title">
+                                {{ 'Erilk Jon spcelstra' }}
+                                <div class="typeInfo">
+                                    <icon class="icon" icon="file-alt" /> {{'教師申請加入'}}
+                                </div>
+                            </span>
+
+                        </div>
+                        <div class="detail-ctr">
+                            <div class="time">
+                                2009.9.5 AM 10:49
+                            </div>
+                            <div calss="btns">
+                                <div>
+                                    <div>
+                                        sdf
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+
+                </div>
+            </div>
+        </div>
+        <div class="addTeacher">
+            sdfsdf
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name:'personnel',
+    data() {
+        return {
+        }
+    },
+    computed:{
+
+    },
+    methods: {
+    }
+}
+</script>

+ 111 - 0
TEAMModelOS/ClientApp/src/view/teachermgmt/components/userList/Index.less

@@ -0,0 +1,111 @@
+.userList{
+    width: 100%;
+    height: 100%;
+    position: relative;
+    overflow-x: hidden;
+    .userLists{
+        float: left;
+        width: 100%;
+        height: 100%;
+        border-right: 1px solid #464646;
+        transition: all 0.7s;
+        position: absolute;
+        &.isSetting{
+            width: 70%;
+        }
+        .serch-box{            
+            padding: 5px 5px 5px 20px;
+            border-bottom: 1px solid #464646;
+            height: 45px;
+            background: -webkit-linear-gradient(left,#2a2a2a,#1b1b1b);
+            background: -o-linear-gradient(right,#2a2a2a,#1b1b1b);
+            background: -moz-linear-gradient(right,#2a2a2a,#1b1b1b);
+            background: linear-gradient(to right,#2a2a2a,#1b1b1b);
+            .multiSet{
+                float: right;
+                color: #ccc;
+            }
+        }
+        .userListContent{
+            padding-left: 20px;
+            height: calc(100% - 45px);
+            background-color: #282828;
+        }
+    }
+    .authSetting{
+        float: left;
+        height: calc(100% - 45px);
+        width: 30%;
+        position: absolute;
+        transition: all 0.7s;
+        right: -30%;
+        padding-left: 20px;
+        &.isSetting{
+            right: 0;
+        }
+        .header{
+            height: 45px;
+            line-height: 45px;
+            width: 100%;
+            border-bottom: 1px solid #464646;
+            .title{
+                color: #727272;
+            }
+            .icon{
+                cursor: pointer;
+                margin-right: 20px;
+                height: 50px;
+                line-height: 50px;
+                float: right;
+            }
+        }
+        .users{
+            padding-bottom: 15px;
+            border-bottom: 1px solid #464646;           
+            .title{
+                color: #727272;
+                font-size: 12px;
+                height: 50px;
+                line-height: 50px;
+            }
+            .ids{
+                color: #ccc;
+                height: 130px;
+                overflow: auto;
+            }
+        }
+        .authContent{
+            height: calc(100% - 322px);
+            overflow: auto;
+            .authBox{
+                padding-right: 20px;
+            }
+            .title{
+                color: #656464;
+                font-size: 12px;
+                padding: 10px 0;
+            }
+            .subTitle{
+                padding: 10px 0 10px 10px;
+                color: #ccc;
+                font-size: 13px;
+                .switch{
+                    float: right;
+                }
+            }
+            .detail{
+                padding: 10px 0 10px 20px;
+                .auth{
+                    color: #656464;
+                    font-size: 12px;
+                }
+                .switch{
+                    float: right;
+                }
+            }
+        }
+        .authBtn{
+            padding: 15px;
+        }
+    }
+}

+ 417 - 0
TEAMModelOS/ClientApp/src/view/teachermgmt/components/userList/Index.vue

@@ -0,0 +1,417 @@
+<style lang="less" scoped>
+  @import './Index.less';
+</style>
+
+<style lang="less">
+.serch-inp{
+  width: 100%;
+  max-width: 300px;
+  .ivu-input{    
+    font-size: 13px;
+    background-color: transparent;
+    border-color: #ccc;
+    color: #ccc;
+  }
+}
+.multiSet{
+    &:hover{
+        span{
+            color: #333;
+        }
+    }
+    .icon{
+        vertical-align: middle;
+        margin-right: 7px;
+    }
+}
+.userListContent{
+    .ivu-table{
+        background-color: transparent;
+        .ivu-table-header{
+            tr:first-child{
+                background: -webkit-linear-gradient(left,#272727,#222222);
+                background: -o-linear-gradient(right,#272727,#222222);
+                background: -moz-linear-gradient(right,#272727,#222222);
+                background: linear-gradient(to right,#272727,#222222);
+            }
+        }
+        th {
+           background-color: transparent;
+           border-bottom: 1px solid #343434;
+           color: #757575;
+           font-size: 12px;
+        }
+        td{
+            background-color: transparent;
+        }
+        .ivu-table-tbody{
+            td{
+                background-color: transparent;
+                border-bottom: 1px solid #343434;
+                color: #757575;
+                font-size: 12px;
+            }
+            .ivu-table-row{
+                td:nth-child(8){
+                    .ivu-table-cell{
+                        display: none;
+                    }              
+                }
+            }
+        }
+        .ivu-table-row-hover{
+            background: -webkit-linear-gradient(left,#272727,#373737);
+            background: -o-linear-gradient(right,#272727,#373737);
+            background: -moz-linear-gradient(right,#272727,#373737);
+            background: linear-gradient(to right,#272727,#373737);
+            td:last-child{
+                .ivu-table-cell{
+                    display: block!important;
+                }
+            }
+        }        
+        .ivu-checkbox-inner{
+            background-color: transparent;
+            border: 2px solid #343434;
+            border-radius: 3px;
+        }
+        .ivu-checkbox-checked .ivu-checkbox-inner:after{
+            width: 8px;
+            height: 14px;
+            top: -2px;
+            left: 4px;
+            border-color: #1eb38d;
+            border-right-width: 3px;
+            border-bottom-width: 3px;
+        }
+        .ivu-table-overflowY{
+            &::-webkit-scrollbar {
+                width: 5px;
+            }
+            &::-webkit-scrollbar-track {
+                // margin: 0px;
+                background: transparent;
+            }
+            &::-webkit-scrollbar-thumb {
+                border-radius: 10px;
+                background: #94998a;
+            }
+            &::-webkit-scrollbar-thumb:hover {
+            /* background: #555; */
+            }
+            &::-webkit-scrollbar-button {
+                display: none;
+            }
+        }
+    }
+}
+.authSetting{
+    .ivu-btn{
+        background-color: #48d2b0;
+        color: #fff;
+        border-radius: 2px;
+    }
+}
+</style>  
+
+<template>
+    <div class="userList">
+        <div class="userLists" :class="{isSetting:authMulti}">
+            <div class="serch-box">
+                <Input class="serch-inp" suffix="ios-search" :placeholder="$t('teachermgmt.blurryFilter')" v-model="blurryFilter" />
+                <Button v-if="!authMulti" class="multiSet" type="text" @click="multiSet()"><icon class="icon" icon="shield-alt" /> {{$t('teachermgmt.mulitSet')}}</Button>
+            </div>
+            <div class="userListContent">
+                <Table class="scrollstyle" :height="tableHeight" ref="selection" :columns="tableColumns" :data="tableData" @on-selection-change="setTeachers" @on-sort-change="changeSort">
+                    <template slot-scope="{ row }" slot="cellphone">
+                        <Icon v-if="row.cellphone" color="#1eb38d" size="30" type="md-checkmark" />
+                        <Icon v-else color="#c43635" size="30" type="md-close" />
+                    </template>
+                    <template slot-scope="{ row }" slot="email">
+                        <Icon v-if="row.email" color="#1eb38d" size="30" type="md-checkmark" />
+                        <Icon v-else color="#c43635" size="30" type="md-close" />
+                    </template>
+                    <template slot-scope="{ row }" slot="loginCount">
+                        {{$t('teachermgmt.table.text1')}} {{row.loginCount}} {{$t('teachermgmt.table.text2')}}
+                    </template>
+                    <template slot-scope="{ row }" slot="action">
+                        <icon icon="shield-alt" style="font-size: 14px;color: #fff;margin-right: 20px;cursor: pointer;" @click="showAuth(row)" />
+                        <icon icon="trash" style="color: #fff;font-size: 14px;cursor: pointer;" @click="removeUser(row)" />
+                    </template>
+                </Table>
+            </div>
+        </div>
+        <div class="authSetting" :class="{isSetting:authMulti}">
+            <div class="header">
+                <span class="title">{{$t('teachermgmt.authSet.title')}}</span>
+                <Icon class="icon" size="26" color="#ffffff" type="md-close" @click="closeAuthSeting()" />
+            </div>
+            <div class="users">
+                <div class="title">
+                    {{$t('teachermgmt.authSet.subTitle')}}
+                </div>
+                <div class="ids scrollstyle">
+                    <span v-for="(item, key) in TEAMModelIds" :key="key">
+                        {{item}}
+                        <span v-if="TEAMModelIds[key+1]">,</span>
+                    </span>
+                </div>
+            </div>
+            <div class="authContent scrollstyle">
+                <!-- 一種權限設定 Start -->
+                <div class="authBox">
+                    <div class="title">{{$t('teachermgmt.authSet.area1.title')}}</div>
+                    <div class="subTitle">
+                        <span>{{$t('teachermgmt.authSet.area1.read')}}</span>
+                        <i-switch :true-color="switchTrueColor" :false-color="switchFalseColor" class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                </div>
+                <!-- 一種權限設定 End -->
+                <div class="authBox">
+                    <div class="title">{{$t('teachermgmt.authSet.area1.title')}}</div>
+                    <div class="subTitle">
+                        <span>{{$t('teachermgmt.authSet.area1.read')}}</span>
+                        <i-switch :true-color="switchTrueColor" :false-color="switchFalseColor" class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                </div>
+                <div class="authBox">
+                    <div class="title">{{$t('teachermgmt.authSet.area1.title')}}</div>
+                    <div class="subTitle">
+                        <span>{{$t('teachermgmt.authSet.area1.read')}}</span>
+                        <i-switch :true-color="switchTrueColor" :false-color="switchFalseColor" class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                    <div class="detail">
+                        <span class="auth">{{$t('teachermgmt.authSet.area1.auth1')}}</span><i-switch :true-color="switchTrueColor" :false-color="switchFalseColor"  class="switch" />
+                    </div>
+                </div>
+            </div>
+            <div class="authBtn">
+                <Button size="large" style="margin-bottom: 11px;" long>{{$t('teachermgmt.authSet.reset')}}</Button>
+                <Button size="large" long>{{$t('teachermgmt.authSet.save')}}</Button>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name:'userList',
+    data() {
+        return {
+            columns: [
+                {
+                    type: 'selection',
+                    width: 60,
+                    align: 'center'
+                },
+                {
+                    title: this.$t('teachermgmt.table.th1'),
+                    width: 230,
+                    key: 'TEAMModelId',
+                    sortable: true
+                },
+                {
+                    title: this.$t('teachermgmt.table.th2'),
+                    key: 'name',
+                    sortable: true
+                },
+                {
+                    title: this.$t('teachermgmt.table.th3'),
+                    width: 150,
+                    key: 'jobTitle',
+                    sortable: true
+                },
+                {
+                    title: this.$t('teachermgmt.table.th4'),
+                    slot: 'cellphone',
+                    sortable: 'custom',
+                    show: true,
+                    align: 'center',
+                    width: 130
+                },
+                {
+                    title: this.$t('teachermgmt.table.th5'),
+                    slot: 'email',
+                    sortable: true,
+                    show: true,
+                    align: 'center',
+                    width: 130,
+                },
+                {
+                    title: this.$t('teachermgmt.table.th6'),
+                    slot: 'loginCount',
+                    sortable: true,
+                    show: true,
+                    width: 200,
+                },
+                {
+                    title: ' ',
+                    slot: 'action',
+                    width: 130,
+                    align: 'center',
+                    show: true,
+                }
+            ],
+            data: [               
+            ],
+            authMulti: false,
+            blurryFilter:'',
+            tableHeight: 100,
+            screenHeight: document.documentElement.clientHeight,//螢幕高度
+            TEAMModelIds:[],
+            multiSetMode: false,    // 多筆設定
+            teachers:[],
+            switchTrueColor: '#008f6b',
+            switchFalseColor: '#4e4d4d',
+        }
+    },
+    computed:{
+        tableData: function(){
+            let filterData = this.data
+            if(this.blurryFilter){
+                // 可以客制調整
+                filterData = this.data.filter(res => {
+                    let a = res.name.toLowerCase();
+                    let b = res.TEAMModelId.toLowerCase();
+                    return (a.indexOf(this.blurryFilter) >= 0) || (b.indexOf(this.blurryFilter) >= 0)
+                })
+            }
+            return filterData
+        },
+        tableColumns: function(){
+            let column = []
+            this.columns.forEach(res=>{
+                if(res.show){
+                    if(!this.authMulti){
+                        column.push(res)                        
+                    }
+                } else {
+                    column.push(res)
+                }
+            })
+            return column
+        }
+    },
+    watch:{
+        'screenHeight': function(val){
+            this.tableHeight = val - this.$refs.selection.$el.offsetTop - 133
+        }
+    },
+    methods: {
+        showAuth: function(val){    // 個人設定
+            console.log(val)
+            this.authMulti = true
+            this.TEAMModelIds.push(val.TEAMModelId)            
+        },
+        removeUser: function(val){
+            this.$Modal.confirm({
+                title: this.$t('teachermgmt.model.delTeacher.title'),
+                content: '<p>'+this.$t('teachermgmt.model.delTeacher.text1') + ' ' + val.name + '(' + val.TEAMModelId +') ?</p>',
+                onOk: () => {
+                    let index
+                    this.data.forEach(function(item, key){
+                        if(item.id == val.id){
+                            index = key
+                        }
+                    })
+                    this.data.splice(index, 1)
+                    this.$Message.info(this.$t('teachermgmt.message.info1'));
+                },
+                // onCancel: () => {
+                //     this.$Message.info('Clicked cancel');
+                // }
+            });
+        },
+        multiSet: function(){    // 多人設定
+            if(this.teachers.length > 0){
+                this.authMulti = true
+                this.multiSetMode = true
+                this.teachers.forEach(res => {
+                    this.TEAMModelIds.push(res.TEAMModelId)
+                })
+            } else {
+                this.$Modal.warning({
+                    title: this.$t('teachermgmt.model.warning.title'),
+                    content: this.$t('teachermgmt.model.warning.text1')
+                });
+            }            
+        },
+        setTeachers: function(val){ // 多選暫存
+            this.teachers = val
+        },
+        closeAuthSeting: function(){
+            this.multiSetMode = false
+            this.authMulti = false
+            this.TEAMModelIds = []
+        },
+        // ASC 代表結果會以由小往大的順序列出,而 DESC 代表結果會以由大往小的順序列出。
+        changeSort({column, key, order}){
+            if(column.slot === 'cellphone' || column.slot === 'email' || column.slot === 'loginCount'){
+                let data = this.data
+                this.data.sort(function(a, b){
+                    let nameA = a[column.slot]
+                    let nameB = b[column.slot]                    
+                    if(column.slot === 'cellphone' || column.slot === 'email'){
+                        nameA = a[column.slot] ? 1 : 0;
+                        nameB = b[column.slot] ? 1 : 0;
+                    }
+
+                    switch (order) {
+                        case 'asc':
+                            return nameA - nameB;
+                            break;
+                        case 'desc':
+                            return nameB - nameA;
+                            break;                        
+                    }                    
+                })
+            }
+        }
+    },
+    created(){
+        this.$api.teachMgmt.GetTeacherList().then(res => {
+            this.data = res.data
+        })
+    },
+    mounted() {
+        this.tableHeight = window.innerHeight - this.$refs.selection.$el.offsetTop - 133 // 預設表格初始高度
+        var _this = this;
+            window.onresize = function(){ // 定義視窗大小變更通知事件
+            _this.screenHeight = document.documentElement.clientHeight; //視窗高度
+        }
+    }
+}
+</script>

+ 0 - 69
TEAMModelOS/ClientApp/src/view/teachermgmt/menu/accountmgmt/Index.less

@@ -1,69 +0,0 @@
-#accountMgmt{    
-    width: 100%;
-    height: 100%;
-    color: #fff;
-    overflow-x: auto;
-    overflow-y: hidden;
-    .main{
-        white-space: nowrap;
-        display: -webkit-box;
-        display: -ms-flexbox;
-        display: flex;
-        height:100%;
-        .pane{
-            height: 100%;
-            padding:10px;
-            background-color: #282828;
-            border:1px solid #666;
-            position: relative;
-            z-index:10;
-            box-shadow: 2px 0 2px 0px rgba(81, 90, 110, 0.5);
-            .title{
-                height:5%;
-            }
-            .head{
-                border-bottom: 1px solid rgb(148, 153, 138);
-                padding-bottom: 10px                
-            }
-            .conet{
-                overflow: auto;
-                height: 94%;
-                width: 100%;
-                .user{
-                    &:hover, &.active{
-                        background: -webkit-linear-gradient(right, rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: -o-linear-gradient(right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: -moz-linear-gradient(right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: linear-gradient(to right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                    }
-                    padding: 15px 10px 10px 25px;
-                    background-color: #66666629;
-                    cursor: pointer;
-                    margin-bottom:5px;
-                    .box{
-                        height: 50px;
-                        .name{
-                            h3{
-                                font-size: 1.5em
-                            }
-                            span{
-                                font-size: 1em;color: #dcdee2;
-                            }
-                        }
-                        .nickName{
-                            span{
-                                font-size: 1em
-                            }
-                        }
-                        .play{
-                            text-align: right;
-                        }
-                    }
-                }
-            }
-        }
-        .pane-z-index-1{
-            z-index:1;
-        }
-    }
-}

+ 0 - 187
TEAMModelOS/ClientApp/src/view/teachermgmt/menu/accountmgmt/Index.vue

@@ -1,187 +0,0 @@
-<style lang="less" scoped>
-  @import './Index.less';
-</style>
-
-<template>
-  <div id="accountMgmt">
-    <Row class="main">
-      <Col class="pane" :span="7" style="z-index: 11;">
-        <Row class="head">
-            <Col :span="14">
-              <Row :gutter="10">
-                  <Col :span="5">
-                      <Button @click="addTeacher = true" icon="md-add" style="margin-right: 5px;" />
-                  </Col>
-                  <Col :span="19">
-                      <Input v-model="filterName" suffix="ios-search" placeholder="ID / Name" />
-                  </Col>
-              </Row>
-            </Col>
-            <Col :span="10">
-                <a style="color:#fff;float: right;"  @click="closeBtn()"><Icon size="17" type="md-close" /></a>
-            </Col>
-        </Row>
-        <div class="conet scrollstyle">
-            <div v-for="(user, index) in filterLists" :key="index" class="user">
-                <Row class="box" type="flex" justify="center" align="middle">
-                    <Col class="name" :span="8">
-                        <h3>{{user.id}}</h3>
-                        <span>{{user.name}}</span>
-                    </Col>
-                    <Col class="nickName" :span="8"><span>{{user.nickName}}</span></Col>
-                    <Col class="play" :span="8">
-                        <Button @click="delTeacher(user.name)" size="small">刪除</Button>
-                    </Col>
-                </Row>
-            </div>
-        </div>
-      </Col>
-      <transition name="leftInOut">
-      <Col v-if="addTeacher" class="pane" :span="5">
-        <Row style="border-bottom: 1px solid #94998a;padding-bottom: 10px;    min-height: 44px;">
-            <Col :span="12">
-              <h3>
-                  是否讓以下的老師加入:
-                  <!-- 老師加入後給予預設的權限 -->
-              </h3>
-            </Col>
-            <Col :span="12">
-              <a style="color:#fff;float: right;"  @click="addTeacher = false"><Icon size="17" type="md-close" /></a>
-            </Col>
-        </Row>
-        <Row class="scrollstyle"  style="margin-top: 10px;overflow: auto;height: 88%;">
-            <Col>
-                <div style="padding: 15px 10px 10px 15px;background-color: #66666629;;cursor: pointer;margin-bottom: 5px;">
-                  <h3>JEFF-<small>JEFF#1234</small></h3>
-                    <RadioGroup>
-                      <Radio true-value="01" label="通過"></Radio>
-                      <Radio true-value="10" label="拒絕"></Radio>
-                  </RadioGroup>
-                </div>
-                <div style="padding: 15px 10px 10px 15px;background-color: #66666629;cursor: pointer;margin-bottom: 5px;">
-                  <h3>Mickey-<small>Mikey#1234</small></h3>
-                  <RadioGroup>
-                      <Radio true-value="01" label="通過"></Radio>
-                      <Radio true-value="10" label="拒絕"></Radio>
-                  </RadioGroup>
-                </div>
-            </Col>
-        </Row>
-        <Row >
-            <Col style="text-align: right;">
-                <Button>確定</Button>
-            </Col>
-        </Row>
-      </Col>
-      </transition>
-    </Row>
-  </div>
-</template>
-
-<script>
-
-export default {
-  data() {
-    return {
-      deleteID: '',
-      addTeacher: false,
-      filterName: '',
-      userList: [ // UserLIST
-        {
-          id: 'Osbert#1234',
-          name: '歐斯柏',
-          nickName: '老師',
-          authList: [
-            {
-              path: '/smartschooldashboard',
-              component: 'smartschooldashboard',
-              access: { // 小組件權限
-                'fun1': true,
-                'fun2': false
-              },
-              permissions: true // true: 有權訪問, false: 無權訪問
-            },
-            {
-              path: '/smartclassdashboard',
-              component: 'smartclassdashboard',
-              access: { // 小組件權限
-                'fun1': true,
-                'fun2': false
-              },
-              permissions: true // true: 有權訪問, false: 無權訪問
-            },
-            {
-              path: '/guidelines',
-              component: 'guidelines',
-              access: { // 小組件權限
-                'fun1': true,
-                'fun2': false
-              },
-              permissions: true // true: 有權訪問, false: 無權訪問
-            }
-          ]
-        },
-        {
-          id: 'James#1234',
-          name: '詹姆士',
-          nickName: '老師',
-          authList: [
-            {
-              path: '/smartschooldashboard', // 頁面
-              component: 'smartschooldashboard', // 組件名
-              access: { // 小組件權限
-                'fun1': false,
-                'fun2': false
-              },
-              permissions: true // true: 有權訪問, false: 無權訪問
-            },
-            {
-              path: '/smartclassdashboard',
-              component: 'smartclassdashboard',
-              access: { // 小組件權限
-                'fun1': true,
-                'fun2': false
-              },
-              permissions: true // true: 有權訪問, false: 無權訪問
-            },
-            {
-              path: '/guidelines',
-              component: 'guidelines',
-              access: { // 小組件權限
-                'fun1': false,
-                'fun2': false
-              },
-              permissions: false // true: 有權訪問, false: 無權訪問
-            }
-          ]
-        }
-      ]
-    }
-  },
-  computed: {
-    filterLists: function() {
-    // 通通轉小寫比對。
-    let filterName = this.filterName.toLowerCase()
-
-    return (filterName.trim() !== '')
-        ? this.userList.filter(function(d) { return (d.name.toLowerCase().indexOf(filterName) > -1 || d.id.toLowerCase().indexOf(filterName) > -1) })
-        : this.userList
-    }
-  },
-  methods: {
-    closeBtn: function() {
-      this.$emit('closeComp', '')
-    },
-    delTeacher: function(name) {
-      this.$Modal.confirm({
-        title: '刪除確認',
-        content: '<p>請問是否要刪除 ' + name + '</p>',
-        onOk: () => {
-        },
-        onCancel: () => {
-        }
-      })
-    }
-  }
-}
-</script>

+ 0 - 111
TEAMModelOS/ClientApp/src/view/teachermgmt/menu/authorization/Index.less

@@ -1,111 +0,0 @@
-#authMgmt{    
-    .list-group {
-        display: -ms-flexbox;
-        display: -webkit-box;
-        display: flex;
-        -ms-flex-direction: column;
-        -webkit-box-orient: vertical;
-        -webkit-box-direction: normal;
-        flex-direction: column;
-        padding-left: 0;
-        margin-bottom: 0;
-    }
-    .list-group-item:first-child {
-        border-top-left-radius: .25rem;
-        border-top-right-radius: .25rem;
-    }
-    .list-group-item {
-        position: relative;
-        display: block;
-        padding: .75rem 1.25rem;
-        margin-bottom: -1px;
-        background-color: #fff;
-        color: #333;
-        border: 1px solid rgba(0,0,0,.125);
-    }
-    .list-group-item {
-        cursor: move;
-    }
-
-    width: 100%;
-    height: 100%;
-    color: #fff;
-    overflow-x: auto;
-    overflow-y: hidden;
-    .main{
-        white-space: nowrap;
-        display: -webkit-box;
-        display: -ms-flexbox;
-        display: flex;
-        height:100%;
-        .pane{
-            height: 100%;
-            padding:10px;
-            background-color: #282828;
-            border:1px solid #666;
-            position: relative;
-            z-index:10;
-            .title{
-                height:5%;
-            }
-            .head{
-                border-bottom: 1px solid rgb(148, 153, 138);
-                padding-bottom: 10px                
-            }
-            .conet{
-                overflow: auto;
-                height: 94%;
-                width: 100%;
-                .user{
-                    &:hover, &.active{
-                        background: -webkit-linear-gradient(right, rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: -o-linear-gradient(right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: -moz-linear-gradient(right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: linear-gradient(to right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                    }
-                    padding: 15px 10px 10px 25px;
-                    background-color: #66666629;
-                    cursor: pointer;
-                    margin-bottom:5px;
-                    .box{
-                        height: 50px;
-                        .name{
-                            h3{
-                                font-size: 1.5em
-                            }
-                            span{
-                                font-size: 1em;color: #dcdee2;
-                            }
-                        }
-                        .nickName{
-                            span{
-                                font-size: 1em
-                            }
-                        }
-                        .play{
-                            text-align: right;
-                        }
-                    }
-                }
-            }
-            .listRow{
-                .listItem{
-                    padding: 15px 10px 10px 15px;
-                    background-color: #66666629;
-                    cursor: pointer;
-                    margin-bottom: 5px;
-                    text-align:center;
-                    &:hover, &.active{
-                        background: -webkit-linear-gradient(right, rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: -o-linear-gradient(right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: -moz-linear-gradient(right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: linear-gradient(to right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                    }
-                }
-            }
-        }
-        .pane-z-index-1{
-            z-index:1;
-        }
-    }
-}

+ 0 - 454
TEAMModelOS/ClientApp/src/view/teachermgmt/menu/authorization/Index.vue

@@ -1,454 +0,0 @@
-<style lang="less" scoped>
-  @import './Index.less';
-</style>
-
-<template>
-  <div id="authMgmt">
-    <Row class="main">
-        <Col v-if="mainPane" class="pane" :span="7">
-            <Row class="head">
-                <Col :span="14">
-                    <Row :gutter="10">
-                        <Col :span="19">
-                            <Input v-model="filterName" suffix="ios-search" placeholder="ID / Name" />
-                        </Col>
-                        <Col :span="5">
-                            <Button @click="batchSwitch()" icon="ios-photos"/>
-                        </Col>
-                    </Row>
-                </Col>
-                <Col :span="10">
-                    <a style="color:#fff;float: right;"  @click="closeAuth()"><Icon size="17" type="md-close" /></a>
-                </Col>
-            </Row>
-            <div class="conet scrollstyle">
-                <div v-for="(user, index) in filterLists" :key="index" class="user" :class="{ 'active': user.id === userSelect }" @click="userAuthSeting(user.id)">
-                    <Row class="box" type="flex" justify="center" align="middle">
-                        <Col class="name" :span="8">
-                            <h3>{{user.id}}</h3>
-                            <span>{{user.name}}</span>
-                        </Col>
-                        <Col class="nickName" :span="8"><span>{{user.nickName}}</span></Col>
-                        <Col class="play" :span="8"><Icon size="20" type="md-play" /></Col>
-                    </Row>
-                </div>
-            </div>
-        </Col>
-        <transition name="leftInOut">
-            <Col class="pane"  style=" z-index:9;" v-if="userPane" :span="5">
-                <Row style="border-bottom: 1px solid #94998a;padding-bottom: 10px;    min-height: 44px;">
-                    <Col :span="12">
-                        <h3>
-                            {{userAuth.name}}
-                            <small>{{userAuth.id}}</small>
-                        </h3>
-                    </Col>
-                    <Col :span="12">
-                        <a style="color:#fff;float: right;"  @click="closeBtn()"><Icon size="17" type="md-close" /></a>
-                    </Col>
-                </Row>
-                <Row style="margin-top: 10px;">
-                    <Col :span="21">
-                        <Input size="small">
-                            <span slot="prepend">稱謂</span>
-                        </Input>
-                    </Col>
-                    <Col :span="3" style="text-align: right;">
-                        <Button size="small" icon="md-copy" @click="copyUserAuthFlag = true"></Button>
-                    </Col>
-                </Row>
-                <Row class="scrollstyle"  style="margin-top: 10px;overflow: auto;height: 84%;">
-                    <Col v-for="(item, authKey) in userAuth.authList" :key="authKey">
-                        <div style="padding: 15px 10px 10px 25px;background-color: #66666629;cursor: pointer;margin-bottom: 5px;">
-                            <Checkbox v-model="item.permissions"> {{item.path}}</Checkbox>
-                        </div>
-                        <transition name="leftInOut">
-                            <div v-if="item.permissions == 1">
-                                <ul style="margin-left: 15px;list-style-type: none;">
-                                    <li v-for="(value, name) in item.access">
-                                        <div style="padding: 15px 10px 10px 25px;background-color: #66666629;cursor: pointer;margin-bottom: 5px;">
-                                            <Checkbox v-model="item.access[name]">{{ name }}</Checkbox>
-                                        </div>
-                                    </li>
-                                </ul>
-                            </div>
-                        </transition>
-                    </Col>
-                </Row>
-                <Row >
-                    <Col style="text-align: right;">
-                        <Button>確定</Button>
-                    </Col>
-                </Row>
-                <Spin size="large" fix v-if="authSpin">
-                    <Icon type="ios-loading" size=18 class="spin-icon-load"></Icon>
-                    <div>Loading</div>
-                </Spin>
-            </Col>
-        </transition>
-        <transition name="leftInOut">
-            <Col class="pane" style=" z-index:8;" v-if="copyUserAuthFlag" :span="4">
-                <Row style="border-bottom: 1px solid #94998a;padding-bottom: 10px;    min-height: 44px;">
-                    <Col :span="12">
-                        <h3>權限複製</h3>
-                    </Col>
-                    <Col :span="12">
-                        <a style="color:#fff;float: right;"  @click="copyUserAuthFlag = false"><Icon size="17" type="md-close" /></a>
-                    </Col>
-                </Row>
-                <Row style="margin-top: 10px;">
-                    <Col>
-                        <Input v-model="filterNameBycopy" suffix="ios-search" placeholder="ID / Name" />
-                    </Col>
-                </Row>
-                <Row class="scrollstyle listRow"  style="margin-top: 10px;overflow: auto;height: 88%;">
-                    <Col v-for="(item, key) in filterCopyName" :key="key">
-                        <div class="listItem" @click="copyAuth(item.id, item.name)">
-                            {{item.name}}
-                        </div>
-                    </Col>
-                </Row>
-            </Col>
-        </transition>
-        <transition name="leftInOut">
-            <Col v-if="batchPane" class="pane" style=" z-index:8;" :span="12">
-                <Row style="border-bottom: 1px solid #94998a;padding-bottom: 10px;min-height: 44px;">
-                    <Col :span="12">
-                        <h3>批次設定</h3>
-                    </Col>
-                    <Col :span="12">
-                        <a style="color:#fff;float: right;"  @click="batchSwitch"><Icon size="17" type="md-close" /></a>
-                    </Col>
-                </Row>
-                <Row style="height: 90%;">
-                    <Col :span="8" style="height: 100%;padding: 10px;border-right: 1px solid #94998a;">
-                        <div style="height: 10%;">
-                            <h3>權限</h3>
-                        </div>
-                        <Row class="scrollstyle"  style="margin-top: 10px;overflow: auto;height: 84%;">
-                            <Col v-for="(item, authKey) in basicAuth" :key="authKey">
-                                <div style="padding: 15px 10px 10px 25px;background-color: #66666629;cursor: pointer;margin-bottom: 5px;">
-                                    <Checkbox v-model="item.permissions"> {{item.path}}</Checkbox>
-                                </div>
-                                <transition name="leftInOut">
-                                    <div v-if="item.permissions == 1">
-                                        <ul style="margin-left: 15px;list-style-type: none;">
-                                            <li v-for="(value, name) in item.access">
-                                                <div style="padding: 15px 10px 10px 25px;background-color: #66666629;cursor: pointer;margin-bottom: 5px;">
-                                                    <Checkbox v-model="item.access[name]">{{ name }}</Checkbox>
-                                                </div>
-                                            </li>
-                                        </ul>
-                                    </div>
-                                </transition>
-                            </Col>
-                        </Row>
-                    </Col>
-                    <Col :span="8" style="height: 100%;padding: 10px;">
-                        <div style="height: 10%;">
-                            <h3>老師列表</h3>
-                            <Input v-model="filterName" suffix="ios-search" placeholder="ID / Name" style="margin: 10px 0px;" />
-                        </div>
-                        <draggable :list="userList" group="people" @change="log" class="conet scrollStyle" style="border: 1px solid #fefefe;padding: 10px;height: 90%;padding: 10px;    border-radius: 10px;">
-                            <div
-                            class="user"
-                            v-for="(element, index) in filterLists"
-                            :key="element.name"
-                            >
-                            {{ element.name }} {{ index }}
-                            </div>
-                        </draggable>
-                    </Col>
-                    <Col :span="8" style="height: 100%;padding: 10px;">
-                        <div style="height: 10%;">
-                            <h3>要修改的老師</h3>
-                        </div>
-                        <draggable :list="list2" group="people" @change="log" class="conet" style="border: 1px solid #fefefe;padding: 10px;height: 90%;padding: 10px;    border-radius: 10px;">
-                            <div
-                            class="user"
-                            v-for="(element, index) in list2"
-                            :key="element.name"
-                            >
-                            {{ element.name }} {{ index }}
-                            </div>
-                        </draggable>
-                    </Col>
-                </Row>
-                <Row >
-                    <Col style="text-align: right;">
-                        <Button>確定</Button>
-                    </Col>
-                </Row>
-            </Col>
-        </transition>
-    </Row>
-  </div>
-</template>
-
-<script>
-import draggable from 'vuedraggable'
-
-export default {
-    components: {
-        draggable
-    },
-    data() {
-    return {
- list1: [
-        { name: 'John', id: 1 },
-        { name: 'Joao', id: 2 },
-        { name: 'Jean', id: 3 },
-        { name: 'Gerard', id: 4 }
-      ],
-      list2: [
-
-      ],
-
-        mainPane: true,
-        batchPane: false,
-        copyUserAuthFlag: false,
-        filterName: '',
-        filterNameBycopy: '',
-        userSelect: '', // 被點選的人
-        userPane: '', // 啟動的功能頁紀錄
-        authSpin: false, // 權限頁Spin
-        userList: [ // UserLIST
-            {
-                id: 'Osbert#1234',
-                name: '歐斯柏',
-                nickName: '老師',
-                authList: [
-                    {
-                        path: '/smartschooldashboard',
-                        component: 'smartschooldashboard',
-                        access: { // 小組件權限
-                            'fun1': true,
-                            'fun2': false
-                        },
-                        permissions: true // true: 有權訪問, false: 無權訪問
-                    },
-                    {
-                        path: '/smartclassdashboard',
-                        component: 'smartclassdashboard',
-                        access: { // 小組件權限
-                            'fun1': true,
-                            'fun2': false
-                        },
-                        permissions: true // true: 有權訪問, false: 無權訪問
-                    },
-                    {
-                        path: '/guidelines',
-                        component: 'guidelines',
-                        access: { // 小組件權限
-                            'fun1': true,
-                            'fun2': false
-                        },
-                        permissions: true // true: 有權訪問, false: 無權訪問
-                    }
-                ]
-            },
-            {
-                id: 'James#1234',
-                name: '詹姆士',
-                nickName: '老師',
-                authList: [
-                    {
-                        path: '/smartschooldashboard', // 頁面
-                        component: 'smartschooldashboard', // 組件名
-                        access: { // 小組件權限
-                            'fun1': false,
-                            'fun2': false
-                        },
-                        permissions: true // true: 有權訪問, false: 無權訪問
-                    },
-                    {
-                        path: '/smartclassdashboard',
-                        component: 'smartclassdashboard',
-                        access: { // 小組件權限
-                            'fun1': true,
-                            'fun2': false
-                        },
-                        permissions: true // true: 有權訪問, false: 無權訪問
-                    },
-                    {
-                        path: '/guidelines',
-                        component: 'guidelines',
-                        access: { // 小組件權限
-                            'fun1': false,
-                            'fun2': false
-                        },
-                        permissions: false // true: 有權訪問, false: 無權訪問
-                    }
-                ]
-            },
-            {
-                id: 'Mickey#2345',
-                name: '米奇',
-                nickName: '老師',
-                authList: [
-                    {
-                        path: '/smartschooldashboard', // 頁面
-                        component: 'smartschooldashboard', // 組件名
-                        access: { // 小組件權限
-                            'fun1': false,
-                            'fun2': false
-                        },
-                        permissions: false // true: 有權訪問, false: 無權訪問
-                    },
-                    {
-                        path: '/smartclassdashboard',
-                        component: 'smartclassdashboard',
-                        access: { // 小組件權限
-                            'fun1': false,
-                            'fun2': false
-                        },
-                        permissions: false // true: 有權訪問, false: 無權訪問
-                    },
-                    {
-                        path: '/guidelines',
-                        component: 'guidelines',
-                        access: { // 小組件權限
-                            'fun1': false,
-                            'fun2': false
-                        },
-                        permissions: false // true: 有權訪問, false: 無權訪問
-                    }
-                ]
-            }
-        ],
-        userAuth: { // 使用者個人權限顯示
-            id: '',
-            name: '',
-            nickName: '',
-            authList: []
-        },
-        basicAuth: [
-            {
-                path: '/smartschooldashboard', // 頁面
-                component: 'smartschooldashboard', // 組件名
-                access: { // 小組件權限
-                    'fun1': false,
-                    'fun2': false
-                },
-                permissions: false // true: 有權訪問, false: 無權訪問
-            },
-            {
-                path: '/smartclassdashboard',
-                component: 'smartclassdashboard',
-                access: { // 小組件權限
-                    'fun1': false,
-                    'fun2': false
-                },
-                permissions: false // true: 有權訪問, false: 無權訪問
-            },
-            {
-                path: '/guidelines',
-                component: 'guidelines',
-                access: { // 小組件權限
-                    'fun1': false,
-                    'fun2': false
-                },
-                permissions: false // true: 有權訪問, false: 無權訪問
-            }
-        ]
-
-    }
-  },
-  computed: {
-    filterLists: function() {
-    // 通通轉小寫比對。
-    let filterName = this.filterName.toLowerCase()
-
-    return (filterName.trim() !== '')
-        ? this.userList.filter(function(d) { return (d.name.toLowerCase().indexOf(filterName) > -1 || d.id.toLowerCase().indexOf(filterName) > -1) })
-        : this.userList
-    },
-    filterCopyName: function() {
-        let _this = this
-        let newList = this.userList.filter(function(item) {
-            return (item.id != _this.userAuth.id)
-        })
-        // 通通轉小寫比對。
-        let filterName = this.filterNameBycopy.toLowerCase()
-
-        return (filterName.trim() !== '')
-        ? newList.filter(function(d) { return (d.name.toLowerCase().indexOf(filterName) > -1 || d.id.toLowerCase().indexOf(filterName) > -1) })
-        : newList
-    }
-  },
-  methods: {
-    closeBtn: function() {
-        this.userPane = false
-        this.userSelect = ''
-        this.copyUserAuthFlag = false
-    },
-    sleep: function(time) {
-        return new Promise((resolve) => setTimeout(resolve, time))
-    },
-    userAuthSeting: async function(id) {
-        this.userPane = true
-        this.authSpin = true
-        await this.sleep(2000)
-        let auth = this.userList.find(function(item) {
-            return item.id == id
-        })
-        this.userAuth.id = auth.id
-        this.userAuth.name = auth.name
-        this.userAuth.nickName = auth.nickName
-        this.userAuth.authList = auth.authList
-        this.authSpin = false
-    },
-    closeAuth: function() {
-        this.$emit('closeComp', '')
-    },
-    copyAuth: function(id, name) {
-        this.$Modal.confirm({
-            title: '複製確認',
-            content: '<p>請問是否要複製 ' + name + ' 的權限</p>',
-            onOk: () => {
-                let user = this.userList.filter(function(item) {
-                    return (item.id == id)
-                })
-                this.userAuth.authList = user[0].authList
-            },
-            onCancel: () => {
-            }
-        })
-    },
-    batchSwitch: function() {
-        this.filterName = ''
-        this.batchPane = !this.batchPane
-        this.mainPane = !this.mainPane
-        this.copyUserAuthFlag = false
-        this.userPane = false
-    },
-
-     add: function() {
-      this.list.push({ name: 'Juan' })
-    },
-    replace: function() {
-      this.list = [{ name: 'Edgard' }]
-    },
-    clone: function(el) {
-      return {
-        name: el.name + ' cloned'
-      }
-    },
-    log: function(evt) {
-      window.console.log(evt)
-    }
-  }
-}
-</script>
-<style scoped>
-.leftInOut-enter-active, .leftInOut-leave-active {
-    transition: all 0.7s;
-}
-.leftInOut-enter, .leftInOut-leave-to /* .list-leave-active below version 2.1.8 */ {
-    opacity: 0;
-    transform: translateX(-150px);
-}
-.spin-icon-load{
-    animation: ani-demo-spin 1s linear infinite;
-}
-</style>

+ 46 - 33
TEAMModelOS/Controllers/Learn/HomeWorkController.cs

@@ -29,46 +29,73 @@ namespace TEAMModelOS.Controllers.Learn
             _cosmos = cosmos;
         }
 
-
         /// <summary>
-        /// 新增或修改 作业活动 同时创建关联关系表
+        /// 撤消作业
         /// </summary>
         /// <param name="request"></param>
         /// <returns></returns>
-        [HttpPost("SaveorUpdataHomeWork")]
-        public async Task<BaseJosnRPCResponse> SaveorUpdataHomeWork(JosnRPCRequest<HomeWork> request)
+        [HttpPost("RevokeHomeWork")]
+        public async Task<BaseJosnRPCResponse> RevokeHomeWork(JosnRPCRequest<string> homeWorkId) 
         {
             JsonRPCResponseBuilder builder = JsonRPCResponseBuilder.custom();
+            List<HomeWork> homeWorks = await _cosmos.FindByDict<HomeWork>(new Dictionary<string, object> { { "id", homeWorkId.@params } });
 
-            if (request.@params.publishModel.Equals("0"))
+            foreach (HomeWork homeWork in homeWorks) 
             {
-                request.@params.startTime = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
+                homeWork.state = 100;
+            }
+            List<HomeWork> homeWorks1 = await _cosmos.UpdateAll<HomeWork>(homeWorks);
 
+            //查询之前是否有 关联关系表 HomeWorkStudent 有则删除
+            List<HomeWorkStudent> homeWorkStudents = await _cosmos.FindByDict<HomeWorkStudent>(new Dictionary<string, object> { { "homeWorkId", homeWorkId.@params } });
+            if (homeWorkStudents.IsNotEmpty())
+            {
+                await _cosmos.DeleteAll(homeWorkStudents);
             }
-            bool flg = false; 
+            return builder.Data(homeWorks1).build();
+        }
 
 
+        /// <summary>
+        /// 新增或修改 作业活动 同时创建关联关系表
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [HttpPost("SaveorUpdataHomeWork")]
+        public async Task<BaseJosnRPCResponse> SaveorUpdataHomeWork(JosnRPCRequest<HomeWorkDto> request)
+        {
+            JsonRPCResponseBuilder builder = JsonRPCResponseBuilder.custom();
             //新增
-            if (string.IsNullOrEmpty(request.@params.id)) {
-
-                request.@params.id = Guid.NewGuid().ToString();
-
-                flg = true;
+            if (string.IsNullOrEmpty(request.@params.homeWork.id))
+            {
+                request.@params.homeWork.id = Guid.NewGuid().ToString();
+                request.@params.homeWork.state = 100;
             }
 
-            //重新发布
-
-
-            HomeWork homeWork = await _cosmos.SaveOrUpdate<HomeWork>(request.@params);
+            if (request.@params.homeWork.publishModel.Equals("0"))
+            {
+                request.@params.homeWork.startTime = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
+                request.@params.homeWork.state = 200;
+            }
+            HomeWork homeWork = await _cosmos.SaveOrUpdate<HomeWork>(request.@params.homeWork);
 
-            if (flg)
+            if (!request.@params.reset)
             {
+
+              
                 //根据作业发布对象查找到每一个具体学生生成关联关系表 HomeWorkStudent
-                List<Target> targets = request.@params.target;
+                List<Target> targets = request.@params.homeWork.target;
                 List<ClassroomStudent> Classrooms = new List<ClassroomStudent>();
                 List<HomeWorkStudent> homeWorkStudents = new List<HomeWorkStudent>();
                 foreach (Target target in targets)
                 {
+                    //查询之前是否有 关联关系表 HomeWorkStudent 有则删除
+                    List<HomeWorkStudent> homeWorks = await _cosmos.FindByDict<HomeWorkStudent>(new Dictionary<string, object> { { "homeWorkId", request.@params.homeWork.id } });
+                    if (homeWorks.IsNotEmpty()) 
+                    {
+                      await _cosmos.DeleteAll(homeWorks);
+                    }
+
                     List<ClassroomStudent> classroom = await _cosmos.FindByDict<ClassroomStudent>(new Dictionary<string, object> { { "id", target.classroomCode }, { "scopeCode", target.scopeCode } });
 
                     if (classroom.IsNotEmpty())
@@ -77,14 +104,13 @@ namespace TEAMModelOS.Controllers.Learn
                         {
                             HomeWorkStudent homeWorkStudent = new HomeWorkStudent();
                             homeWorkStudent.id = studentid;
-                            homeWorkStudent.homeWorkId = request.@params.id;
+                            homeWorkStudent.homeWorkId = request.@params.homeWork.id;
                             homeWorkStudent.studentId = studentid;
                             homeWorkStudent.classroom.code = target.classroomCode;
                             homeWorkStudent.classroom.name = target.classroomName;
                             homeWorkStudents.Add(homeWorkStudent);
                         }
                     }
-
                 }
                 if (homeWorkStudents.IsNotEmpty())
                 {
@@ -102,21 +128,8 @@ namespace TEAMModelOS.Controllers.Learn
                     await _cosmos.SaveOrUpdateAll<HomeWorkStudent>(homeWorkStudents);
                 }
             }
-            //else {
-            //    List<Target> targets = request.@params.target;
-            //    foreach (Target target in targets) { 
-            //        List<HomeWorkStudent> classroom = await _cosmos.FindByDict<HomeWorkStudent>(new Dictionary<string, object> { { "id", target.classroomCode }, { "scopeCode", target.scopeCode } });
-
-
-
-            //    }
 
 
-
-
-            //}
-           
-
             return builder.Data(homeWork).build();
         }
 

+ 165 - 25
TEAMModelOS/Controllers/Test/TestAPIController.cs

@@ -3,49 +3,169 @@ using System.Net.Http;
 using Microsoft.AspNetCore.Mvc;
 using Newtonsoft.Json.Linq;
 using System.Threading.Tasks;
-using System.Text;
-using System.Net;
+using TEAMModelOS.SDK.Module.AzureCosmosDB.Interfaces;
+using System.Linq;
+using Microsoft.Azure.Documents.Client;
+using System.Collections.Generic;
+using Microsoft.WindowsAzure.Storage.Table;
+using Microsoft.WindowsAzure.Storage;
 using Newtonsoft.Json;
+using TEAMModelOS.SDK.Extension.DataResult.JsonRpcRequest;
+using TEAMModelOS.SDK.Extension.DataResult.JsonRpcResponse;
 
 namespace TEAMModelOS.Controllers.Test
 {
     [Route("api/[controller]")]
     public class TestAPIController : ControllerBase
     {
-        [HttpGet("[action]")]
-        public async Task<JObject> GetTestData()
+        public static DocumentClient DocumentClient;
+
+        public TestAPIController()
         {
-            var httpClient = new HttpClient();
-            var response = await httpClient.GetAsync("https://ies.habook.com.cn/cms/osbert/api2/json?id=1");
+            InitializeDocumentClient();
+        }
 
-            //will throw an exception if not successful
-            response.EnsureSuccessStatusCode();
+        [HttpPost("[action]")]
+        public JObject Login([FromBody]JObject data)
+        {            
+            String TMID = data.Value<string>("TMID");
+            String SchoolCode = data.Value<string>("SchoolCode");
 
-            string content = await response.Content.ReadAsStringAsync();
-            return await Task.Run(() => JObject.Parse(content));
+            JObject jObject = new JObject();
+            FeedOptions queryOptions = new FeedOptions { MaxItemCount = -1, MaxDegreeOfParallelism = -1, EnableCrossPartitionQuery = true };
+            IQueryable<JObject> queryInSql = DocumentClient.CreateDocumentQuery<JObject>(
+                UriFactory.CreateDocumentCollectionUri("OS", "SchoolSystem"), $"SELECT * FROM c WHERE c.id = 'schoolAuth' and c.schoolCode = '" + SchoolCode + "'", queryOptions);
+            foreach (JObject q in queryInSql)
+            {
+                jObject = q;
+            }
+
+            JArray roles = new JArray();
+            JArray permissions = new JArray();
+
+            JObject ORoles = jObject.Value<JObject>("role");
+            JObject OPermissions = jObject.Value<JObject>("permissions");
+
+            foreach (var ORole in ORoles)
+            {
+                if (ORole.Value.ToString().Contains(TMID))
+                {
+                    roles.Add(ORole.Key);
+                }
+            }
+
+            foreach (var OAccess in OPermissions)
+            {
+                if (OAccess.Value.ToString().Contains(TMID))
+                {
+                    permissions.Add(OAccess.Key);
+                }
+            }
+
+            JObject res = new JObject
+            {
+                { "roles", roles },
+                { "permissions", permissions }
+            };
+
+
+            return res;
         }
 
+        // 取得權限頁面設定
         [HttpGet("[action]")]
-        public async Task<JObject> GetTestAuth()
+        public JArray GetAccessPathTable()
+        {
+            String tableName = "rolePerimissions";
+            String pathSetting = "role";
+            var ret = Get<Secrets>(tableName, pathSetting, null).Result;
+
+            JArray accessPath = new JArray();
+            foreach (Secrets data in ret)
+            {
+                String str = JsonConvert.SerializeObject(data);
+                accessPath.Add(JObject.Parse(str));
+            }
+
+            return accessPath;
+        }
+
+        private CloudTable InitCloudTable(string tableName)
         {
-            string auth = @"{
-                'data':[
+            var cloudStorageAccount = CloudStorageAccount.Parse("AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;");
+            CloudTableClient tableClient = cloudStorageAccount.CreateCloudTableClient();
+            CloudTable cloudTable = tableClient.GetTableReference(tableName);
+            return cloudTable;
+        }
+
+        public async Task<List<T>> Get<T>(string tableName, string partitionKey, string rowKey) where T : ITableEntity, new()
+        {
+            string filter = String.Empty;
+
+            var result = new List<T>();
+
+            switch (0)
+            {
+                case 0:
+                    if (String.IsNullOrWhiteSpace(partitionKey) && String.IsNullOrWhiteSpace(rowKey)) return result;
+                    goto case 1;
+                case 1:
+                    if (String.IsNullOrWhiteSpace(partitionKey) && !String.IsNullOrWhiteSpace(rowKey))
+                    {
+                        filter = TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, rowKey);
+                        break;
+                    }
+                    goto case 2;
+                case 2:
+                    if (!String.IsNullOrWhiteSpace(partitionKey) && String.IsNullOrWhiteSpace(rowKey))
                     {
-                        'path': '/smartschooldashboard',
-                        'component': 'smartschooldashboard',
-                        'access':{
-                            'fun1': true,
-                            'fun2': false
-                        },
+                        filter = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey);
+                        break;
                     }
-                ]
-            }";
+                    goto case 3;
+                case 3:
+                    string filterA = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey);
+                    string filterB = TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, rowKey);
+                    filter = TableQuery.CombineFilters(filterA, TableOperators.And, filterB);
+                    break;
+            }
+
+            TableQuery<T> tableQuery = new TableQuery<T>().Where(filter);
 
-            return await Task.Run(() => JObject.Parse(auth));
+            TableContinuationToken tableContinuationToken = null;
+            do
+            {
+                var queryResponse = await InitCloudTable(tableName).ExecuteQuerySegmentedAsync(tableQuery, tableContinuationToken);
+                tableContinuationToken = queryResponse.ContinuationToken;
+                result.AddRange(queryResponse.Results);
+            } while (tableContinuationToken != null);
+            return result;
         }
 
-        [HttpGet("[action]/{schoolShortCode}")]
-        public async Task<JObject> GetTestIoTData(string schoolShortCode)
+        private void InitializeDocumentClient()
+        {
+            var uri = new Uri("https://localhost:8081"); // 測試站
+            //var uri = new Uri("https://teammodelos.documents.azure.com:443"); // 正式站
+
+            String authKey = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="; // 測試站
+            //String authKey = "mOXBNzaJiawPeLd3ADsIGo2rfsTxv7b2JnosnjFhMGUY3LFGeo9bksv3CaAHo4LqxmlMEORSkZbaYyaBG03r8w=="; // 正式站
+
+            var connectionPolicy = new ConnectionPolicy
+            {
+                ConnectionMode = ConnectionMode.Direct,
+                ConnectionProtocol = Protocol.Tcp
+            };
+            DocumentClient = new DocumentClient(uri, authKey, connectionPolicy);
+            DocumentClient.OpenAsync().GetAwaiter().GetResult();
+        }
+
+        /// <summary>
+        /// 資料表Data
+        /// </summary>
+        /// <param name="schoolShortCode"></param>
+        /// <returns></returns>
+        [HttpGet("GetTestIoTData")]
+        public async Task<BaseJosnRPCResponse> GetTestIoTData(string schoolShortCode)
         {
             var httpClient = new HttpClient();
             var response = await httpClient.GetAsync($"https://coreapisjp-test.azurewebsites.net/values/schooldashboard/{schoolShortCode}");
@@ -54,7 +174,27 @@ namespace TEAMModelOS.Controllers.Test
             response.EnsureSuccessStatusCode();
 
             string content = await response.Content.ReadAsStringAsync();
-            return await Task.Run(() => JObject.Parse(content));
+            // return await Task.Run(() => JObject.Parse(content));
+
+            // string contentRootPath = _hostingEnvironment.ContentRootPath;
+            //identity = "grade";
+            JsonRPCResponseBuilder builder = JsonRPCResponseBuilder.custom();
+            // string data = FileTool.getJson(contentRootPath,identity);
+            builder.Data(JsonConvert.DeserializeObject(content));
+            //return builder.build();
+            return await Task.Run(() => builder.build());
+
+        }
+        public class Secrets : TableEntity
+        {
+            public Secrets(string clientId, string ver)
+            {
+                this.PartitionKey = clientId;
+                this.RowKey = ver;
+            }
+            public string Access { get; set; }
+            public string Path { get; set; }
+            public Secrets() { }
         }
     }
 }

+ 18 - 0
TEAMModelOS/Models/HomeWorkDto.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using TEAMModelOS.Service.Models.Learn;
+
+namespace TEAMModelOS.Models
+{
+    public class HomeWorkDto
+    {
+        public HomeWork homeWork { get; set; }
+
+        /// <summary>
+        /// 是否重置学生作业关联表数据
+        /// </summary>
+        public bool reset { get; set; }
+    }
+}

+ 1 - 1
TEAMModelOS/Properties/launchSettings.json

@@ -19,7 +19,7 @@
     },
     "TEAMModelOS": {
       "commandName": "Project",
-      "launchBrowser": false,
+      "launchBrowser": true,
       "launchUrl": "selectModule",
       "applicationUrl": "https://localhost:5001;http://localhost:5000",
       "environmentVariables": {

+ 15 - 0
TEAMModelOS/ServiceProviderFactory.cs

@@ -0,0 +1,15 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS
+{
+    public static class ServiceProviderFactory
+    {
+         static    ServiceProviderFactory() { 
+        
+        }
+    }
+}

+ 13 - 4
TEAMModelOS/Startup.cs

@@ -15,6 +15,7 @@ using Microsoft.AspNetCore.SpaServices;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
+using Scrutor;
 using TEAMModelOS.SDK.Context.Attributes.Azure;
 using TEAMModelOS.SDK.Context.Configuration;
 using TEAMModelOS.SDK.Context.Filter;
@@ -31,7 +32,7 @@ namespace TEAMModelOS
 {
     public class Startup
     {
-
+        private IServiceCollection _services;
         public Startup(IConfiguration configuration, IWebHostEnvironment env)
         {
             Configuration = configuration;
@@ -39,7 +40,7 @@ namespace TEAMModelOS
         }
 
         public IConfiguration Configuration { get; }
-
+      
         // This method gets called by the runtime. Use this method to add services to the container.
         public void ConfigureServices(IServiceCollection services)
         {
@@ -130,6 +131,13 @@ namespace TEAMModelOS
                .AddClasses(classes => classes.AssignableTo<IBusinessService>())
                    .AsImplementedInterfaces()
                    .WithScopedLifetime());
+            services.Scan(scan => scan.FromApplicationDependencies()
+               .AddClasses(classes => classes.AssignableTo<IChangeService>()).UsingRegistrationStrategy(RegistrationStrategy.Skip)
+                   .AsImplementedInterfaces()
+                  .WithSingletonLifetime());
+
+
+            _services = services;
         }
 
         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -139,8 +147,9 @@ namespace TEAMModelOS
             {
                 app.UseDeveloperExceptionPage();
             }
-            cosmosDBV3Repository.InitializeDatabase().GetAwaiter();
-            changeFeedInvoke.MonitorChangeFeed().GetAwaiter();
+
+            Dictionary<string ,CosmosModelInfo> dict=  cosmosDBV3Repository.InitializeDatabase().Result;
+            changeFeedInvoke.MonitorChangeFeed(dict, _services);
             app.UseMiddleware<HttpGlobalExceptionInvoke>();
             //以下需要按照順序載入中間件  如果应用调用 UseStaticFiles,请将 UseStaticFiles 置于 UseRouting之前。
             app.UseStaticFiles();

+ 2 - 1
TEAMModelOS/appsettings.Development.json

@@ -196,5 +196,6 @@
         "TeamModelId": "cdhabook#2182"
       }
     ]
-  }
+  },
+  "BasicRouter": "{\"data\":[{\"name\":\"testschooldashboard\",\"path\":\"testschooldashboard\",\"component\":\"smartschooldashboard/Index.vue\"},{\"name\":\"testschool\",\"path\":\"testschool\",\"component\":\"school-mgmt/Index.vue\",\"children\":[{\"name\":\"system\",\"path\":\"system\",\"component\":\"school-mgmt/SystemSetting/SystemSetting.vue\"},{\"name\":\"classroom\",\"path\":\"classroom\",\"component\":\"school-mgmt/ClassroomSetting/ClassroomSetting.vue\"}]}]}"
 }

+ 2 - 1
TEAMModelOS/appsettings.json

@@ -196,5 +196,6 @@
         "TeamModelId": "cdhabook#2182"
       }
     ]
-  }
+  },
+  "BasicRouter": "{\"data\":[{\"name\":\"testschooldashboard\",\"path\":\"testschooldashboard\",\"component\":\"smartschooldashboard/Index.vue\"},{\"name\":\"testschool\",\"path\":\"testschool\",\"component\":\"school-mgmt/Index.vue\",\"children\":[{\"name\":\"system\",\"path\":\"system\",\"component\":\"school-mgmt/SystemSetting/SystemSetting.vue\"},{\"name\":\"classroom\",\"path\":\"classroom\",\"component\":\"school-mgmt/ClassroomSetting/ClassroomSetting.vue\"}]}]}"
 }