Browse Source

Merge branch 'develop' into PL/develop-IES5

Li 2 years ago
parent
commit
154562eeda
35 changed files with 802 additions and 323 deletions
  1. 0 113
      TEAMModelBI/Properties/ServiceDependencies/teammodelbi - Web Deploy/profile.arm.json
  2. 4 3
      TEAMModelOS.FunctionV4/Properties/serviceDependencies.json
  3. 5 0
      TEAMModelOS.FunctionV4/Properties/serviceDependencies.teammodelosfunction-test - Zip Deploy.json
  4. 9 0
      TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs
  5. 2 0
      TEAMModelOS.SDK/Models/Cosmos/Common/ArtMusic.cs
  6. 6 6
      TEAMModelOS.SDK/Models/Cosmos/Common/LessonRecord.cs
  7. 70 23
      TEAMModelOS.SDK/Models/Service/Common/ActivityStudentService.cs
  8. 0 6
      TEAMModelOS.sln
  9. 7 0
      TEAMModelOS/ClientApp/public/lang/en-US.js
  10. 7 0
      TEAMModelOS/ClientApp/public/lang/zh-CN.js
  11. 7 0
      TEAMModelOS/ClientApp/public/lang/zh-TW.js
  12. 13 0
      TEAMModelOS/ClientApp/src/api/elegant.js
  13. 2 0
      TEAMModelOS/ClientApp/src/api/index.js
  14. 4 5
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  15. 2 0
      TEAMModelOS/ClientApp/src/common/BaseSelectSchool.vue
  16. 7 6
      TEAMModelOS/ClientApp/src/components/research-dashboard/BaseTechBar.vue
  17. 2 2
      TEAMModelOS/ClientApp/src/components/research-dashboard/LeftTop.vue
  18. 1 1
      TEAMModelOS/ClientApp/src/router/routes.js
  19. 1 1
      TEAMModelOS/ClientApp/src/utils/blobTool.js
  20. 16 4
      TEAMModelOS/ClientApp/src/view/Home.vue
  21. 3 3
      TEAMModelOS/ClientApp/src/view/classrecord/ClassRecord.vue
  22. 4 2
      TEAMModelOS/ClientApp/src/view/dashboard/Sport.vue
  23. 39 31
      TEAMModelOS/ClientApp/src/view/dashboard/fiveEdu/FiveEdu.vue
  24. 23 2
      TEAMModelOS/ClientApp/src/view/dashboard/moral/BaseCarousel.vue
  25. 289 4
      TEAMModelOS/ClientApp/src/view/elegant/Elegant.vue
  26. 20 12
      TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue
  27. 2 2
      TEAMModelOS/ClientApp/src/view/learnactivity/CreatePrivEva.vue
  28. 2 2
      TEAMModelOS/ClientApp/src/view/learnactivity/CreateSchoolEva.vue
  29. 2 2
      TEAMModelOS/ClientApp/src/view/mycourse/exam/CreatePrivExam.vue
  30. 70 55
      TEAMModelOS/ClientApp/src/view/research-center/BaseReportRadar.vue
  31. 124 19
      TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.vue
  32. 26 18
      TEAMModelOS/Controllers/Analysis/ClassAnalysisController.cs
  33. 10 0
      TEAMModelOS/Controllers/Both/LessonRecordController.cs
  34. 22 0
      TEAMModelOS/Controllers/XTest/TestController.cs
  35. 1 1
      TEAMModelOS/TEAMModelOS.csproj

+ 0 - 113
TEAMModelBI/Properties/ServiceDependencies/teammodelbi - Web Deploy/profile.arm.json

@@ -1,113 +0,0 @@
-{
-  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
-  "contentVersion": "1.0.0.0",
-  "metadata": {
-    "_dependencyType": "compute.appService.windows"
-  },
-  "parameters": {
-    "resourceGroupName": {
-      "type": "string",
-      "defaultValue": "TEAMModelChengdu",
-      "metadata": {
-        "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
-      }
-    },
-    "resourceGroupLocation": {
-      "type": "string",
-      "defaultValue": "",
-      "metadata": {
-        "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
-      }
-    },
-    "resourceName": {
-      "type": "string",
-      "defaultValue": "teammodelbi",
-      "metadata": {
-        "description": "Name of the main resource to be created by this template."
-      }
-    },
-    "resourceLocation": {
-      "type": "string",
-      "defaultValue": "[parameters('resourceGroupLocation')]",
-      "metadata": {
-        "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
-      }
-    }
-  },
-  "variables": {
-    "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-    "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]"
-  },
-  "resources": [
-    {
-      "type": "Microsoft.Resources/resourceGroups",
-      "name": "[parameters('resourceGroupName')]",
-      "location": "[parameters('resourceGroupLocation')]",
-      "apiVersion": "2019-10-01"
-    },
-    {
-      "type": "Microsoft.Resources/deployments",
-      "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
-      "resourceGroup": "[parameters('resourceGroupName')]",
-      "apiVersion": "2019-10-01",
-      "dependsOn": [
-        "[parameters('resourceGroupName')]"
-      ],
-      "properties": {
-        "mode": "Incremental",
-        "template": {
-          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
-          "contentVersion": "1.0.0.0",
-          "resources": [
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[parameters('resourceName')]",
-              "type": "Microsoft.Web/sites",
-              "apiVersion": "2015-08-01",
-              "tags": {
-                "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
-              },
-              "dependsOn": [
-                "[variables('appServicePlan_ResourceId')]"
-              ],
-              "kind": "app",
-              "properties": {
-                "name": "[parameters('resourceName')]",
-                "kind": "app",
-                "httpsOnly": true,
-                "reserved": false,
-                "serverFarmId": "[variables('appServicePlan_ResourceId')]",
-                "siteConfig": {
-                  "metadata": [
-                    {
-                      "name": "CURRENT_STACK",
-                      "value": "dotnetcore"
-                    }
-                  ]
-                }
-              },
-              "identity": {
-                "type": "SystemAssigned"
-              }
-            },
-            {
-              "location": "[parameters('resourceLocation')]",
-              "name": "[variables('appServicePlan_name')]",
-              "type": "Microsoft.Web/serverFarms",
-              "apiVersion": "2015-08-01",
-              "sku": {
-                "name": "S1",
-                "tier": "Standard",
-                "family": "S",
-                "size": "S1"
-              },
-              "properties": {
-                "name": "[variables('appServicePlan_name')]"
-              }
-            }
-          ]
-        }
-      }
-    }
-  ]
-}

+ 4 - 3
TEAMModelOS.FunctionV4/Properties/serviceDependencies.json

@@ -1,11 +1,12 @@
 {
   "dependencies": {
-    "appInsights1": {
-      "type": "appInsights"
-    },
     "storage1": {
       "type": "storage",
       "connectionId": "AzureWebJobsStorage"
+    },
+    "appInsights1": {
+      "type": "appInsights",
+      "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING"
     }
   }
 }

+ 5 - 0
TEAMModelOS.FunctionV4/Properties/serviceDependencies.teammodelosfunction-test - Zip Deploy.json

@@ -4,6 +4,11 @@
       "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Storage/storageAccounts/teammodellog",
       "type": "storage.azure",
       "connectionId": "AzureWebJobsStorage"
+    },
+    "appInsights1": {
+      "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/microsoft.insights/components/test-teammodelosfunction",
+      "type": "appInsights.azure",
+      "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING"
     }
   }
 }

+ 9 - 0
TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs

@@ -1463,6 +1463,15 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                         lessonRecord.examCount = lessonBase.summary.examCount;
                                         lessonRecord.totalInteractPoint = lessonBase.summary.totalInteractPoint;
                                         lessonRecord.learningCategory = lessonBase.summary.learningCategory;
+                                        if (lessonRecord.learningCategory == null)
+                                        {
+                                            
+                                            lessonRecord.learningCategory = new LearningCategory();
+                                        }
+                                        if (lessonRecord.hitaClientCmpCount > 0) {
+
+                                            lessonRecord.learningCategory.cooperation = 1;
+                                        }
                                         if (!string.IsNullOrWhiteSpace(lessonRecord.school))
                                         {
                                             lessonBase.student.ForEach(x =>

+ 2 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/ArtMusic.cs

@@ -13,8 +13,10 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         {
             pk = "ArtMusic";
         }
+        //模块ID
         public string activityId { get; set; }
         public List<StuInfo> stus { get; set; }
+        //第三方平台返回的结构
         public JsonElement JsonElement { get; set; }
     }
     public class StuInfo {

+ 6 - 6
TEAMModelOS.SDK/Models/Cosmos/Common/LessonRecord.cs

@@ -222,7 +222,7 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public int upload { get; set; }
 
-        public LearningCategory learningCategory { get; set; }
+        public LearningCategory learningCategory { get; set; } = new LearningCategory();
         public int hitaClientCmpCount { get; set; }
         /// <summary>
         /// 课例来源 0 本公司  1 第三方公司    是因支持VR/AR那边课例
@@ -244,23 +244,23 @@ namespace TEAMModelOS.SDK.Models
         /// <summary>
         /// //合作學習
         /// </summary>
-        public int cooperation { get; set; }
+        public int cooperation { get; set; } = 0;
         /// <summary>
         /// 互動學習
         /// </summary>
-        public int interaction { get; set; }
+        public int interaction { get; set; } = 0;
         /// <summary>
         /// 任務學習
         /// </summary>
-        public int task { get; set; }
+        public int task { get; set; } = 0;
         /// <summary>
         /// 測驗學習
         /// </summary>
-        public int exam { get; set; }
+        public int exam { get; set; } = 0;
         /// <summary>
         /// 差異化學習
         /// </summary>
-        public int diffential { get; set; }
+        public int diffential { get; set; } = 0;
     }
     public class LessonTC
     {

+ 70 - 23
TEAMModelOS.SDK/Models/Service/Common/ActivityStudentService.cs

@@ -15,6 +15,7 @@ using StackExchange.Redis;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
 using TEAMModelOS.Models;
 using TEAMModelOS.SDK;
+using DocumentFormat.OpenXml.Drawing.Charts;
 
 namespace TEAMModelOS.SDK.Services
 {
@@ -618,29 +619,31 @@ namespace TEAMModelOS.SDK.Services
                                     {
                                         recs[index].ForEach(x =>
                                         {
-                                            if (survey.answers[index].Contains(x))
-                                            {
-                                                if (dict.ContainsKey(x))
-                                                {
-                                                    dict[x] = dict[x] + 1;
-                                                }
-                                                else
+                                            if (!string.IsNullOrWhiteSpace(x)) {
+                                                if (survey.answers[index].Contains(x))
                                                 {
-                                                    dict[x] = 1;
-                                                }
-                                            }
-                                            else
-                                            {
-                                                if (dict.ContainsKey("other"))
-                                                {
-                                                    dict["other"] = dict["other"] + 1;
+                                                    if (dict.ContainsKey(x))
+                                                    {
+                                                        dict[x] = dict[x] + 1;
+                                                    }
+                                                    else
+                                                    {
+                                                        dict[x] = 1;
+                                                    }
                                                 }
                                                 else
                                                 {
-                                                    dict["other"] = 1;
+                                                    if (dict.ContainsKey("other"))
+                                                    {
+                                                        dict["other"] = dict["other"] + 1;
+                                                    }
+                                                    else
+                                                    {
+                                                        dict["other"] = 1;
+                                                    }
+                                                    //这里暂不处理, 结算再处理other 
+                                                    //  tasks.Add(_azureStorage.UploadFileByContainer(survey.owner,new { other=x, userid, time =curr }.ToJsonString(), "survey", $"{survey.id}/other/{index}/{userid}.json", false));
                                                 }
-                                                //这里暂不处理, 结算再处理other 
-                                                //  tasks.Add(_azureStorage.UploadFileByContainer(survey.owner,new { other=x, userid, time =curr }.ToJsonString(), "survey", $"{survey.id}/other/{index}/{userid}.json", false));
                                             }
                                         });
                                     }
@@ -748,13 +751,51 @@ namespace TEAMModelOS.SDK.Services
                                 }
                                 var records = await azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}");
                                 List<dynamic> recds = new List<dynamic>();
-                                foreach (var rcd in records)
-                                {
-                                    var value = rcd.Value.ToString().ToObject<JsonElement>();
-                                    recds.Add(new { index = rcd.Name.ToString(), ans = value });
+
+                                List<srecord> srecords = new List<srecord>();
+                                int len = survey.answers.Count;
+                                for (int i = 0; i < len; i++) {
+                                    var anses= surveyRecords.Select(z => z.ans).ToList();
+                                    srecord srecord= new srecord() { index=$"{i}"};
+                                    Dictionary<string, int> dict = new Dictionary<string, int>();
+                                    srecord.ans = dict;
+                                    foreach (var asd in anses) {
+                                        asd[i].ForEach(z => {
+                                            if (!string.IsNullOrWhiteSpace(z)) {
+                                                if (survey.answers[i].Contains(z))
+                                                {
+                                                    if (dict.ContainsKey(z))
+                                                    {
+                                                        dict[z] = dict[z] + 1;
+                                                    }
+                                                    else
+                                                    {
+                                                        dict.Add(z, 1);
+                                                    }
+                                                }
+                                                else
+                                                {
+                                                    if (dict.ContainsKey("other"))
+                                                    {
+                                                        dict["other"] = dict["other"] + 1;
+                                                    }
+                                                    else
+                                                    {
+                                                        dict.Add("other", 1);
+                                                    }
+                                                }
+                                            }
+                                        });
+                                    }
+                                    srecords.Add(srecord);
                                 }
+                                //foreach (var rcd in records)
+                                //{
+                                //    var value = rcd.Value.ToString().ToObject<JsonElement>();
+                                //    recds.Add(new { index = rcd.Name.ToString(), ans = value });
+                                //}
                                 await Task.WhenAll(tasks);
-                                var cods = new { records = recds, userids, question = questionRecords, urecord = surveyRecords };
+                                var cods = new { records = srecords, userids, question = questionRecords, urecord = surveyRecords };
                                 //问卷整体情况
                                 await _azureStorage.GetBlobContainerClient(blobcntr).UploadFileByContainer(cods.ToJsonString(), "survey", $"{survey.id}/record.json");
                                 ///end 20210805 huanghb 实时结算
@@ -843,5 +884,11 @@ namespace TEAMModelOS.SDK.Services
             public Dictionary<string, int> srecord { get; set; } = new Dictionary<string, int>();
             public Dictionary<string, string[]> urecord { get; set; } = new Dictionary<string, string[]>();
         }
+
+        public class srecord
+        {
+            public string index { get; set;}
+            public Dictionary<string, int> ans { get; set; } = new Dictionary<string, int>();
+        }
     }
 }

+ 0 - 6
TEAMModelOS.sln

@@ -5,8 +5,6 @@ VisualStudioVersion = 17.0.32014.148
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelOS.SDK", "TEAMModelOS.SDK\TEAMModelOS.SDK.csproj", "{E804B5FA-8D72-4ED4-AF9E-8AA48C17CE76}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelGrpc", "TEAMModelGrpc\TEAMModelGrpc.csproj", "{B10346B6-FE98-47AF-A77C-148605EFF0E5}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelOS.FunctionV4", "TEAMModelOS.FunctionV4\TEAMModelOS.FunctionV4.csproj", "{2A159D6A-55DB-4B0F-9129-3EB9EE28A1CC}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelOS", "TEAMModelOS\TEAMModelOS.csproj", "{985D4ABD-281A-428C-81AD-60FCA0045DAD}"
@@ -23,10 +21,6 @@ Global
 		{E804B5FA-8D72-4ED4-AF9E-8AA48C17CE76}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{E804B5FA-8D72-4ED4-AF9E-8AA48C17CE76}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{E804B5FA-8D72-4ED4-AF9E-8AA48C17CE76}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B10346B6-FE98-47AF-A77C-148605EFF0E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B10346B6-FE98-47AF-A77C-148605EFF0E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B10346B6-FE98-47AF-A77C-148605EFF0E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B10346B6-FE98-47AF-A77C-148605EFF0E5}.Release|Any CPU.Build.0 = Release|Any CPU
 		{2A159D6A-55DB-4B0F-9129-3EB9EE28A1CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{2A159D6A-55DB-4B0F-9129-3EB9EE28A1CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{2A159D6A-55DB-4B0F-9129-3EB9EE28A1CC}.Release|Any CPU.ActiveCfg = Release|Any CPU

+ 7 - 0
TEAMModelOS/ClientApp/public/lang/en-US.js

@@ -2985,6 +2985,13 @@ const LANG_EN_US = {
     },
     // 课堂记录
     lessonRecord: {
+        mgt: {
+            cooperation: '合作学习',
+            diffential: '差异化学习',
+            exam: '测验学习',
+            interaction: '互动学习',
+            task: '任务学习'
+        },
         export: {
             order: 'No.',
             tchName: 'Teacher Name',

+ 7 - 0
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -2985,6 +2985,13 @@ const LANG_ZH_CN = {
     },
     // 课堂记录
     lessonRecord: {
+        mgt: {
+            cooperation: '合作学习',
+            diffential: '差异化学习',
+            exam: '测验学习',
+            interaction: '互动学习',
+            task: '任务学习'
+        },
         export: {
             order: '序号',
             tchName: '教师姓名',

+ 7 - 0
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -2987,6 +2987,13 @@ const LANG_ZH_TW = {
     },
     // 课堂记录
     lessonRecord: {
+        mgt: {
+            cooperation: '合作学习',
+            diffential: '差异化学习',
+            exam: '测验学习',
+            interaction: '互动学习',
+            task: '任务学习'
+        },
         export: {
             order: '序號',
             tchName: '教師姓名',

+ 13 - 0
TEAMModelOS/ClientApp/src/api/elegant.js

@@ -0,0 +1,13 @@
+import { post } from '@/api/http'
+export default {
+    // 获取知识块知识点
+    findElegants: function (data) {
+        return post('/school/elegant/find', data)
+    },
+    upsertElegants: function (data) {
+        return post('/school/elegant/upsert', data)
+    },
+    deleteElegants: function (data) {
+        return post('/school/elegant/delete', data)
+    }
+}

+ 2 - 0
TEAMModelOS/ClientApp/src/api/index.js

@@ -30,6 +30,7 @@ import mark from './mark'
 import openMgmt from './openMgmt'
 import service from './service'
 import notice from './notice'
+import elegant from './elegant'
 import ability from './ability';
 import jyzx from './jyzx'
 import thirdparty from './thirdparty'
@@ -69,6 +70,7 @@ export default {
     openMgmt,
     service,
     notice,
+    elegant,
     jyzx,
     ability,
     train,

+ 4 - 5
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -169,7 +169,6 @@ export default {
     getSystemLevel() {
       if (this.$store.state.userInfo.hasSchool) {
         let prodInfo = this.$store.state.user?.schoolProfile?.svcStatus || {}
-        console.error('版本', prodInfo)
         //如果没有购买服务则为基础版、标准版、专业版
         let serviceList = this.$GLOBAL.PROD_CODE().filter(item => item.type === 'service')
         let count = 0
@@ -402,14 +401,14 @@ export default {
             },
             // 校园风采
             {
-              icon: 'iconfont icon-notify',
+              icon: 'iconfont icon-k-point',
               name: this.$t('system.menu.schoolElegant'),
               router: '/home/schoolElegant',
               tag: '',
               role: 'admin',
-              permission: '',
+              permission: 'teacher-read|teacher-upd',
               menuName: 'schoolElegant',
-              isShow: false
+              isShow: this.IES5Menu && !this.isGlobalSite
             },
             // 授权管理
             {
@@ -430,7 +429,7 @@ export default {
               router: '/home/log',
               tag: '',
               role: 'admin',
-              permission: 'teacher-read|teacher-upd',
+              permission: 'log-read',
               menuName: 'log',
               isShow: this.IES5Menu
               // isShow: this.$store.state.config.srvAdrType != 'product' && this.$jsFn.checkJinNiu()

+ 2 - 0
TEAMModelOS/ClientApp/src/common/BaseSelectSchool.vue

@@ -120,6 +120,7 @@ export default {
     console.log('当前区域学校 > ', this.areaSchs)
     console.log('当前学校 > ', this.curSchool)
     console.log('当前学段 > ', this.curPeriod)
+    this.$EventBus.$emit('homePageInit')
   },
   methods: {
     async onSchoolSelect(val) {
@@ -183,6 +184,7 @@ export default {
         localStorage.removeItem('bankFilterConds')
         localStorage.setItem('cur_schoolCode', schoolCode)
         this.$emit('onSchoolChange', schoolCode)
+        this.$EventBus.$emit('onSchoolChange')
         // this.periods && (this.curPeriod = this.periods[0])
         setTimeout(() => {
           this.$EventBus.$emit('onGlobalLoading', false)

+ 7 - 6
TEAMModelOS/ClientApp/src/components/research-dashboard/BaseTechBar.vue

@@ -13,7 +13,7 @@ export default {
       let myChart = this.$echarts.init(document.getElementById('baseTechBar'))
       var echartsData = {
         title: 'title',
-        city: ['互动教学', '合作学习', '差异教学', '测验教学'],
+        city: [this.$t('lessonRecord.mgt.cooperation'), this.$t('lessonRecord.mgt.diffential'), this.$t('lessonRecord.mgt.exam'), this.$t('lessonRecord.mgt.interaction'), this.$t('lessonRecord.mgt.task')],
         legend: data.legend,
         data: data.data,
         total: data.total,
@@ -144,13 +144,14 @@ export default {
     let echartJson = {
       legend: pieJson.teachingCount.map(i => i.name),
       data: pieJson.teachingCount.map(i => {
-        return [i.clientInteractionCount, i.collateTaskCount, i.pushCount, i.examCount]
+        return [i.cooperation, i.diffential, i.exam, i.interaction, i.task]
       }),
       total: [
-        pieJson.teachingCount.reduce((a, b) => a + b.clientInteractionCount, 0),
-        pieJson.teachingCount.reduce((a, b) => a + b.collateTaskCount, 0),
-        pieJson.teachingCount.reduce((a, b) => a + b.pushCount, 0),
-        pieJson.teachingCount.reduce((a, b) => a + b.examCount, 0),
+        pieJson.teachingCount.reduce((a, b) => a + b.cooperation, 0),
+        pieJson.teachingCount.reduce((a, b) => a + b.diffential, 0),
+        pieJson.teachingCount.reduce((a, b) => a + b.exam, 0),
+        pieJson.teachingCount.reduce((a, b) => a + b.interaction, 0),
+        pieJson.teachingCount.reduce((a, b) => a + b.task, 0),
       ]
     }
     console.error(echartJson)

+ 2 - 2
TEAMModelOS/ClientApp/src/components/research-dashboard/LeftTop.vue

@@ -40,8 +40,7 @@ export default {
           number: 0
         },
         {
-          title: vm.$t('lessonRecord.echarts.count5'),
-          key: 'semester',
+          title: `课例类别数`,
           number: 0
         },
         {
@@ -69,6 +68,7 @@ export default {
       totalJson.forEach(i => {
         this.titleItem.find(j => j.key === i.name).number = i.value
       })
+      this.titleItem[4].number = allJson.classify_type.length
       this.titleItem[5].number = allJson.classify_grade.length
       this.titleItem[6].number = allJson.classify_sub.length
       this.titleItem[7].number = allJson.classify_group.length

+ 1 - 1
TEAMModelOS/ClientApp/src/router/routes.js

@@ -1345,7 +1345,7 @@ export const routes = [{
         component: () => import('@/view/log/Log.vue'),
         meta: {
             activeName: 'log',
-            middleware: ['login', 'ability:admin,teacher-read|teacher-upd'],
+            middleware: ['login', 'ability:admin'],
         }
     },
     //管理艺术评测

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

@@ -6,7 +6,7 @@ import store from '@/store'
 import FileSaver from "file-saver";
 import JSZip from "jszip";
 
-const BLOB_PATH = ['avatar', 'audio', 'doc', 'exam', 'image', 'item', 'notice', 'other', 'paper', 'syllabus', 'res', 'student', 'survey', 'temp', 'thum', 'video', 'vote', 'jyzx', 'train', 'yxpt', 'homework', 'policy', 'public', 'art']
+const BLOB_PATH = ['avatar', 'audio', 'doc', 'exam', 'image', 'elegant', 'item', 'notice', 'other', 'paper', 'syllabus', 'res', 'student', 'survey', 'temp', 'thum', 'video', 'vote', 'jyzx', 'train', 'yxpt', 'homework', 'policy', 'public', 'art']
 const { BlobServiceClient } = require("@azure/storage-blob")
 
 //获取文件后缀和类型

+ 16 - 4
TEAMModelOS/ClientApp/src/view/Home.vue

@@ -369,6 +369,10 @@ export default {
       localStorage.setItem('noSave', '[]')
     }
 
+    setTimeout(() => {
+      this.isLoading = false
+    }, 2000)
+
     this.$EventBus.$off('noSave')
     this.$EventBus.$on('noSave', val => {
       let curNoSaveArr = JSON.parse(localStorage.getItem('noSave'))
@@ -378,11 +382,16 @@ export default {
 
     this.$EventBus.$off('onGlobalLoading')
     this.$EventBus.$on('onGlobalLoading', val => {
+      console.error('HOME - ', Boolean(val))
       this.isLoading = val
-      console.error('HOME - ', val)
-      if (!val) {
-        this.$EventBus.$emit('homePageInit', val)
-      }
+      // if (!val) {
+      //   setTimeout(() => {
+      //     this.isLoading = false
+      //   }, 2000)
+      //   this.$EventBus.$emit('homePageInit', val)
+      // } else {
+
+      // }
     })
   },
   computed: {
@@ -435,6 +444,9 @@ export default {
     },
     '$i18n.locale'(n, o) {
       this.getQrImgByLang()
+    },
+    isLoading(n, o) {
+      console.error('loading变化', n, o)
     }
   },
 }

+ 3 - 3
TEAMModelOS/ClientApp/src/view/classrecord/ClassRecord.vue

@@ -760,9 +760,9 @@ export default {
   created() {
     this.hiTeachEvent = this.$GLOBAL.HI_TEACH_EVENT()
     //正式站先暂时不放出课中评测
-    // if (this.$store.state.config.srvAdrType == 'product') {
-    //     this.$delete(this.hiTeachEvent, 'SPQStrt')
-    // }
+     if (this.$store.state.config.srvAdrType == 'product') {
+         this.$delete(this.hiTeachEvent, 'SPQStrt')
+     }
     this.events = Object.keys(this.hiTeachEvent)
     this.fnEvents = this.events.filter(key => this.hiTeachEvent[key].type === 'fn')
     console.log(this.events, this.fnEvents)

+ 4 - 2
TEAMModelOS/ClientApp/src/view/dashboard/Sport.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="moral-iframe-container">
+  <div class="moral-iframe-container" id="sportIndex">
     <iframe id="sportIframe" :src="iframeSrc" frameborder="0" width="100%" height="100%"></iframe>
   </div>
 </template>
@@ -17,7 +17,9 @@ export default {
     }
   },
   mounted() {
-    this.$tools.fullScreen(document.getElementById('sportIframe'))
+    setTimeout(() => {
+      this.$tools.fullScreen(document.getElementById('sportIndex'))
+    }, 200)
   }
 }
 </script>

+ 39 - 31
TEAMModelOS/ClientApp/src/view/dashboard/fiveEdu/FiveEdu.vue

@@ -54,12 +54,12 @@
                 <dv-border-box-13>
                   <div class="dashboard-block">
                     <div class="block-title">
-                      <span>德育活跃指标分布</span>
+                      <span>近三次评测统计图</span>
                       <dv-decoration-1 style="width:150px;height:20px;" />
                     </div>
                     <div class="block-content">
-
-                      <BaseWordCloud></BaseWordCloud>
+                      <!-- <BaseWordCloud></BaseWordCloud> -->
+                      <BaseExamLine></BaseExamLine>
                     </div>
                   </div>
                 </dv-border-box-13>
@@ -76,18 +76,34 @@
                 </dv-border-box-13>
               </div>
               <div class="left-bottom-right">
-                <div class="top">
+                <div class="bottom">
                   <dv-border-box-13>
                     <div class="dashboard-block">
+                      <div class="stu-search-wrap" v-if="inClassView">
+                        <Select filterable v-model="curStuIndex" style="width:250px">
+                          <Option v-for="(item,index) in stuList" :value="index" :key="item.id">{{ item.name }}({{ item.id }})</Option>
+                        </Select>
+                      </div>
                       <div class="block-title">
-                        <span>年级综合排名</span>
+                        <span>学生德育风采</span>
                         <dv-decoration-1 style="width:150px;height:20px;" />
                       </div>
                       <div class="block-content">
-                        <dv-scroll-board :config="gradeRankConfig" />
+                        <BaseCarousel></BaseCarousel>
+                        <!-- <div class="honor-avatar">
+                          <div class="honor-item" v-for="(item,index) in stuTopArr" :key="index">
+                            <img class="img-avatar" @click="goStudent()" src="https://paas-admin.xydqq.cn/img/avatar.647bbbfe.png" alt="" width="80">
+                            <img class="img-crown" src="@/assets/dashboard/student/icon_crown.png" alt="" v-show="index === 0">
+                            <img class="img-crown" src="@/assets/dashboard/student/icon_crown2.png" alt="" v-show="index === 1">
+                            <img class="img-crown" src="@/assets/dashboard/student/icon_crown3.png" alt="" v-show="index === 2">
+                            <span>学生姓名{{ index + 1 }}</span>
+                          </div>
+                        </div> -->
                       </div>
                     </div>
                   </dv-border-box-13>
+                </div>
+                <div class="top">
                   <dv-border-box-13>
                     <div class="dashboard-block">
                       <div class="block-title">
@@ -99,29 +115,14 @@
                       </div>
                     </div>
                   </dv-border-box-13>
-                </div>
-                <div class="bottom">
                   <dv-border-box-13>
                     <div class="dashboard-block">
-                      <div class="stu-search-wrap" v-if="inClassView">
-                        <Select filterable v-model="curStuIndex" style="width:250px">
-                          <Option v-for="(item,index) in stuList" :value="index" :key="item.id">{{ item.name }}({{ item.id }})</Option>
-                        </Select>
-                      </div>
                       <div class="block-title">
                         <span>个人综合排名</span>
                         <dv-decoration-1 style="width:150px;height:20px;" />
                       </div>
                       <div class="block-content">
-                        <div class="honor-avatar">
-                          <div class="honor-item" v-for="(item,index) in stuTopArr" :key="index">
-                            <img class="img-avatar" @click="goStudent()" src="https://paas-admin.xydqq.cn/img/avatar.647bbbfe.png" alt="" width="80">
-                            <img class="img-crown" src="@/assets/dashboard/student/icon_crown.png" alt="" v-show="index === 0">
-                            <img class="img-crown" src="@/assets/dashboard/student/icon_crown2.png" alt="" v-show="index === 1">
-                            <img class="img-crown" src="@/assets/dashboard/student/icon_crown3.png" alt="" v-show="index === 2">
-                            <span>学生姓名{{ index + 1 }}</span>
-                          </div>
-                        </div>
+                        <dv-scroll-board :config="gradeRankConfig" />
                       </div>
                     </div>
                   </dv-border-box-13>
@@ -179,9 +180,9 @@
         <StudyDash v-else-if="activeMenuId === 'study'"></StudyDash>
         <MoralDash v-else-if="activeMenuId === 'moral'"></MoralDash>
         <!-- <ArtDash v-else-if="activeMenuId === 'art'"></ArtDash> -->
-        <div class="sport-box" style="width:100%;height:90vh;padding-top:25px;" v-show="activeMenuId === 'sport'">
+        <!-- <div class="sport-box" style="width:100%;height:90vh;padding-top:25px;" v-show="activeMenuId === 'sport'">
           <iframe src="https://ydztshow.cdwalker.com/app-health-100/smart-course" width="100%" height="100%" frameborder="0"></iframe>
-        </div>
+        </div> -->
       </div>
 
     </div>
@@ -204,8 +205,10 @@ import BaseCircle from '@/components/dashboard/student/BaseCircle'
 import StudentDetails from '../Student'
 import BaseProgressBar from '@/components/dashboard/student/BaseProgressBar'
 import StudyDash from '../study/StudyDash'
+import BaseExamLine from '../study/BaseExamLine'
 import MoralDash from '../moral/MoralDash'
 import ArtDash from '../Art.vue'
+import BaseCarousel from '../moral/BaseCarousel'
 export default {
   data() {
     return {
@@ -355,6 +358,7 @@ export default {
     }
   },
   components: {
+    BaseExamLine,
     StudyDash,
     ArtDash,
     MoralDash,
@@ -367,7 +371,8 @@ export default {
     BaseArtCircle,
     BaseMusicCircle,
     BaseCircle,
-    BaseProgressBar
+    BaseProgressBar,
+    BaseCarousel
   },
   mounted() {
     if (!this.isFull) {
@@ -402,12 +407,14 @@ export default {
           }
           break;
         case 'moral':
-          if (this.isTestView) {
-            this.activeMenuId = menu.id
-          } else {
-            this.noAuthModal = true
-            this.noAuthName = '德育看板'
-          }
+          // if (this.isTestView) {
+          //   this.activeMenuId = menu.id
+          // } else {
+          //   this.noAuthModal = true
+          //   this.noAuthName = '德育看板'
+          // }
+          this.noAuthModal = true
+          this.noAuthName = '德育看板'
           break;
         case 'study':
           this.activeMenuId = menu.id
@@ -416,6 +423,7 @@ export default {
           if (this.isTestView) {
             // window.open('https://ydztshow.cdwalker.com/app-health-100/smart-course')
             this.activeMenuId = menu.id
+            this.$router.push('/sportDashboard')
           } else {
             this.noAuthModal = true
             this.noAuthName = '体育看板'

+ 23 - 2
TEAMModelOS/ClientApp/src/view/dashboard/moral/BaseCarousel.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="moral-carousel-container">
-    <carousel-3d :autoplay=" true" :autoplayTimeout="3000" :height="240" :width="380" :space="180" controlsVisible>
+    <carousel-3d :autoplay="true" :autoplayTimeout="3000" :height="240" :width="380" :space="180" controlsVisible>
       <slide v-for="(slide, i) in slides" :index="i" :key="i">
         <template slot-scope="{ index, isCurrent, leftIndex, rightIndex }">
           <img :data-index="index" :class="{ current: isCurrent, onLeft: (leftIndex >= 0), onRight: (rightIndex >= 0) }" :src="slide.src">
@@ -40,8 +40,29 @@ export default {
         {
           src: require('./6.jpg')
         },
-      ]
+      ],
+      schoolProfile: null
     }
+  },
+  created() {
+    // this.schoolProfile = JSON.parse(decodeURIComponent(localStorage.school_profile || '{}', "utf-8"))
+    // this.$api.elegant.findElegants({
+    //   "admin": "1",//表示管理列表,其他则只获取有效的publish
+    //   "stime": null,//可选
+    //   "etime": null,//可选
+    // }).then(res => {
+    //   console.log(res)
+    //   if (!res.elegants.length) return
+    //   res.elegants.forEach(item => {
+    //     item.attachments.forEach(img => {
+    //       this.slides.push({
+    //         src: img.url + '?' + this.schoolProfile.blob_sas,
+    //         title: item.title
+    //       })
+    //     })
+    //   })
+    //   console.log(this.slides.map(i => i.src))
+    // })
   }
 }
 </script>

+ 289 - 4
TEAMModelOS/ClientApp/src/view/elegant/Elegant.vue

@@ -2,22 +2,239 @@
   <div class="elegant-container">
     <div class="header">
       <span class="title">校园德育风采</span>
-      <Button type="success" size="small">+ 添加素材</Button>
+      <Button type="success" size="small" @click="onAddElegant">+ 添加素材</Button>
     </div>
-    <div class="content-box">
-
+    <div class="elegant-list">
+      <EmptyData :top="300" v-if="!elegantList.length"></EmptyData>
+      <Timeline v-else>
+        <TimelineItem v-for="(item,index) in elegantList" :key="index">
+          <p class="elegant-title">
+            <span>{{ item.title }}</span>
+            <span style="margin:0 10px;">
+              <Tag color="primary">{{ $tools.formatTime(item.createTime) }}</Tag>
+            </span>
+            <!-- <Icon type="md-create" color="#2d8cf0" @click="onEditElegant(item,index)"></Icon> -->
+            <Icon type="md-trash" color="#2d8cf0" @click="onDelElegant(item,index)"></Icon>
+          </p>
+          <p class="elegant-content">{{ item.content }}</p>
+          <div class="img-list">
+            <div class="img-item" v-for="(img,imgIndex) in item.attachments" :key="imgIndex" @click="onImgClick(item.attachments,imgIndex)">
+              <img :src="getFullPath(img.url)" alt="">
+            </div>
+          </div>
+        </TimelineItem>
+      </Timeline>
     </div>
+    <Drawer :title="isEdit ? '编辑素材' : '添加素材'" :closable="false" v-model="editModal" width="520" :transfer="false">
+      <Form :model="curElegantItem" label-position="top" v-if="curElegantItem">
+        <FormItem :label="`活动名称`">
+          <Input v-model="curElegantItem.title" :placeholder="`请输入活动名称...`"></Input>
+        </FormItem>
+        <FormItem :label="`活动描述`">
+          <Input v-model="curElegantItem.content" :placeholder="`请输入活动描述内容...`"></Input>
+        </FormItem>
+        <FormItem :label="`活动素材`">
+          <Upload multiple type="drag" action="" :before-upload="onBeforeUpload" :show-upload-list="false" accept="image/jpeg,image/jpg,image/png," :format="['jpg','jpeg','png']" :on-format-error="handleFormatError">
+            <div style="padding: 40px 0">
+              <Icon type="ios-cloud-upload" size="52" style="color: #3399ff"></Icon>
+              <p>拖拽或者点击上传活动图片素材</p>
+            </div>
+          </Upload>
+          <div class="img-list">
+            <div class="img-item" v-for="(imgFile,imgFileIndex) in imgFilePreviewList" :key="imgFileIndex">
+              <div class="mask">
+                <Icon type="md-trash" color="#fff" size="26" @click="onRemoveFile(imgFileIndex)"></Icon>
+              </div>
+              <img :src="getDataUrl(imgFile)" alt="">
+            </div>
+          </div>
+          <p style="margin-top:10px;color:red">上传须知:</p>
+          <p style="color:red">1. 活动素材需为后缀名为jpg/jpeg/png格式的图片文件,单张图片大小不得超出10M</p>
+          <p style="color:red">2. 活动素材图片数量最多为10张</p>
+        </FormItem>
+        <Button type="primary" @click="onConfirm" style="width: 100%;height: 40px;" :loading="btnLoading" class="modal-btn">保存</Button>
+      </Form>
+    </Drawer>
   </div>
 </template>
 
 <script>
+import BlobTool from '@/utils/blobTool.js'
 export default {
+  data() {
+    return {
+      elegantList: [],
+      curElegantItem: null,
+      curElegantIndex: 0,
+      editModal: false,
+      isEdit: false,
+      btnLoading: false,
+      fileArr: [],
+      priviewSrc: '',
+      imgFilePreviewList: [],
+      containerClient: null,
+      schoolProfile: null
+    }
+  },
+  created() {
+    this.schoolProfile = JSON.parse(decodeURIComponent(localStorage.school_profile || '{}', "utf-8"))
+    this.$api.elegant.findElegants({
+      "admin": "1",//表示管理列表,其他则只获取有效的publish
+      "stime": null,//可选
+      "etime": null,//可选
+    }).then(res => {
+      this.elegantList = res.elegants.reverse()
+    })
+  },
+  methods: {
+    onAddElegant() {
+      this.editModal = true
+      this.curElegantItem = {
+        title: '',
+        content: '',
+        createTime: 0,
+        attachments: []
+      }
+    },
+    onImgClick(imgList, index) {
+      this.$hevueImgPreview({
+        multiple: true,
+        keyboard: true,
+        nowImgIndex: index,
+        imgList: imgList.map(i => this.getFullPath(i.url))
+      })
+    },
+    onEditElegant(item, index) {
 
+    },
+    onDelElegant(item, index) {
+      this.$Modal.confirm({
+        title: this.$t('evaluation.newExercise.modalTip'),
+        content: `确认删除【${item.title}】活动?`,
+        onOk: () => {
+          this.$api.elegant.deleteElegants({ id: item.id }).then(res => {
+            if (!res.error) {
+              this.deleteBlobPrefix(item)
+              this.$Message.success('操作成功!')
+              this.elegantList.splice(index, 1)
+            }
+          })
+        }
+      });
+    },
+    deleteBlobPrefix(item) {
+      return new Promise((resolve, reject) => {
+        this.$api.blob.deletePrefix({
+          "cntr": item.school,
+          "prefix": `elegant/` + item.id
+        }).then(
+          (res) => {
+            if (!res.error) {
+              resolve(200)
+            } else {
+              resolve(500)
+            }
+          },
+          (err) => {
+            reject(err)
+          }
+        )
+      })
+    },
+    handleFormatError(file) {
+      this.$Notice.warning({
+        title: '上传素材文件格式错误',
+        desc: file.name + ' 文件格式错误,请上传后缀名为 jpg/jpeg/png 的图片素材'
+      });
+    },
+    onBeforeUpload(file) {
+      if (this.imgFilePreviewList.length >= 10) {
+        this.$Message.warning('最多允许上传10张图片素材!')
+        return
+      }
+      if (file.size > 10 * 1024 * 1024) {
+        this.$Message.warning('单张图片大小不得超过10M')
+        return
+      }
+      this.imgFilePreviewList.push(file)
+    },
+    onRemoveFile(fileIndex) {
+      this.imgFilePreviewList.splice(fileIndex, 1)
+    },
+    /* 保存上传 */
+    async onConfirm() {
+      let { title, content } = this.curElegantItem
+      if (!title || !content) {
+        this.$Message.warning('请填写完整!')
+        return
+      }
+      if (!this.imgFilePreviewList.length) {
+        this.$Message.warning('图片素材不可为空!')
+      }
+      let n = await this.$tools.getSchoolSas()
+      let elegantId = this.$tools.guid()
+      let params = this._.cloneDeep(this.curElegantItem)
+      this.btnLoading = true
+      this.containerClient = new BlobTool(n.url, n.name, n.sas, 'school')
+      try {
+        let uploadResult = await this.uploadFiles(this.imgFilePreviewList, elegantId)
+        params.attachments = uploadResult
+        params.id = elegantId
+        params.publish = 1
+        params.type = 'school'
+        params.startTime = 111
+        params.endTime = 222
+        this.$api.elegant.upsertElegants(params).then(res => {
+          if (!res.error) {
+            this.btnLoading = false
+            this.$Message.success('操作成功!')
+            this.elegantList.unshift(res.elegant)
+            this.editModal = false
+          } else {
+            this.btnLoading = false
+            this.$Message.error(res.error)
+          }
+        })
+      } catch (e) {
+        this.$Message.error(e)
+        this.btnLoading = false
+      }
+      console.log(this.imgFilePreviewList)
+    },
+    uploadFiles(files, elegantId) {
+      return new Promise((resolve, reject) => {
+        let promiseArr = []
+        files.forEach(file => {
+          promiseArr.push(this.containerClient.upload(file, { path: `elegant/${elegantId}` }))
+        })
+        Promise.all(promiseArr).then(result => {
+          resolve(result)
+        }).catch(e => {
+          reject(e)
+        })
+      })
+    }
+  },
+  computed: {
+    getDataUrl() {
+      return file => {
+        var windowURL = window.URL || window.webkitURL;
+        var dataURL = windowURL.createObjectURL(file)
+        return dataURL
+      }
+    },
+    getFullPath() {
+      return url => {
+        return url + '?' + this.schoolProfile.blob_sas
+      }
+    }
+  }
 }
 </script>
 
-<style lang="less" scoped>
+<style lang="less">
 .elegant-container {
+  height: 100%;
   .header {
     width: 100%;
     display: flex;
@@ -31,5 +248,73 @@ export default {
       font-weight: bold;
     }
   }
+
+  .elegant-list {
+    width: 100%;
+    height: 90%;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 15px;
+    overflow: auto;
+
+    .ivu-timeline {
+      height: 100%;
+    }
+
+    .ivu-timeline-item-head-blue {
+      background: #2d8cf0 !important;
+      color: #2d8cf0;
+      margin-top: 4px;
+    }
+
+    .elegant-title {
+      font-size: 16px;
+      font-weight: bold;
+      display: flex;
+      align-items: center;
+
+      .ivu-icon {
+        margin-right: 5px;
+        cursor: pointer;
+      }
+    }
+
+    .elegant-content {
+      margin: 10px 0;
+      color: #817f7f;
+    }
+  }
+
+  .img-list {
+    display: flex;
+    flex-wrap: wrap;
+    .img-item {
+      position: relative;
+      margin: 10px 10px 0 0;
+      cursor: pointer;
+
+      img {
+        width: 140px;
+        height: 100px;
+      }
+
+      &:hover {
+        .mask {
+          display: flex;
+        }
+      }
+
+      .mask {
+        position: absolute;
+        width: 140px;
+        height: 100px;
+        background: rgba(0, 0, 0, 0.6);
+        display: none;
+        align-items: center;
+        justify-content: center;
+      }
+    }
+  }
 }
 </style>

+ 20 - 12
TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="home-page-container">
-    <!-- <Loading v-if="isLoading" :top="300" type="3"></Loading> -->
+    <Loading v-if="isLoading" :top="300"></Loading>
     <vuescroll>
       <div class="chart-box">
         <div class="chart-box-column1">
@@ -352,6 +352,7 @@ export default {
   inject: ['reload'],
   data() {
     return {
+      createdInit: false,
       spaceStatus: 1, //1:正常 2:空间不足10% 3:空间已满
       recentRcdList: [],
       countData: {},
@@ -362,7 +363,7 @@ export default {
       weekData: [],
       recordData: {},
       recordCount: {},
-      isLoading: true,
+      isLoading: false,
       settings: {}, //研修标准设置
       teacherInfo: {},//老师研修数据
       //总学时数据
@@ -764,7 +765,7 @@ export default {
     },
     //获取活动统计数据已经进行中的活动
     getAcCount() {
-      this.isLoading = true
+
       this.$api.learnActivity.ActivityCount({}).then(
         res => {
           if (res.totalCount && res.totalCount.length) {
@@ -810,10 +811,18 @@ export default {
         }
       ).finally(() => {
         this.isLoading = false
+        this.createdInit = false
       })
     },
-    initData() {
-      console.error('HomePage INIT !!!')
+    initData(type) {
+      if (type === 'created') {
+        this.createdInit = true
+        this.isLoading = true
+      } else {
+        if (this.createdInit) return
+      }
+      console.error(type, this.createdInit)
+      console.error('============获取首页数据=================')
       this.areaSas = this.$store.state.user.userProfile.osblob_sas
       this.schoolSas = this.$store.state.user.schoolProfile.blob_sas
       this.platformList = []
@@ -830,14 +839,13 @@ export default {
     }
   },
   created() {
-    console.error('HomePageCreated')
-    // this.initData()
+    console.error('============HomePageCreated============')
+    this.initData('created')
   },
   mounted() {
-    this.$EventBus.$off('homePageInit')
-    this.$EventBus.$on('homePageInit', val => {
-      console.error('homePageInit')
-      this.initData()
+    this.$EventBus.$off('onSchoolChange')
+    this.$EventBus.$on('onSchoolChange', val => {
+      this.initData('custom')
     })
   },
   computed: {
@@ -858,7 +866,7 @@ export default {
     globalLoading() {
       return sessionStorage.getItem('isGlobalLoading') !== 'true'
     }
-  }
+  },
 }
 </script>
 <style scoped lang="less">

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

@@ -26,8 +26,8 @@
                                     </Tooltip>
                                 </label>
                                 <Select v-model="evaluationInfo.source" @on-change="checkItemSort">
-                                    <!-- 暂时取消创建课中评量 -->
-                                    <Option v-for="(item,index) in $GLOBAL.EV_MODE()" v-show="index != 1" :label="item.label" :value="item.value" :key="index" :disabled="index > 1 && (!$store.state.userInfo.hasSchool || !$store.state.user.schoolProfile.svcStatus.VABAJ6NV)">
+                                    <!-- 暂时取消创建课中评量 --> <!-- 20221124非正式站課中評測放回 -->
+                                    <Option v-for="(item,index) in $GLOBAL.EV_MODE()" v-show="index != 1 || $store.state.config.srvAdrType != 'product'" :label="item.label" :value="item.value" :key="index" :disabled="index > 1 && (!$store.state.userInfo.hasSchool || !$store.state.user.schoolProfile.svcStatus.VABAJ6NV)">
                                         <div>
                                             <span>
                                                 {{ item.label }}

+ 2 - 2
TEAMModelOS/ClientApp/src/view/learnactivity/CreateSchoolEva.vue

@@ -26,8 +26,8 @@
                                     </Tooltip>
                                 </label>
                                 <Select v-model="evaluationInfo.source" @on-change="checkItemSort">
-                                    <!-- 校本评测开放创建课中评量 2022530调整不能发布课中评测,没有做物联网-->
-                                    <Option v-for="(item,index) in $GLOBAL.EV_MODE()" v-show="index != 1" :label="item.label" :value="item.value" :key="index" :disabled="index > 1 && !$store.state.user.schoolProfile.svcStatus.VABAJ6NV">
+                                    <!-- 校本评测开放创建课中评量 2022530调整不能发布课中评测,没有做物联网--> <!-- 20221124非正式站課中評測放回 -->
+                                    <Option v-for="(item,index) in $GLOBAL.EV_MODE()" v-show="index != 1 || $store.state.config.srvAdrType != 'product'" :label="item.label" :value="item.value" :key="index" :disabled="index > 1 && !$store.state.user.schoolProfile.svcStatus.VABAJ6NV">
                                         <div>
                                             <span>
                                                 {{ item.label }}

+ 2 - 2
TEAMModelOS/ClientApp/src/view/mycourse/exam/CreatePrivExam.vue

@@ -26,8 +26,8 @@
                                     </Tooltip>
                                 </label>
                                 <Select v-model="evaluationInfo.source" @on-change="checkItemSort">
-                                    <!-- 暂时取消创建课中评量 -->
-                                    <Option v-for="(item,index) in $GLOBAL.EV_MODE()" v-show="index != 1" :label="item.label" :value="item.value" :key="index" :disabled="index > 1 && (!$store.state.userInfo.hasSchool || !$store.state.user.schoolProfile.svcStatus.VABAJ6NV)">
+                                    <!-- 暂时取消创建课中评量 --> <!-- 20221124非正式站課中評測放回 -->
+                                    <Option v-for="(item,index) in $GLOBAL.EV_MODE()" v-show="index != 1 || $store.state.config.srvAdrType != 'product'" :label="item.label" :value="item.value" :key="index" :disabled="index > 1 && (!$store.state.userInfo.hasSchool || !$store.state.user.schoolProfile.svcStatus.VABAJ6NV)">
                                         <div>
                                             <span>
                                                 {{ item.label }}

+ 70 - 55
TEAMModelOS/ClientApp/src/view/research-center/BaseReportRadar.vue

@@ -17,67 +17,86 @@ export default {
   methods: {
     doRender(pieData) {
       let myChart = this.$echarts.init(document.getElementById('reportRadar'))
-      let max = Math.max(...pieData.map(i => i.value)) + 5
       let option = {
+        color: ['#5189F8'],
         tooltip: {},
         radar: {
-          // shape: 'circle',
-          name: {
-            textStyle: {
-              color: '#999999',
-            }
-          },
-          splitArea: {
-            areaStyle: {
-              color: [
-                "rgba(178, 199, 255, 1)",
-                "rgba(191, 208, 255, 1)",
-                "rgba(204, 218, 255, 1)",
-                "rgba(217, 227, 255, 1)",
-                "rgba(229, 236, 255, 1)",
-                "rgba(242,246,255,1)",
-              ],
-              shadowColor: "rgba(0, 0, 0, 0.3)",
-            },
+          axisName: {
+            fontSize: 14,
+            color: '#6D7278',
           },
           axisLine: {
             lineStyle: {
-              color: "rgba(255, 255, 255, 0.2)",
-            },
-          },
-          splitLine: {
-            lineStyle: {
-              color: "rgba(255, 255, 255, 0)",
+              color: '#6D7278',
             },
           },
+          shape: 'circle',
+          center: ['50%', '50%'],
+          radius: '60%',
+          triggerEvent: false,
           indicator: [
-            { name: '互动教学', max: max },
-            { name: '合作学习', max: max },
-            { name: '差异教学', max: max },
-            { name: '测验教学', max: max },
-          ]
-        },
-        series: [{
-          type: 'radar',
-          data: [
             {
-              value: pieData.map(i => i.value),
-              name: '数据',
-              itemStyle: {
-                normal: {
-                  color: 'rgba(5, 128, 242, 0.8)'
-                }
-              },
-              areaStyle: {
-                normal: {
-                  color: '#0580f2'
-                }
-              }
+              name: this.$t('lessonRecord.mgt.cooperation'),
+              max: 1,
+              min: 0,
+            },
+            {
+              name: this.$t('lessonRecord.mgt.diffential'),
+              max: 1,
+              min: 0,
+            },
+            {
+              name: this.$t('lessonRecord.mgt.exam'),
+              max: 1,
+              min: 0,
+            },
+            {
+              name: this.$t('lessonRecord.mgt.interaction'),
+              max: 1,
+              min: 0,
+            },
+            {
+              name: this.$t('lessonRecord.mgt.task'),
+              max: 1,
+              min: 0,
             }
-          ]
-        }]
-      }
-
+          ],
+        },
+        series: [
+          {
+            name: '课堂表现',
+            type: 'radar',
+            symbolSize: 7,
+            areaStyle: {
+              color: {
+                type: 'radial',
+                x: 0.5,
+                y: 0.5,
+                r: 0.5,
+                colorStops: [
+                  {
+                    offset: 0,
+                    color: 'rgba(0, 180, 235, 0.3)', // 0% 处的颜色
+                  },
+                  {
+                    offset: 1,
+                    color: 'rgba(0, 180, 235, 0.9)', // 100% 处的颜色
+                  },
+                ],
+              },
+            },
+            lineStyle: {
+              width: 2
+            },
+            data: [
+              {
+                value: pieData,
+                name: '课堂表现',
+              },
+            ],
+          },
+        ],
+      };
       myChart.clear()
       myChart.setOption(option)
       window.addEventListener('resize', function () {
@@ -87,11 +106,7 @@ export default {
     }
   },
   mounted() {
-    let pieData = [{ value: this.lessonInfo.clientInteractionAverge, name: '互动教学' },
-    { value: this.lessonInfo.collateTaskCount, name: '合作学习' },
-    { value: this.lessonInfo.pushCount, name: '差异教学' },
-    { value: this.lessonInfo.examCount, name: '测验教学' },]
-    this.doRender(pieData)
+    this.doRender(Object.values(this.lessonInfo.learningCategory))
   },
   //   watch: {
   //     '$store.state.dashboard.artDashboard': {

+ 124 - 19
TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.vue

@@ -209,7 +209,7 @@
             <div v-if="row.status === 404">
               <Icon class="action-icon" type="md-alert" color="#e25255" :title="$t('lessonRecord.delStatusTip')" />
             </div>
-            <span style="margin-top: 5px;display: block;">{{ $tools.formatTime(row.startTime,'yyyy-MM-dd') }}</span>
+            <span style="margin-top: 5px;display: flex;justify-content:space-between">{{ $tools.formatTime(row.startTime,'yyyy-MM-dd') }} <Tag color="volcano">{{ formatDuration(row.duration) }}</Tag> </span>
           </template>
         </Table>
       </Scroll>
@@ -267,11 +267,11 @@
         <div style="display: flex;justify-content: center;font-weight: bold">
           <span style="display: flex;justify-content: center;flex-direction: column;align-items: center">
             <span :style="{ backgroundColor: getLevelColor(curLessonRecord.tLevel),boxShadow:'0 0 6px ' + getLevelColor(curLessonRecord.tLevel) }" class="level-light"></span>
-            <span>技术应用</span>
+            <span>互动指数</span>
           </span>
           <span style="display: flex;justify-content: center;flex-direction: column;align-items: center;margin-left: 40px;">
             <span :style="{ backgroundColor: getLevelColor(curLessonRecord.pLevel),boxShadow:'0 0 6px ' + getLevelColor(curLessonRecord.pLevel) }" class="level-light"></span>
-            <span>教法应用</span>
+            <span>教法指数</span>
           </span>
         </div>
         <div class="static-box">
@@ -324,8 +324,8 @@
             <span class="static-label">学生互动总数</span>
           </div>
         </div>
-        <BaseReportPie v-if="reportModal" :lessonInfo="curLessonRecord"></BaseReportPie>
-        <!-- <BaseReportRadar v-if="reportModal" :lessonInfo="curLessonRecord"></BaseReportRadar> -->
+        <!-- <BaseReportPie v-if="reportModal" :lessonInfo="curLessonRecord"></BaseReportPie> -->
+        <BaseReportRadar v-if="reportModal" :lessonInfo="curLessonRecord"></BaseReportRadar>
       </div>
     </Modal>
   </div>
@@ -496,16 +496,22 @@ export default {
           minWidth: 320
         },
         {
-          key: 'clientInteractionAverge',
           align: 'center',
           sortable: 'custom',
           minWidth: 120,
           render: (h, params) => {
-            return h('strong', { style: { fontSize: '16px', color: params.row.clientInteractionAverge ? '#00b214' : '#a4a4a4' } }, params.row.clientInteractionAverge);
+            const done = params.row.learningCategory.cooperation > 0
+            return h('Icon', {
+              props: {
+                type: done ? 'ios-checkmark-circle' : 'ios-remove-circle',
+                color: done ? '#00b214' : '#a4a4a4',
+                size: 24
+              }
+            })
           },
           renderHeader: (h) => {
             return h('div', [
-              h('strong', vm.$t('lessonRecord.clientInteractionCount')),
+              h('strong', vm.$t('lessonRecord.mgt.cooperation')),
               h('Tooltip', {
                 props: {
                   placement: 'right',
@@ -536,16 +542,22 @@ export default {
           }
         },
         {
-          key: 'hitaClientCmpCount',
           align: 'center',
           sortable: 'custom',
           minWidth: 80,
           render: (h, params) => {
-            return h('strong', { style: { fontSize: '16px', color: params.row.hitaClientCmpCount ? '#00b214' : '#a4a4a4' } }, params.row.hitaClientCmpCount);
+            const done = params.row.learningCategory.interaction > 0
+            return h('Icon', {
+              props: {
+                type: done ? 'ios-checkmark-circle' : 'ios-remove-circle',
+                color: done ? '#00b214' : '#a4a4a4',
+                size: 24
+              }
+            })
           },
           renderHeader: (h) => {
             return h('div', [
-              h('strong', vm.$t('lessonRecord.collateTaskCount')),
+              h('strong', vm.$t('lessonRecord.mgt.interaction')),
               h('Tooltip', {
                 props: {
                   placement: 'right',
@@ -576,16 +588,22 @@ export default {
           }
         },
         {
-          key: 'pushCount',
           align: 'center',
           sortable: 'custom',
           minWidth: 80,
           render: (h, params) => {
-            return h('strong', { style: { fontSize: '16px', color: params.row.pushCount ? '#00b214' : '#a4a4a4' } }, params.row.pushCount);
+            const done = params.row.learningCategory.task > 0
+            return h('Icon', {
+              props: {
+                type: done ? 'ios-checkmark-circle' : 'ios-remove-circle',
+                color: done ? '#00b214' : '#a4a4a4',
+                size: 24
+              }
+            })
           },
           renderHeader: (h) => {
             return h('div', [
-              h('strong', vm.$t('lessonRecord.pushCount')),
+              h('strong', vm.$t('lessonRecord.mgt.task')),
               h('Tooltip', {
                 props: {
                   placement: 'right',
@@ -616,16 +634,22 @@ export default {
           }
         },
         {
-          key: 'examCount',
           align: 'center',
           sortable: 'custom',
           minWidth: 80,
           render: (h, params) => {
-            return h('strong', { style: { fontSize: '16px', color: params.row.examCount ? '#00b214' : '#a4a4a4' } }, params.row.examCount);
+            const done = params.row.learningCategory.exam > 0
+            return h('Icon', {
+              props: {
+                type: done ? 'ios-checkmark-circle' : 'ios-remove-circle',
+                color: done ? '#00b214' : '#a4a4a4',
+                size: 24
+              }
+            })
           },
           renderHeader: (h) => {
             return h('div', [
-              h('strong', vm.$t('lessonRecord.examQuizCount')),
+              h('strong', vm.$t('lessonRecord.mgt.exam')),
               h('Tooltip', {
                 props: {
                   placement: 'right',
@@ -656,12 +680,58 @@ export default {
           }
         },
         {
-          title: `技术应用`,
+          align: 'center',
+          sortable: 'custom',
+          minWidth: 80,
+          render: (h, params) => {
+            const done = params.row.learningCategory.diffential > 0
+            return h('Icon', {
+              props: {
+                type: done ? 'ios-checkmark-circle' : 'ios-remove-circle',
+                color: done ? '#00b214' : '#a4a4a4',
+                size: 24
+              }
+            })
+          },
+          renderHeader: (h) => {
+            return h('div', [
+              h('strong', vm.$t('lessonRecord.mgt.diffential')),
+              h('Tooltip', {
+                props: {
+                  placement: 'right',
+                  transfer: true,
+                  theme: "light"
+                },
+              }, [h('Icon', {
+                props: {
+                  type: 'ios-help-circle-outline',
+                  color: '#c4c4c4'
+                },
+                style: {
+                  marginLeft: '5px',
+                  fontSize: '16px',
+                  fontWeight: 'bolder',
+                  cursor: 'pointer'
+                }
+              }),
+              h('span', {
+                slot: 'content',
+                style: {
+                  whiteSpace: 'normal',
+                  wordBreak: 'break-all'
+                }
+              }, `智慧课堂中发布的测验次数`)
+              ])
+            ])
+          }
+        },
+        {
+          title: `互动指数`,
           slot: 'tLevel',
           align: 'center'
         },
         {
-          title: `教法应用`,
+          title: `教法指数`,
           slot: 'pLevel',
           align: 'center'
         },
@@ -1118,6 +1188,17 @@ export default {
       this.totalNum = await this.$api.lessonRecord.getLessonCount(this.filterParams)
       this.$api.lessonRecord.getLessonList(this.filterParams).then(async res => {
         if (!res.error && res.lessonRecords) {
+          res.lessonRecords.forEach(record => {
+            if (!record.learningCategory) {
+              record.learningCategory = {
+                cooperation: 0,
+                diffential: 0,
+                exam: 0,
+                interaction: 0,
+                task: 0
+              }
+            }
+          })
           let schoolSas = await this.$tools.getSchoolSas()
           this.tableData = this.getFullInfo(res.lessonRecords, schoolSas)
           this.isReachBottom = true
@@ -1292,6 +1373,25 @@ export default {
           this.oldNewTags = []
         }
       })
+    },
+    getSFM(seconds, dateFormat = 'H:i:s') {
+      var obj = {};
+      obj.H = Number.parseInt(seconds / 3600);
+      obj.i = Number.parseInt((seconds - obj.H * 3600) / 60);
+      obj.s = Number.parseInt(seconds - obj.H * 3600 - obj.i * 60);
+      if (obj.H < 10) {
+        obj.H = '0' + obj.H;
+      }
+      if (obj.i < 10) {
+        obj.i = '0' + obj.i;
+      }
+      if (obj.s < 10) {
+        obj.s = '0' + obj.s;
+      }
+
+      // 3.解析
+      var rs = dateFormat.replace('H', obj.H).replace('i', obj.i).replace('s', obj.s);
+      return rs;
     }
   },
   computed: {
@@ -1306,6 +1406,11 @@ export default {
           return ['#ff2d2d', '#ffc018', '#00b214'][level]
         }
       }
+    },
+    formatDuration() {
+      return seconds => {
+        return this.getSFM(seconds, 'i:s')
+      }
     }
   },
   beforeRouteLeave(to, from, next) {

+ 26 - 18
TEAMModelOS/Controllers/Analysis/ClassAnalysisController.cs

@@ -132,50 +132,58 @@ namespace TEAMModelOS.Controllers.Analysis
                     School scInfo = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{code}", partitionKey: new PartitionKey("Base"));
                     var perMore = scInfo.period.Where(c => c.id.Equals(pId.GetString())).FirstOrDefault().grades;
 
-                    var clientInteractionCount = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).GroupBy(k => int.Parse(k.grade?[0])).Select(x => new
+                    var interaction = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).GroupBy(k => int.Parse(k.grade?[0])).Select(x => new
                     {
                         x.Key,
                         name = perMore[x.Key],
-                        count = x.Sum(t => t.clientInteractionCount)
+                        count = x.Sum(t => t.learningCategory?.interaction)
                     });
-                    var pushCount = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).GroupBy(k => int.Parse(k.grade?[0])).Select(x => new
+                    var cooperation = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).GroupBy(k => int.Parse(k.grade?[0])).Select(x => new
                     {
                         x.Key,
                         name = perMore[x.Key],
-                        count = x.Sum(t => t.pushCount)
+                        count = x.Sum(t => t.learningCategory?.cooperation)
                     });
-                    var collateTaskCount = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).GroupBy(k => int.Parse(k.grade?[0])).Select(x => new
+                    var task = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).GroupBy(k => int.Parse(k.grade?[0])).Select(x => new
                     {
                         x.Key,
                         name = perMore[x.Key],
-                        count = x.Sum(t => t.collateTaskCount)
+                        count = x.Sum(t => t.learningCategory?.task)
                     });
-                    var examCount = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).GroupBy(k => int.Parse(k.grade?[0])).Select(x => new
+                    var exam = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).GroupBy(k => int.Parse(k.grade?[0])).Select(x => new
                     {
                         x.Key,
                         name = perMore[x.Key],
-                        count = x.Sum(t => t.examCount)
+                        count = x.Sum(t => t.learningCategory?.exam)
                     });
-                    List<(string name, int? cICount, int? pCount, int? cTCount, int? eCount)> tcount = new();
+                    var diffential = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).GroupBy(k => int.Parse(k.grade?[0])).Select(x => new
+                    {
+                        x.Key,
+                        name = perMore[x.Key],
+                        count = x.Sum(t => t.learningCategory?.diffential)
+                    });
+                    List<(string name, int? cICount, int? pCount, int? cTCount, int? eCount,int? diffCount)> tcount = new();
                     List<(string name, int? count)> gdCount = new();
                     perMore.ForEach(x =>
                     {
-                        var cICount = clientInteractionCount.Where(c => c.name.Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault()?.count;
-                        var pCount = pushCount.Where(c => c.name.Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault()?.count;
-                        var cTCount = collateTaskCount.Where(c => c.name.Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault()?.count;
-                        var eCount = examCount.Where(c => c.name.Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault()?.count;
+                        var cICount = interaction.Where(c => c.name.Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault()?.count;
+                        var pCount = cooperation.Where(c => c.name.Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault()?.count;
+                        var cTCount = task.Where(c => c.name.Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault()?.count;
+                        var eCount = exam.Where(c => c.name.Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault()?.count;
+                        var diffCount = diffential.Where(c => c.name.Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault()?.count;
                         var gradeCount = grades.Where(c => perMore[int.Parse(c.name)].Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault().count;
-                        tcount.Add((x, cICount, pCount, cTCount, eCount));
+                        tcount.Add((x, cICount, pCount, cTCount, eCount, diffCount));
                         gdCount.Add((x, gradeCount));
                     });
 
                     var teachingCount = tcount.Select(x => new
                     {
                         x.name,
-                        clientInteractionCount = x.cICount == null ? 0 : x.cICount,
-                        pushCount = x.pCount == null ? 0 : x.pCount,
-                        collateTaskCount = x.cTCount == null ? 0 : x.cTCount,
-                        examCount = x.eCount == null ? 0 : x.eCount
+                        interaction = x.cICount == null ? 0 : x.cICount,
+                        cooperation = x.pCount == null ? 0 : x.pCount,
+                        task = x.cTCount == null ? 0 : x.cTCount,
+                        exam = x.eCount == null ? 0 : x.eCount,
+                        diffential = x.diffCount == null ? 0 : x.eCount
                     });
                     var classify_grade = gdCount.Select(x => new
                     {

+ 10 - 0
TEAMModelOS/Controllers/Both/LessonRecordController.cs

@@ -793,6 +793,16 @@ namespace TEAMModelOS.Controllers
                             if (rcd.hitaClientCmpCount <= 0 && rcd.collateTaskCount > 0) {
                                 rcd.hitaClientCmpCount= rcd.collateTaskCount;
                             }
+                            if (rcd.learningCategory == null)
+                            {
+
+                                rcd.learningCategory = new LearningCategory();
+                            }
+                            if (rcd.hitaClientCmpCount > 0)
+                            {
+
+                                rcd.learningCategory.cooperation = 1;
+                            }
                             lessonRecords.Add(rcd);
                         }
                         continuationToken = item.GetContinuationToken();

File diff suppressed because it is too large
+ 22 - 0
TEAMModelOS/Controllers/XTest/TestController.cs


+ 1 - 1
TEAMModelOS/TEAMModelOS.csproj

@@ -104,7 +104,7 @@
     <!-- Build Target: Restore NPM packages using npm -->
     <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
 
-    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
+    <Exec WorkingDirectory="$(SpaRoot)" Command="cnpm install" />
   </Target>
 
   <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">