소스 검색

Merge branch 'develop' of http://52.130.252.100:10000/TEAMMODEL/TEAMModelOS into develop

jeff 1 년 전
부모
커밋
44afdd06a0
29개의 변경된 파일2171개의 추가작업 그리고 1456개의 파일을 삭제
  1. 32 0
      TEAMModelBI/Filter/AspNetCoreBuilderServiceCollectionExtensions.cs
  2. 109 0
      TEAMModelBI/Filter/RequestAuditFilter.cs
  3. 2 2
      TEAMModelBI/Startup.cs
  4. 27 2
      TEAMModelOS.FunctionV4/HttpTrigger/IESHttpTrigger.cs
  5. 222 69
      TEAMModelOS/ClientApp/src/components/dashboard/art/LeftBottom.vue
  6. 2 0
      TEAMModelOS/ClientApp/src/components/dashboard/art/RightTop.vue
  7. 5 0
      TEAMModelOS/ClientApp/src/static/Global.js
  8. 184 214
      TEAMModelOS/ClientApp/src/view/areaMgmt/AreaIndex.vue
  9. 403 394
      TEAMModelOS/ClientApp/src/view/art/SchoolArt.vue
  10. 24 4
      TEAMModelOS/ClientApp/src/view/classrecord/ClassRecord.vue
  11. 14 8
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Buzr.vue
  12. 107 0
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Cowork.vue
  13. 14 8
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Pick.vue
  14. 47 27
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/PopQues.vue
  15. 4 2
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Push.vue
  16. 55 41
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Receive.vue
  17. 38 33
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/SmartRating.vue
  18. 135 0
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/SubjectiveAns.vue
  19. 53 40
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/WrkCmp.vue
  20. 463 416
      TEAMModelOS/ClientApp/src/view/dashboard/Art.vue
  21. 35 17
      TEAMModelOS/Controllers/Analysis/ArtAnalysisController.cs
  22. 1 1
      TEAMModelOS/Controllers/Client/AClassONEController.cs
  23. 1 1
      TEAMModelOS/Controllers/Common/ExamController.cs
  24. 16 31
      TEAMModelOS/Controllers/System/CoreController.cs
  25. 119 117
      TEAMModelOS/Controllers/XTest/TestController.cs
  26. 4 3
      TEAMModelOS/Filter/BlobLoggerProvider.cs
  27. 43 16
      TEAMModelOS/Filter/RequestAuditFilter.cs
  28. 10 8
      TEAMModelOS/Program.cs
  29. 2 2
      TEAMModelOS/Startup.cs

+ 32 - 0
TEAMModelBI/Filter/AspNetCoreBuilderServiceCollectionExtensions.cs

@@ -0,0 +1,32 @@
+using Google.Protobuf.WellKnownTypes;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+
+namespace TEAMModelOS.Filter
+{
+    public static class AspNetCoreBuilderServiceCollectionExtensions
+    {  /// <summary>
+       /// 注册 Mvc 过滤器
+       /// </summary>
+       /// <typeparam name="TFilter"></typeparam>
+       /// <param name="services"></param>
+       /// <param name="configure"></param>
+       /// <returns></returns>
+        public static IServiceCollection AddMvcFilter<TFilter>(this IServiceCollection services, Action<MvcOptions> configure = default)
+            where TFilter : IFilterMetadata
+        {
+            services.Configure<MvcOptions>(options =>
+            {
+                options.Filters.Add<TFilter>();
+
+                // 其他额外配置
+                configure?.Invoke(options);
+            });
+
+            return services;
+        }
+    }
+
+}

+ 109 - 0
TEAMModelBI/Filter/RequestAuditFilter.cs

@@ -0,0 +1,109 @@
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System.Security.Claims;
+using System;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.Extension;
+using Microsoft.Extensions.Logging;
+using TEAMModelOS.SDK;
+using DocumentFormat.OpenXml.Office2010.Excel;
+using DocumentFormat.OpenXml.Wordprocessing;
+using System.IdentityModel.Tokens.Jwt;
+using System.Linq;
+using Azure.Core;
+using DocumentFormat.OpenXml.Office2016.Excel;
+using TEAMModelOS.SDK.DI;
+using Microsoft.Extensions.Primitives;
+using HTEXLib.Helpers.ShapeHelpers;
+
+namespace TEAMModelOS.Filter
+{
+    public class RequestAuditFilter : IAsyncActionFilter
+    {
+        //private readonly ILogger _logger;
+        private readonly HttpTrigger _httpTrigger;
+        public RequestAuditFilter(/*ILoggerFactory loggerFactory*/HttpTrigger httpTrigger)
+        {
+          //  _logger = loggerFactory.CreateLogger<RequestAuditFilter>();
+            _httpTrigger = httpTrigger;
+        }
+        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+        {
+            //============== 这里是执行方法之前获取数据 ====================
+
+            // 获取控制器、路由信息
+            //var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
+
+            // 获取请求的方法
+            //var method = actionDescriptor.MethodInfo;
+
+            // 获取 HttpContext 和 HttpRequest 对象
+            var httpContext = context.HttpContext;
+            var httpRequest = httpContext.Request;
+
+            // 获取客户端 Ipv4 地址
+            var remoteIPv4 = httpContext.GetRemoteIpAddressToIPv4();
+
+            // 获取请求的 Url 地址
+           // var requestUrl = httpRequest.GetRequestUrlAddress();
+
+            
+            // 获取来源 Url 地址
+           //var refererUrl = httpRequest.GetRefererUrlAddress();
+
+            // 获取请求参数(写入日志,需序列化成字符串后存储)
+            var parameters = context.ActionArguments;
+
+            // 获取操作人(必须授权访问才有值)"userId" 为你存储的 claims type,jwt 授权对应的是 payload 中存储的键名
+            //var userId = httpContext.User?.FindFirstValue("userId");
+            var authtoken = context.HttpContext.GetXAuth("AuthToken");
+            string tokenSha = string.Empty,client = string.Empty;
+            if (context.HttpContext.Request.Headers.TryGetValue("Authorization", out StringValues Authorization)) 
+            {
+                try {
+                    string token = Authorization.ToString().Replace("Bearer ", "");
+                    var jwt = new JwtSecurityTokenHandler().ReadJwtToken(token);
+                      tokenSha = ShaHashHelper.GetSHA1(token);
+                    client = jwt.Claims.FirstOrDefault(claim => claim.Type.Equals("roles"))?.Value;
+                } catch (Exception ex ) { }
+            }
+            string id = string.Empty, name = string.Empty, picture = string.Empty, school = string.Empty;
+            if (!string.IsNullOrWhiteSpace(authtoken)) {
+                var jwt = new JwtSecurityTokenHandler().ReadJwtToken(authtoken);
+                id = jwt.Payload.Sub;
+                school = jwt.Payload.Azp;
+                name = jwt.Claims.FirstOrDefault(claim => claim.Type.Equals("name"))?.Value;
+            }
+            // 请求时间
+            var requestedTime = DateTimeOffset.Now.GetGMTTime(8).ToUnixTimeMilliseconds();
+            //============== 这里是执行方法之后获取数据 ====================
+            var actionContext = await next();
+            // 获取返回的结果
+            // var returnResult = actionContext.Result;
+
+            // 判断是否请求成功,没有异常就是请求成功
+            // var isRequestSucceed = actionContext.Exception == null;
+
+            // 获取调用堆栈信息,提供更加简单明了的调用和异常堆栈
+            // var stackTrace = EnhancedStackTrace.Current();
+            // string region = await _searcher.SearchIpAsync(remoteIPv4);
+            //同一个账号,同一IP,同一接口,UA标识(UA标识随意切换则表示可能会存在DDOS),时间段
+             //_logger.LogInformation(new{ ua=httpContext.GetUserAgent(), ip=remoteIPv4,time=requestedTime,path =$"{httpRequest.PathBase}{httpRequest.Path}",host= $"{httpRequest.Host}", param=parameters,id ,name ,school,succeed =isRequestSucceed }.ToJsonString());
+            var data = new {
+                //ua = httpContext.GetUserAgent(),
+                ip = remoteIPv4,
+                time = requestedTime,
+                path = $"{httpRequest.PathBase}{httpRequest.Path}",
+                host = $"{httpRequest.Host}",
+                param = parameters,
+                id,
+                name,
+                school,
+                client,tid= tokenSha,
+                p="bi",
+            };
+            _= _httpTrigger.RequestHttpTrigger(data, "China", "http-log");
+            
+        }
+    }
+}

+ 2 - 2
TEAMModelBI/Startup.cs

@@ -26,6 +26,7 @@ using TEAMModelOS.SDK.Helper.Common.ReflectorExtensions;
 using TEAMModelOS.SDK.Models;
 using VueCliMiddleware;
 using System.Net.Http;
+using TEAMModelOS.Filter;
 
 namespace TEAMModelBI
 {
@@ -185,6 +186,7 @@ namespace TEAMModelBI
             });
             //等保安全性验证。
             services.AddScoped<SecurityHeadersAttribute>();
+            services.AddMvcFilter<RequestAuditFilter>();
             services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");
         }
 
@@ -233,8 +235,6 @@ namespace TEAMModelBI
 #endif
 
             });
-
-
         }
     }
 }

+ 27 - 2
TEAMModelOS.FunctionV4/HttpTrigger/IESHttpTrigger.cs

@@ -1,5 +1,6 @@
 using Azure.Cosmos;
 using Azure.Storage.Blobs.Models;
+using Azure.Storage.Blobs.Specialized;
 using Azure.Storage.Sas;
 using DocumentFormat.OpenXml.Bibliography;
 using DocumentFormat.OpenXml.Drawing.Wordprocessing;
@@ -28,6 +29,7 @@ using System.Net.Http;
 using System.Net.Http.Json;
 using System.Reflection;
 using System.Security.Policy;
+using System.ServiceModel.Channels;
 using System.Text;
 using System.Text.Json;
 using System.Threading;
@@ -72,9 +74,32 @@ namespace TEAMModelOS.FunctionV4
             _option = option?.Value;
             _configuration = configuration;
         }
+        // <summary>
+        /// </summary>
+        /// <param name="req"></param>
+        /// <param name="log"></param>
+        /// <returns></returns>
+        [Function("http-log")]
+        public async Task<HttpResponseData> HttpLog([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req) {
+            string data = await new StreamReader(req.Body).ReadToEndAsync();
+            var response = req.CreateResponse(HttpStatusCode.OK);
+            
+            var appendBlob = _azureStorage.GetBlobContainerClient("0-service-log").GetAppendBlobClient($"http-log/{DateTimeOffset.UtcNow.GetGMTTime(8):yyyy-MM-dd}.log");
+            if (!appendBlob.Exists())
+            {
+                appendBlob.Create();
+                using var stream = new MemoryStream(Encoding.UTF8.GetBytes($"{data},\n"));
+                await appendBlob.AppendBlockAsync(stream);
+            }
+            else
+            {
+                using var stream = new MemoryStream(Encoding.UTF8.GetBytes($"{data},\n"));
+                await appendBlob.AppendBlockAsync(stream);
+            }
+            return response;
+        }
 
-        
-        /// <summary>
+         /// <summary>
          /// </summary>
          /// <param name="req"></param>
          /// <param name="log"></param>

+ 222 - 69
TEAMModelOS/ClientApp/src/components/dashboard/art/LeftBottom.vue

@@ -1,77 +1,230 @@
 <template>
-  <div id="bottomLeft">
-    <p class="dashboard-block-title">
-      <Icon type="md-pulse" />
-      <span>学生落点分析图</span>
-      <dv-decoration-1 class="dv-dec-3" />
-    </p>
-    <div class="bg-color-black">
-      <BaseArtScatter></BaseArtScatter>
-      <!-- <dv-scroll-board :config="config" style="width:96%;margin-left:2%" /> -->
-    </div>
-  </div>
+	<div id="bottomLeft">
+		<p class="dashboard-block-title">
+			<Icon type="md-pulse" />
+			<span>知识点得分率明细</span>
+			<dv-decoration-1 class="dv-dec-3" />
+		</p>
+		<div class="select-wrap">
+			<Cascader v-model="cascaderVal" :data="cascaderConfig" change-on-select @on-change="onSelect" :clearable="false"></Cascader>
+		</div>
+		<div class="bg-color-black">
+			<!-- <BaseArtScatter></BaseArtScatter> -->
+			<!-- <dv-scroll-board :config="config" style="width:96%;margin-left:2%" /> -->
+			<div id="knoBar" style="height: 300px"></div>
+		</div>
+	</div>
 </template>
 
 <script>
-import BaseArtScatter from '@/components/dashboard/art/BaseArtScatter.vue'
-export default {
-  components: {
-    BaseArtScatter
-  },
-  data() {
-    return {
-      config: null
-    }
-  },
-  watch: {
-    '$store.state.dashboard.artDashboard': {
-      deep: true,
-      immediate: true,
-      handler(n, o) {
-        if (n) {
-          this.$nextTick(() => {
-            console.error(n.paperArr)
-            this.config = {
-              header: ["名称", "满分", "试题总数", "使用人数", "有效题", "无效题", "难度"],
-              data: n.paperArr,
-              rowNum: 4, //表格行数
-              headerHeight: 35,
-              headerBGC: "#0f1325", //表头
-              oddRowBGC: "#0f1325", //奇数行
-              evenRowBGC: "#171c33", //偶数行
-              columnWidth: [250],
-            }
-          })
-        }
-      }
-    }
-  }
-}
+	import BaseArtScatter from "@/components/dashboard/art/BaseArtScatter.vue";
+	export default {
+		components: {
+			BaseArtScatter
+		},
+		data() {
+			return {
+				cascaderConfig: [],
+				cascaderVal: [],
+				config: null,
+				option: null,
+				artAnalysisJson: null
+			};
+		},
+		methods: {
+			onSelect(val) {
+				console.log(val);
+				if (val.length === 1) {
+					this.doRender(this.artAnalysisJson.cInfo.find((i) => i.id === val[0]).kno);
+				} else {
+					this.doRender(this.artAnalysisJson.students.find((i) => i.id === val[1]).kno);
+				}
+			},
+			doRender(data) {
+				let myChart = this.$echarts.init(document.getElementById("knoBar"));
+				this.option = {
+					title: {
+						textStyle: {
+							align: "center",
+							color: "#fff",
+							fontSize: 20
+						},
+						top: "5%",
+						left: "center"
+					},
+					tooltip: {
+						trigger: "axis",
+						axisPointer: {
+							type: "shadow"
+						},
+						formatter: function (params) {
+							return params[0].name + "<br>得分率:" + params[0].value + "%";
+						}
+					},
+					grid: {
+						left: "2%",
+						right: "4%",
+						bottom: "8%",
+						top: "10%",
+						containLabel: true
+					},
+					xAxis: {
+						type: "category",
+						data: data.map((i) => i.name),
+						axisLine: {
+							lineStyle: {
+								color: "#eee"
+							}
+						},
+						axisLabel: {
+							interval: 0,
+							margin: 20,
+							color: "#05D5FF",
+							textStyle: {
+								fontSize: 11
+							}
+						}
+					},
+					yAxis: [
+						{
+							type: "value",
+							nameTextStyle: {
+								color: "#A2A5AA",
+								fontSize: 10
+							},
+							splitLine: {
+								show: true,
+								lineStyle: {
+									color: "rgba(255,255,255,0.3)"
+								}
+							},
+							axisLine: {
+								lineStyle: {
+									color: "#6C6F79" //改轴颜色
+								}
+							},
+							axisLabel: {}
+						}
+					],
+					dataZoom: [
+						{
+							show: true,
+							height: 10,
+							xAxisIndex: [0],
+							bottom: 10,
+							start: 0,
+							end: 60,
+							handleIcon: "path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z",
+							handleSize: "110%",
+							handleStyle: {
+								color: "#5B3AAE"
+							},
+							textStyle: {
+								color: "rgba(204,187,225,0.5)"
+							},
+							fillerColor: "rgba(67,55,160,0.4)",
+							borderColor: "rgba(204,187,225,0.5)"
+						},
+						{
+							type: "inside",
+							show: true,
+							height: 15,
+							start: 1,
+							end: 35
+						}
+					],
+					series: [
+						{
+							type: "bar",
+							barWidth: "20",
+							itemStyle: {
+								normal: {
+									color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+										{
+											offset: 0,
+											color: "#70cf7e"
+										},
+										{
+											offset: 1,
+											color: "#1cc0ad"
+										}
+									]),
+									barBorderRadius: 11
+								}
+							},
+							data: data.map((i) => i.score || i.persent)
+						}
+					]
+				};
+				myChart.setOption(this.option);
+				window.addEventListener("resize", function () {
+					myChart.resize();
+				});
+			}
+		},
+		watch: {
+			"$store.state.artDashboard.artAnalysisJson": {
+				deep: true,
+				immediate: true,
+				handler(n, o) {
+					if (n) {
+						this.$nextTick(() => {
+							this.artAnalysisJson = n;
+							n.cInfo.forEach((classItem) => {
+								this.cascaderConfig.push({
+									value: classItem.id,
+									label: classItem.name,
+									children: n.students
+										.filter((i) => i.classId === classItem.id)
+										.map((k) => {
+											return {
+												value: k.id,
+												label: k.name,
+												children: []
+											};
+										})
+								});
+							});
+							this.doRender(n.kno);
+						});
+					}
+				}
+			}
+		}
+	};
 </script>
 
 <style lang="less" scoped>
-@box-height: 100%;
-@box-width: 100%;
-#bottomLeft {
-  padding: 20px 16px;
-  height: @box-height;
-  width: @box-width;
-  display: flex;
-  flex-direction: column;
-  .bg-color-black {
-    height: 91%;
-    padding-top: 10px;
-  }
-  .text {
-    color: #c3cbde;
-  }
-  .chart-box {
-    margin-top: 16px;
-    width: 170px;
-    height: 170px;
-    .active-ring-name {
-      padding-top: 10px;
-    }
-  }
-}
+	@box-height: 100%;
+	@box-width: 100%;
+	#bottomLeft {
+		padding: 20px 16px;
+		height: @box-height;
+		width: @box-width;
+		display: flex;
+		flex-direction: column;
+		.select-wrap {
+			position: absolute;
+			top: 30px;
+			right: 30px;
+			width: 200px;
+			height: 100%;
+			z-index: 1;
+		}
+		.bg-color-black {
+			height: 91%;
+			padding-top: 10px;
+		}
+		.text {
+			color: #c3cbde;
+		}
+		.chart-box {
+			margin-top: 16px;
+			width: 170px;
+			height: 170px;
+			.active-ring-name {
+				padding-top: 10px;
+			}
+		}
+	}
 </style>

+ 2 - 0
TEAMModelOS/ClientApp/src/components/dashboard/art/RightTop.vue

@@ -333,6 +333,8 @@ export default {
             })
 
             this.cascaderConfig = cascaderConfig
+            this.cascaderVal = ['all', cascaderConfig[0].children[0].value]
+            this.onSelect(['all', cascaderConfig[0].children[0].value])
           })
         }
       }

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

@@ -569,6 +569,11 @@ const HI_TEACH_EVENT = () => {
 			text: '智慧评分',
 			type: 'fn',
 			relation: 'smart'
+		},
+		CoworkLoad: {
+			text: '协作',
+			type: 'fn',
+			relation: 'cowork'
 		}
 	}
 }

+ 184 - 214
TEAMModelOS/ClientApp/src/view/areaMgmt/AreaIndex.vue

@@ -18,7 +18,7 @@
 						<!-- <div class="right-top-bottombox-title" :class="[item.classname === 'school' || item.classname === 'teach' || item.classname === 'datas' ? 'all-top-box' : item.classname === 'size' || item.classname === 'months' ? 'sizeclass' : '']">
 							<p class="right-top-title">{{ item.title }}</p>
 						</div> -->
-            <p class="right-top-title">{{ item.title }}</p>
+						<p class="right-top-title">{{ item.title }}</p>
 						<!-- <div class="right-top-bottombox-comparison" v-if="item.classname === 'school' || item.classname === 'teach' || item.classname === 'datas' || item.classname === 'student'">
 							<p>
 								{{ $t("areaStatistics.header.weekAdd") }}:<span class="week-comparison">{{ item.addweek }}</span>
@@ -37,26 +37,17 @@
 					</p>
 				</div>
 				<div :class="[items.type === 'month' ? 'alonebox' : 'totalalonebox']" v-for="(items, indexs) in activityData.oneself" :key="indexs">
-					<p :class="[items.type === 'month' ? 'alonebox-title' : 'total-alonebox-title']">{{ items.title }}</p>
 					<p :class="[items.type === 'month' ? 'alonebox-content' : 'total-alonebox-content']">{{ items.num }}</p>
+					<p :class="[items.type === 'month' ? 'alonebox-title' : 'total-alonebox-title']">{{ items.title }}</p>
 				</div>
 			</div>
-			<div class="rightbox">
+			<div class="rightbox center-resource-right">
 				<div class="tagbox">
-					<p class="tags basics">
-						<span>{{ $t("areaStatistics.tag.basics") }}</span>
+					<p class="tags dynamic">
+						<span>{{ $t("areaStatistics.tag.classActive") }}</span>
 					</p>
 				</div>
-				<!--<div class="rightbox-pie">
-               <CommonPie :proportionData="areaData.alonePie"></CommonPie>
-            </div>-->
-				<div class="rightbox-pie anaphase">
-					<!-- <ConventionPie :proportionData="areaData.research"></ConventionPie> -->
-					<ConventionPie :pieData="areaData.research"></ConventionPie>
-				</div>
-				<div class="rightbox-pie versions">
-					<ConventionPie :pieData="areaData.versions"></ConventionPie>
-				</div>
+				<CommonLine :lineData="areaData.dynamic"></CommonLine>
 			</div>
 		</div>
 		<div class="center-resource">
@@ -66,11 +57,18 @@
 						<span>{{ $t("areaStatistics.tag.classData") }}</span>
 					</p>
 				</div>
+				<div class="chats-tabs">
+					<RadioGroup v-model="timeTab" type="button" button-style="solid" size="small">
+						<Radio label="今年"></Radio>
+						<Radio label="上周"></Radio>
+						<Radio label="本月"></Radio>
+					</RadioGroup>
+				</div>
 				<div class="center-resource-left-leftEcharts">
-					<div class="echarts-title">{{ $t("areaStatistics.class.total") }}:</div>
-					<ConventionPie :pieData="areaData.class"></ConventionPie>
+					<!-- <div class="echarts-title">{{ $t("areaStatistics.class.total") }}:</div> -->
+					<ConventionPie :pieData="timeTab === '今年' ? areaData.class : timeTab === '上周' ? areaData.lastweek : areaData.monthsContrast"></ConventionPie>
 				</div>
-				<div class="center-resource-left-rightbox">
+				<!-- <div class="center-resource-left-rightbox">
 					<div class="week-echart">
 						<div class="echarts-title-pie">{{ $t("areaStatistics.class.lastWeek") }}:</div>
 						<ConventionPie :pieData="areaData.lastweek"></ConventionPie>
@@ -79,15 +77,22 @@
 						<div class="echarts-title-pie">{{ $t("areaStatistics.class.nowMonth") }}:</div>
 						<ConventionPie :pieData="areaData.monthsContrast"></ConventionPie>
 					</div>
-				</div>
+				</div> -->
 			</div>
-			<div class="center-resource-right">
+			<div class="center-resource-right rightbox" style="margin-top: 0">
 				<div class="tagbox">
-					<p class="tags dynamic">
-						<span>{{ $t("areaStatistics.tag.classActive") }}</span>
+					<p class="tags basics">
+						<span>{{ $t("areaStatistics.tag.basics") }}</span>
 					</p>
 				</div>
-				<CommonLine :lineData="areaData.dynamic"></CommonLine>
+
+				<div class="rightbox-pie anaphase">
+					<!-- <ConventionPie :proportionData="areaData.research"></ConventionPie> -->
+					<ConventionPie :pieData="areaData.research"></ConventionPie>
+				</div>
+				<div class="rightbox-pie versions">
+					<ConventionPie :pieData="areaData.versions"></ConventionPie>
+				</div>
 			</div>
 		</div>
 		<div class="bottom-resource">
@@ -105,9 +110,9 @@
 						<span>{{ $t("areaStatistics.tag.size") }}</span>
 					</p>
 				</div>
-				<div class="bottom-rightbox-left">
+				<!-- <div class="bottom-rightbox-left">
 					<Liquidfill :liquidfillData="areaData.size"></Liquidfill>
-				</div>
+				</div> -->
 				<div class="bottom-rightbox-right">
 					<ConventionPie :pieData="areaData.sizeProportion"></ConventionPie>
 				</div>
@@ -120,7 +125,7 @@
 				</p>
 			</div>
 			<div class="listbox">
-				<Table :columns="columns" :data="data">
+				<Table :columns="columns" :data="data" stripe>
 					<template #badge="{ row }">
 						<!--<img :src="row.picture" width="50px" height="50px" />-->
 						<img :src="row.picture" class="schoolImg" v-if="row.picture" />
@@ -148,6 +153,7 @@
 			return {
 				loadingshow: false,
 				states: "develop",
+				timeTab: "今年",
 				showPattern: "all",
 				aspectsData: [
 					{ id: 1, title: this.$t("areaStatistics.header.areaTilte"), num: 0, icon: "iconfont icon-24gl-school", classname: "months", addweek: 0, addmonth: 0 },
@@ -327,30 +333,28 @@
 					},
 					//某个学区活动占比
 					research: {
-						color: ["#ff7979", "#badc58", "#7ed6df", "#f6e58d", "#686de0"],
+						color: ["#37a2da", "#32c5e9", "#9fe6b8", "#ffdb5c", "#ff9f7f", "#fb7293", "#e7bcf3", "#8378ea"],
 						legend: {
-							right: "0%",
-							orient: "vertical",
-							itemWidth: 8,
+							bottom: 0,
+							itemWidth: 16,
 							itemHeight: 8, // 修改icon图形大小
 							textStyle: {
-								fontSize: 12,
-								color: "#333"
+								fontFamily: "Hm",
+								color: "#666"
 							}
 						},
 						series: [
 							{
 								name: this.$t("areaStatistics.basics.activityP"),
 								type: "pie",
-								radius: "70%",
-								center: ["45%", "50%"],
+								radius: "65%",
+								center: ["50%", "40%"],
 								itemStyle: {
 									borderRadius: 8
 								},
 								label: {
 									normal: {
-										position: "inner",
-										show: false
+										position: "outer"
 									}
 								},
 								data: [
@@ -364,31 +368,29 @@
 					},
 					//版本占比
 					versions: {
-						color: ["#5c7bd9", "#9fe080", "#ffdc60"],
+						color: ["#ff9f7f", "#fb7293", "#e7bcf3"],
 						legend: {
-							right: "0%",
-							orient: "vertical",
-							itemWidth: 8,
+							bottom: 0,
+							itemWidth: 16,
 							itemHeight: 8, // 修改icon图形大小
 							textStyle: {
-								fontSize: 12,
-								color: "#333"
+								fontFamily: "Hm",
+								color: "#666"
 							}
 						},
 						series: [
 							{
 								name: this.$t("areaStatistics.basics.versionsP"),
 								type: "pie",
-								radius: "70%",
-								center: ["45%", "50%"],
+								radius: "65%",
+								center: ["50%", "40%"],
 								// roseType: 'area',
 								itemStyle: {
 									borderRadius: 8
 								},
 								label: {
 									normal: {
-										position: "inner",
-										show: false
+										position: "outer"
 									}
 								},
 								data: [
@@ -401,21 +403,15 @@
 					},
 					//课例数据
 					class: {
-						color: ["#3fb1e3", "#6be6c1", "#626c91", "#a0a7e6", "#c4ebad", "#96dee8"],
+						color: ["#afa3f5", "#00d488", "#3feed4", "#3bafff", "#f1bb4c"],
 						legend: {
-							bottom: "1%",
-							orient: "horizontal",
-							itemWidth: 8,
+							bottom: 0,
+							itemWidth: 12,
 							itemHeight: 8, // 修改icon图形大小
 							textStyle: {
 								fontSize: 12,
-								color: "#333"
-							},
-							formatter: function (name) {
-								if (name.length > 6) {
-									name = name.slice(0, 6) + "...";
-								}
-								return name;
+								color: "#666",
+								fontFamily: "Hm"
 							},
 							tooltip: {
 								show: true
@@ -426,43 +422,28 @@
 								name: this.$t("areaStatistics.basics.schoolP"),
 								type: "pie",
 								radius: "65%",
-								center: ["40%", "40%"],
-								itemStyle: {
-									borderRadius: 5
-								},
+								center: ["50%", "40%"],
 								label: {
 									normal: {
-										position: "inner",
-										show: false
+										position: "outer",
+										show: true
 									}
 								},
-								data: [
-									{ value: 1340, name: "锦江区外国语小学" },
-									{ value: 380, name: "川师大附小" },
-									{ value: 658, name: "树德中学" },
-									{ value: 936, name: "石室中学" },
-									{ value: 200, name: "石室小学" }
-								]
+								data: []
 							}
 						]
 					},
 					//上周课例对比
 					lastweek: {
-						color: ["#3fb1e3", "#6be6c1", "#626c91", "#a0a7e6", "#c4ebad", "#96dee8"],
+						color: ["#afa3f5", "#00d488", "#3feed4", "#3bafff", "#f1bb4c"],
 						legend: {
-							right: "1%",
-							orient: "vertical",
-							itemWidth: 8,
+							bottom: 0,
+							itemWidth: 12,
 							itemHeight: 8, // 修改icon图形大小
 							textStyle: {
 								fontSize: 12,
-								color: "#333"
-							},
-							formatter: function (name) {
-								if (name.length > 12) {
-									name = name.slice(0, 12) + "...";
-								}
-								return name;
+								color: "#666",
+								fontFamily: "Hm"
 							},
 							tooltip: {
 								show: true
@@ -472,44 +453,29 @@
 							{
 								name: this.$t("areaStatistics.basics.schoolP"),
 								type: "pie",
-								radius: "75%",
-								center: ["30%", "50%"],
-								itemStyle: {
-									borderRadius: 5
-								},
+								radius: "65%",
+								center: ["50%", "40%"],
 								label: {
 									normal: {
-										position: "inner",
-										show: false
+										position: "outer",
+										show: true
 									}
 								},
-								data: [
-									// { value: 1340, name: '锦江区外国语小学' },
-									// { value: 380, name: '川师大附小' },
-									// { value: 58, name: '树德中学' },
-									// { value: 36, name: '石室中学' },
-									// { value: 100, name: '石室小学' },
-								]
+								data: []
 							}
 						]
 					},
 					//本月课例对比
 					monthsContrast: {
-						color: ["#3fb1e3", "#6be6c1", "#626c91", "#a0a7e6", "#c4ebad", "#96dee8"],
+						color: ["#afa3f5", "#00d488", "#3feed4", "#3bafff", "#f1bb4c"],
 						legend: {
-							right: "1%",
-							orient: "vertical",
-							itemWidth: 8,
+							bottom: 0,
+							itemWidth: 12,
 							itemHeight: 8, // 修改icon图形大小
 							textStyle: {
 								fontSize: 12,
-								color: "#333"
-							},
-							formatter: function (name) {
-								if (name.length > 12) {
-									name = name.slice(0, 12) + "...";
-								}
-								return name;
+								color: "#666",
+								fontFamily: "Hm"
 							},
 							tooltip: {
 								show: true
@@ -519,22 +485,15 @@
 							{
 								name: this.$t("areaStatistics.basics.schoolP"),
 								type: "pie",
-								radius: "75%",
-								center: ["30%", "50%"],
-								itemStyle: {
-									borderRadius: 5
-								},
+								radius: "65%",
+								center: ["50%", "40%"],
 								label: {
 									normal: {
-										position: "inner",
-										show: false
+										position: "outer",
+										show: true
 									}
 								},
-								data: [
-									// { value: 140, name: '锦江区外国语小学' },
-									// { value: 380, name: '川师大附小' },
-									// { value: 100, name: '石室小学' },
-								]
+								data: []
 							}
 						]
 					},
@@ -562,12 +521,19 @@
 							}
 						},
 						calculable: true,
+						legend: {
+							textStyle: {
+								fontFamily: "Hm"
+							},
+							itemWidth: 12,
+							itemHeight: 10
+						},
 						xAxis: [
 							{
 								type: "category",
 								axisLine: {
 									lineStyle: {
-										color: "rgba(204,187,225,0.5)"
+										color: "#666"
 									}
 								},
 								splitLine: {
@@ -576,6 +542,11 @@
 								axisTick: {
 									show: false
 								},
+								axisLabel: {
+									// 其他样式设置,如字体大小、颜色等
+									fontFamily: "Hm",
+									padding: [10, 0]
+								},
 								data: []
 							}
 						],
@@ -587,8 +558,13 @@
 								},
 								axisLine: {
 									lineStyle: {
-										color: "rgba(204,187,225,0.5)"
+										color: "#666"
 									}
+								},
+								axisLabel: {
+									// 其他样式设置,如字体大小、颜色等
+									fontFamily: "Hm",
+									padding: [0, 5]
 								}
 							}
 						],
@@ -597,7 +573,7 @@
 								show: true,
 								height: 10,
 								xAxisIndex: [0],
-								bottom: 10,
+								bottom: 0,
 								start: 0,
 								end: 65,
 								handleIcon: "path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z",
@@ -664,21 +640,17 @@
 							formatter: "{a} <br/>{b} : {c} ({d}%)"
 						},
 						legend: {
-							orient: "vertical",
-							right: "5%",
-							top: "15%",
-							bottom: "15%",
-							itemWidth: 15,
-							itemHeight: 15,
+							bottom: 0,
+							itemWidth: 12,
+							itemHeight: 8, // 修改icon图形大小
 							textStyle: {
-								fontSize: 12
+								fontSize: 12,
+								color: "#666",
+								fontFamily: "Hm"
 							},
-							data: [
-								//{ value: 0, name: '线上研修' },
-								//{ value: 0, name: '校本研修' },
-								//{ value: 0, name: '认证材料' },
-								//{ value: 0, name: '课堂实录' },
-							]
+							tooltip: {
+								show: true
+							}
 						},
 						series: [
 							{
@@ -686,7 +658,8 @@
 								name: "",
 								type: "pie",
 								selectedMode: "single",
-								radius: [0, "55%"],
+								radius: [0, "35%"],
+								center:['50%','40%'],
 								label: {
 									normal: {
 										position: "inner",
@@ -707,7 +680,8 @@
 							{
 								name: this.$t("areaStatistics.basics.scheduleP"),
 								type: "pie",
-								radius: ["65%", "90%"],
+								center:['50%','40%'],
+								radius: ["45%", "65%"],
 								data: [
 									//{ value: 0, name: '线上研修' },
 									//{ value: 0, name: '校本研修' },
@@ -724,13 +698,16 @@
 						// color: ['#05f8d6', '#0082fc', '#fdd845', '#22ed7c', '#09b0d3', '#1d27c9', '#f9e264', '#f47a75', '#009db2', '#024b51', '#0780cf', '#765005'],
 						color: ["#3fb1e3", "#6be6c1", "#626c91", "#a0a7e6", "#c4ebad", "#96dee8", "#05f8d6", "#09b0d3", "#765005", "#22ed7c", "#fdd845", "#0082fc"],
 						legend: {
-							right: "1%",
-							orient: "vertical",
-							itemWidth: 8,
+							bottom: 0,
+							itemWidth: 12,
 							itemHeight: 8, // 修改icon图形大小
 							textStyle: {
 								fontSize: 12,
-								color: "#333"
+								color: "#666",
+								fontFamily: "Hm"
+							},
+							tooltip: {
+								show: true
 							}
 						},
 						tooltip: {
@@ -743,8 +720,8 @@
 							{
 								name: this.$t("areaStatistics.basics.sizeP"),
 								type: "pie",
-								radius: "90%",
-								center: ["50%", "50%"],
+								radius: "65%",
+								center: ["50%", "40%"],
 								itemStyle: {
 									borderRadius: 8,
 									normal: {
@@ -1053,13 +1030,16 @@
 	};
 </script>
 
-<style scoped>
+<style lang="less" scoped>
+	:deep(.listbox .ivu-table-header thead tr th){
+		padding: 20px 0;
+	}
 	.statisticsbox,
 	.statisticsbox-all {
 		width: 100%;
 		height: 100%;
 		padding: 1.5%;
-		line-height: 20px;
+		/* line-height: 20px; */
 		overflow: auto;
 		background: #f2f2f2;
 	}
@@ -1100,15 +1080,13 @@
 
 	.right-top-text {
 		width: 64%;
-		/* background: rgba(178, 190, 195, 0.2);*/
 		background: #fff;
 		float: left;
-		height: 100%;
+		height: 110px;
 		display: flex;
-    flex-direction: column;
-    justify-content: center;
-    align-items: center;
-    padding-top: 15px;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
 	}
 
 	.top-header-icon {
@@ -1123,12 +1101,9 @@
 	}
 
 	.right-top-num {
-		/* position: absolute; */
-		font-size: 48px;
-		/* top: 25%;
-		left: 50%; */
-		/* transform: translate(-50%, -50%); */
-		color: #515a6e;
+		font-size: 40px;
+		font-weight: 600;
+		color: #5f5f5f;
 	}
 
 	.right-top-num span {
@@ -1140,9 +1115,10 @@
 	.right-top-bottombox {
 		width: 100%;
 		text-align: center;
-    margin-top: 15px;
-		line-height: 14px;
-    color: #ccc;
+		/* margin-top: 15px; */
+		/* line-height: 14px; */
+		margin-bottom: 5px;
+		color: #ccc;
 	}
 
 	.right-top-bottombox-title,
@@ -1196,7 +1172,7 @@
 		flex-wrap: wrap;
 		background-color: #fff;
 		margin-top: 30px;
-		padding: 15px;
+		padding: 60px 15px 30px 15px;
 		position: relative;
 		justify-content: space-between;
 		border-radius: 5px;
@@ -1214,47 +1190,26 @@
 		border-radius: 5px;
 	}
 
-	.alonebox {
-		width: 19%;
-		padding: 7px;
-		text-align: left;
-		background-color: #b8ced7;
-		border-radius: 5px;
-		margin: 2% 2.5%;
-	}
-
+	.alonebox,
 	.totalalonebox {
 		width: 19%;
 		padding: 7px;
-		text-align: left;
-		background-color: #96c3d7;
-		border-radius: 5px;
-		margin: 1% 2.5%;
-	}
-
-	.alonebox-title {
-		font-size: 14px;
-		color: #535c68;
-		font-weight: 600;
-		margin-bottom: 16px;
+		text-align: center;
+		color: #a19f9f;
+		/* background-color: #96c3d7; */
+		margin: 1% 2%;
 	}
 
+	.alonebox-title,
 	.total-alonebox-title {
 		font-size: 14px;
-		font-weight: 600;
-		color: #dff9fb;
-		margin-bottom: 16px;
-	}
-
-	.alonebox-content {
-		font-size: 26px;
-		color: #fff;
-		font-weight: 750;
+		margin-top: 10px;
+		margin-bottom: 10px;
 	}
-
+	.alonebox-content,
 	.total-alonebox-content {
-		font-size: 26px;
-		color: #fff;
+		font-size: 32px;
+		color: #5f5f5f;
 		font-weight: 750;
 	}
 
@@ -1267,25 +1222,27 @@
 		width: 100%;
 		height: 40px;
 		position: absolute;
-		top: 3px;
+		top: 10px;
 		left: 1px;
 	}
 
 	.tags {
-		width: 100px;
-		height: 20px;
+		width: 120px;
+		height: 30px;
 		background: rgb(256 169 100) no-repeat center;
 		background-size: contain;
-		font-size: 12px;
+		font-size: 13px;
 		font-weight: 400;
 		color: #ffffff;
 		text-align: center;
 		position: relative;
-		display: block;
+		display: flex;
+		align-items: center;
+		padding-left: 20px;
 	}
 
 	.tags:after {
-		border: 12px solid #fff;
+		border: 15px solid #fff;
 		content: "";
 		border-top-color: transparent;
 		border-left-color: transparent;
@@ -1293,7 +1250,7 @@
 		width: 0px;
 		height: 0px;
 		position: absolute;
-		left: calc(118px - 40px);
+		left: calc(130px - 40px);
 		top: 0px;
 	}
 
@@ -1307,22 +1264,29 @@
 
 	.center-resource-left {
 		width: 48%;
-		height: 300px;
+		/* height: 300px; */
 		position: relative;
 		background: #fff;
-		padding: 15px;
+		/* padding: 15px; */
+		padding: 60px 20px 30px 20px;
 		display: flex;
 		justify-content: space-between;
 		border-radius: 5px;
 	}
 
+	.center-resource-left .chats-tabs {
+		position: absolute;
+		right: 20px;
+		top: 20px;
+	}
+
 	.center-resource-right {
 		width: 50%;
 		/* margin-left: 2%; */
-		height: 300px;
+		/* height: 300px; */
 		position: relative;
 		background: #fff;
-		padding: 23px;
+		padding: 60px 20px 30px 20px;
 		overflow: hidden;
 		border-radius: 5px;
 	}
@@ -1344,22 +1308,24 @@
 
 	.bottom-leftbox {
 		width: 48%;
-		padding: 1%;
-		height: 200px;
+		/* padding: 1%; */
+		height: 400px;
 		background: #fff;
 		position: relative;
 		border-radius: 5px;
+		padding: 60px 20px 30px 20px;
 	}
 
 	.bottom-rightbox {
 		width: 50%;
-		height: 200px;
+		/* height: 200px; */
 		background-color: #fff;
 		display: flex;
 		justify-content: center;
 		position: relative;
 		margin-left: 2%;
 		border-radius: 5px;
+		padding: 60px 20px 30px 20px;
 	}
 
 	.bottom-rightbox-left {
@@ -1369,7 +1335,7 @@
 	}
 
 	.bottom-rightbox-right {
-		width: 55%;
+		width: 100%;
 		height: 100%;
 	}
 
@@ -1541,7 +1507,7 @@
 
 	.center-resource-left-leftEcharts,
 	.center-resource-left-rightbox {
-		width: 50%;
+		width: 100%;
 		height: 270px;
 		position: relative;
 	}
@@ -1678,7 +1644,7 @@
 	.school-Listinfo {
 		width: 100%;
 		margin-top: 0px;
-		padding: 30px 15px 15px 15px;
+		padding: 60px 15px 15px 15px;
 		position: relative;
 		background-color: #fff;
 		margin-bottom: 30px;
@@ -1729,13 +1695,17 @@
 		top: 30%;
 	}
 	.schoolImg {
-		width: 15%;
+		width: 50px;
+		margin: 15px 0;
+		border-radius: 50%;
 	}
 	.schoolnot {
-		width: 20%;
-		line-height: 60px;
-		margin: 0 auto;
-		background: #95a5a6;
+		width: 50px;
+		height: 50px;
+		margin: 15px auto;
+		font-size: 12px;
+		background: #c1c3c4;
+		border-radius: 50%;
 		color: #ecf0f1;
 		display: flex;
 		justify-content: center;

+ 403 - 394
TEAMModelOS/ClientApp/src/view/art/SchoolArt.vue

@@ -1,403 +1,412 @@
 <template>
-  <div id="artIndex" ref="appRef">
-    <div class="bg">
-      <dv-loading v-if="loading">{{ $t('researchCenter.dashboard.loading') }}</dv-loading>
-      <div v-else class="host-body">
-        <!-- 实时北京时间 -->
-        <div class="tools">
-          <span class="time-text">{{ dateYear }} <span style="display: inline-block; margin: 0 5px;color: #0fa2fe;">{{ dateDay }}</span> </span>
-          <span class="icon iconfont icon-download" v-if="!isNoData" style="font-size: 22px;margin-right:10px" :title="`下载艺术评测数据表`" @click="exportArtTable"></span>
-          <span class="icon iconfont icon-tuichuquanping" style="font-size: 22px;" :title="$t('researchCenter.dashboard.quit')" @click="goBack"></span>
-        </div>
-        <!-- 学校基础信息 及 活动、科目选择 -->
-        <div class="school-info">
-          <img :src="schoolInfo.schoolLogo">
-          <span class="school-info-name">{{ schoolInfo.schoolName }}</span>
-          <span class="school-info-period">{{ schoolInfo.periodName }}</span>
-          <span class="school-info-semester" v-if="!$route.params.artInfo">{{ schoolInfo.curSemester }}</span>
-          <div style="margin-left: 15px">
-            <Select v-model="activeAcIndex" @on-change="onAcChange">
-              <Option v-for="(item,index) in acList" :value="index">{{ item.name }}</Option>
-            </Select>
-          </div>
-          <div class="dashboard-select-subject">
-            <Select v-model="curSubjectIndex" @on-change="onSubjectChange">
-              <Option v-for="(item,index) in subjectList" :value="index">{{ item.name }}</Option>
-            </Select>
-          </div>
-        </div>
-        <!-- 头部标题 -->
-        <div class="d-flex jc-center" style="margin-top:-5px">
-          <dv-decoration-10 class="dv-dec-10" />
-          <div class="d-flex jc-center">
-            <dv-decoration-8 class="dv-dec-8" :color="['#568aea', '#000000']" />
-            <div class="title">
-              <span class="dash-title-text">艺术测评看板</span>
-              <dv-decoration-6 class="dv-dec-6" :reverse="true" :color="['#50e3c2', '#67a1e5']" />
-            </div>
-            <dv-decoration-8 class="dv-dec-8" :reverse="true" :color="['#568aea', '#000000']" />
-          </div>
-          <dv-decoration-10 class="dv-dec-10-s" />
-        </div>
-        <!-- 图表区域 -->
-        <div class="body-box">
-          <div class="left-box">
-            <div class="left-box-top">
-              <dv-border-box-12>
-                <LeftTop />
-              </dv-border-box-12>
-            </div>
-            <div class="left-box-center">
-              <dv-border-box-12>
-                <RightTop />
-              </dv-border-box-12>
-            </div>
-          </div>
+	<div id="artIndex" ref="appRef">
+		<div class="bg">
+			<dv-loading v-if="loading">{{ $t("researchCenter.dashboard.loading") }}</dv-loading>
+			<div v-else class="host-body">
+				<!-- 实时北京时间 -->
+				<div class="tools">
+					<span class="time-text"
+						>{{ dateYear }} <span style="display: inline-block; margin: 0 5px; color: #0fa2fe">{{ dateDay }}</span>
+					</span>
+					<span class="icon iconfont icon-download" v-if="!isNoData" style="font-size: 22px; margin-right: 10px" :title="`下载艺术评测数据表`" @click="exportArtTable"></span>
+					<span class="icon iconfont icon-tuichuquanping" style="font-size: 22px" :title="$t('researchCenter.dashboard.quit')" @click="goBack"></span>
+				</div>
+				<!-- 学校基础信息 及 活动、科目选择 -->
+				<div class="school-info">
+					<img :src="schoolInfo.schoolLogo" />
+					<span class="school-info-name">{{ schoolInfo.schoolName }}</span>
+					<span class="school-info-period">{{ schoolInfo.periodName }}</span>
+					<span class="school-info-semester" v-if="!$route.params.artInfo">{{ schoolInfo.curSemester }}</span>
+					<div style="margin-left: 15px">
+						<Select v-model="activeAcIndex" @on-change="onAcChange">
+							<Option v-for="(item, index) in acList" :value="index">{{ item.name }}</Option>
+						</Select>
+					</div>
+					<div class="dashboard-select-subject">
+						<Select v-model="curSubjectIndex" @on-change="onSubjectChange">
+							<Option v-for="(item, index) in subjectList" :value="index">{{ item.name }}</Option>
+						</Select>
+					</div>
+				</div>
+				<!-- 头部标题 -->
+				<div class="d-flex jc-center" style="margin-top: -5px">
+					<dv-decoration-10 class="dv-dec-10" />
+					<div class="d-flex jc-center">
+						<dv-decoration-8 class="dv-dec-8" :color="['#568aea', '#000000']" />
+						<div class="title">
+							<span class="dash-title-text">艺术测评看板</span>
+							<dv-decoration-6 class="dv-dec-6" :reverse="true" :color="['#50e3c2', '#67a1e5']" />
+						</div>
+						<dv-decoration-8 class="dv-dec-8" :reverse="true" :color="['#568aea', '#000000']" />
+					</div>
+					<dv-decoration-10 class="dv-dec-10-s" />
+				</div>
+				<!-- 图表区域 -->
+				<div class="body-box">
+					<div class="left-box">
+						<div class="left-box-top">
+							<dv-border-box-12>
+								<LeftTop />
+							</dv-border-box-12>
+						</div>
+						<div class="left-box-center">
+							<dv-border-box-12>
+								<RightTop />
+							</dv-border-box-12>
+						</div>
+					</div>
 
-          <div class="right-box">
-            <div class="right-box-top">
-              <dv-border-box-12>
-                <LeftBottom />
-              </dv-border-box-12>
-            </div>
-            <div class="right-box-bottom">
-              <div class="right-bottom-single">
-                <dv-border-box-12>
-                  <RightBotL />
-                </dv-border-box-12>
-              </div>
-              <div class="right-bottom-single">
-                <dv-border-box-12>
-                  <RightBotR />
-                </dv-border-box-12>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
+					<div class="right-box">
+						<div class="right-box-top">
+							<dv-border-box-12>
+								<LeftBottom />
+							</dv-border-box-12>
+						</div>
+						<div class="right-box-bottom">
+							<div class="right-bottom-single">
+								<dv-border-box-12>
+									<RightBotL />
+								</dv-border-box-12>
+							</div>
+							<div class="right-bottom-single">
+								<dv-border-box-12>
+									<RightBotR />
+								</dv-border-box-12>
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
 </template>
 
 <script>
-import excel from '@/utils/excel.js'
-import RightBotR from '@/components/dashboard/art/RightBotR'
-import RightBotL from '@/components/dashboard/art/RightBotL'
-import LeftTop from '@/components/dashboard/art/LeftTop'
-import LeftCenter from '@/components/dashboard/art/LeftCenter'
-import LeftBottom from '@/components/dashboard/art/LeftBottom'
-import RightTop from '@/components/dashboard/art/RightTop'
-export default {
-  data() {
-    return {
-      isNoData: false,
-      schCodeFromArea: null,
-      activeAcIndex: 0,
-      acList: [],
-      curAcSummary: null,
-      subjectList: [],
-      activeMenu: 'music',
-      activeClassIndex: -1,
-      activeGradeIndex: 0,
-      curSubjectIndex: 0,
-      timing: null,
-      loading: true,
-      dateDay: null,
-      dateYear: null,
-      dateWeek: null,
-    }
-  },
-  components: {
-    RightBotR,
-    RightBotL,
-    LeftTop,
-    LeftCenter,
-    LeftBottom,
-    RightTop,
-  },
-  mounted() {
-    this.$tools.fullScreen(document.getElementById('artIndex'))
-    this.timeFn()
-  },
-  beforeDestroy() {
-    clearInterval(this.timing)
-  },
-  created() {
-    let params = this.$route.params
-    /* 从区级选择任意一个学校跳转过来的 */
-    console.log(params)
-    if (params.artInfo) {
-      this.findAreaSchoolAnalysis(params.artInfo)
-      this.schCodeFromArea = params.artInfo.code
-    } else {
-      this.findArtList()
-    }
-  },
-  methods: {
-    /* 查询区级任意一个学校的艺术评测看板数据 */
-    findAreaSchoolAnalysis(artInfo) {
-      this.$api.areaArt.findArtSummary({
-        id: artInfo.artId,
-        code: artInfo.code
-      }).then(
-        (res) => {
-          if (!res.error) {
-            this.curAcSummary = res.art
-            // 根据勾选的指标 展示表格的列 其中用户信息列和总分列是固定展示
-            this.subjectList = res.art.subjects
-            this.curSubjectIndex = 0
-            let curSubjectId = this.subjectList[this.curSubjectIndex].id
-            this.acList = [{
-              id: artInfo.artId,
-              name: res.art.name
-            }]
-            this.loading = true
-            // 获取看板数据
-            this.$api.areaArt.findArtDashAnalysis({
-              "code": artInfo.code,
-              "periodId": artInfo.perId,
-              "subjectId": curSubjectId,
-              "areaId": sessionStorage.getItem('areaId'),
-              "id": artInfo.artId,
-              "classIds": res.art.classes,
-              'examId': res.art.settings.find(i => i.id === 'quota_21').task.find(k => k.subject === curSubjectId).acId
-            }).then(analysisRes => {
-              console.log(analysisRes)
-              if (analysisRes.code === 500) {
-                this.$Message.error('数据获取异常')
-              } else {
-                console.error(analysisRes)
-                // 保存到vuex
-                this.$store.commit('artDashboard/setAnalysisJson', analysisRes)
-              }
-              this.cancelLoading()
-            })
-          }
-        },
-        (err) => {
-          this.$Message.error(err)
-        }
-      )
-    },
-    /* 查询活动列表 */
-    findArtList() {
-      let params = {
-        code: this.$store.state.userInfo.schoolCode
-      }
-      this.$api.areaArt.findArtList(params).then(
-        (res) => {
-          this.acList = res.arts.filter(i => i.progress === 'finish')
-          if (this.acList.length) {
-            this.onAcChange(0)
-          }
-        },
-        (err) => { }
-      )
-    },
-    /* 查询艺术活动详情 */
-    findArtSummary(acId) {
-      let params = {
-        id: acId,
-        code: this.$store.state.userInfo.schoolCode
-      }
-      this.$api.areaArt.findArtSummary(params).then(
-        (res) => {
-          if (!res.error) {
-            this.curAcSummary = res.art
-            // 根据勾选的指标 展示表格的列 其中用户信息列和总分列是固定展示
-            this.subjectList = res.art.subjects
-            this.curSubjectIndex = 0
-            this.onSubjectChange()
-          }
-        },
-        (err) => {
-          this.$Message.error(err)
-        }
-      )
-    },
-    /* 活动切换 */
-    onAcChange(val) {
-      this.activeAcIndex = val
-      this.findArtSummary(this.acList[val].id)
-    },
-    /* 科目切换 */
-    onSubjectChange() {
-      let curSubjectId = this.subjectList[this.curSubjectIndex].id
-      this.loading = true
-      // 获取看板数据
-      this.$api.areaArt.findArtDashAnalysis({
-        "code": this.schCodeFromArea || this.$store.state.userInfo.schoolCode,
-        "periodId": this.schoolInfo.periodId,
-        "subjectId": curSubjectId,
-        "areaId": sessionStorage.getItem('areaId'),
-        "id": this.acList[this.activeAcIndex].id,
-        "classIds": this.curAcSummary.classes,
-        'examId': this.curAcSummary.settings.find(i => i.id === 'quota_21').task.find(k => k.subject === curSubjectId).acId
-      }).then(res => {
-        console.log(res);
-        // 保存到vuex
-        this.$store.commit('artDashboard/setAnalysisJson', res)
-        this.cancelLoading()
-      }).catch(err => {
-        console.log(err);
-      })
-    },
-    /* 返回上级 */
-    goBack() {
-      this.$tools.exitFullscreen()
-      // this.$router.push('/home/Dashboard')
-      // if (localStorage.getItem('platform') === 'area') {
-      //   this.$router.push('/area/areaArt')
-      // } else {
-      //   this.$router.push('/home/Dashboard')
-      // }
-      this.$router.go(-1)
-    },
-    exportArtTable() {
-      let sheets = []
-      let analysisJson = this.$store.state.artDashboard.artAnalysisJson
-      // 校级概况sheet
-      let schoolHeader = ['应考人数', '实考人数', '最高分(总)', '最低分(总)', '平均分(总)', '优秀率', '及格率', '标准差', '年级测评平均分', '年级测评最高分', '年级测评优秀率', '年级测评及格率']
-      let schoolKeys = ['count', 'scount', 'max', 'min', 'average', 'excellent', 'pass', 'pow', 'gradeAverage', 'gradeMax', 'gradeExcellent', 'gradePass']
-      let schoolDatas = [{
-        count: analysisJson.count,
-        scount: analysisJson.scount,
-        max: analysisJson.max,
-        min: analysisJson.min,
-        average: analysisJson.average,
-        excellent: parseInt(analysisJson.excellent * 100) + '%',
-        pass: parseInt(analysisJson.pass * 100) + '%',
-        pow: analysisJson.pow,
-        gradeAverage: analysisJson.gscore[0].score,
-        gradeMax: analysisJson.gscore[0].max,
-        gradeExcellent: analysisJson.gscore[0].excellent,
-        gradePass: analysisJson.gscore[0].pass
-      }]
-      const schoolSheet = {
-        title: schoolHeader,
-        key: schoolKeys,
-        data: schoolDatas,
-        filename: '校级概况',
-        autoWidth: true
-      }
-      sheets.push(schoolSheet)
-      // 班级概况sheet
-      let classHeaders = ['班级名称', '平均分', '最高分', '最低分', '优秀率', '及格率']
-      let classKeys = ['name', 'average', 'max', 'min', 'excellent', 'pass']
-      let classDatas = analysisJson.cInfo.map(classItem => {
-        return {
-          name: classItem.name,
-          average: classItem.score,
-          max: classItem.max,
-          min: classItem.min,
-          excellent: parseInt(classItem.excellent * 100) + '%',
-          pass: parseInt(classItem.pass * 100) + '%'
-        }
-      })
-      const classSheet = {
-        title: classHeaders,
-        key: classKeys,
-        data: classDatas,
-        filename: '测评情况统计(班级)',
-        autoWidth: true
-      }
-      sheets.push(classSheet)
-      // 学生测评sheet
-      let stuHeaders = ['班级名称', '年级', '学生姓名', '学生学号', '测评得分', '测评得分率', '稳定度系数', '稳定度区级']
-      let stuKeys = ['className', 'gradeName', 'name', 'id', 'score', 'pass', 'sta', 'stu']
-      let stuDatas = analysisJson.students.map(stu => {
-        return {
-          className: stu.className,
-          gradeName: stu.gradeId,
-          name: stu.name,
-          id: stu.id,
-          score: stu.score,
-          pass: parseInt(stu.score) + '%',
-          sta: stu.sta,
-          stu: stu.stu
-        }
-      })
-      const stuSheet = {
-        title: stuHeaders,
-        key: stuKeys,
-        data: stuDatas,
-        filename: '测评详细统计(学生)',
-        autoWidth: true
-      }
-      sheets.push(stuSheet)
-      // 学生测评sheet
-      let knoHeaders = ['知识点名称', '知识块名称', '知识块配分', '知识块维度', '知识点得分率']
-      let knoKeys = ['pointName', 'blockName', 'blockScore', 'dim', 'pointScoreRate']
-      let knoDatas = []
-      analysisJson.kno.forEach(point => {
-        point.block.forEach(block => {
-          knoDatas.push(
-            {
-              pointName: point.name,
-              blockName: block,
-              blockScore: analysisJson.blk.find(i => i.name === block).score,
-              dim: analysisJson.blk.find(i => i.name === block).dimension[0],
-              pointScoreRate: parseInt(point.score * 100) + '%'
-            }
-          )
-        })
-      })
-      const knoSheet = {
-        title: knoHeaders,
-        key: knoKeys,
-        data: knoDatas,
-        filename: '知识点得分率',
-        autoWidth: true
-      }
-      sheets.push(knoSheet)
-      excel.export_array_to_sheet(sheets, `${this.artName}(${this.subjectList[this.curSubjectIndex].name})- 校级艺术评测报告`)
-    },
-    /* 格式化最新时间 */
-    timeFn() {
-      this.timing = setInterval(() => {
-        this.dateDay = this.$tools.formatTime(new Date(), 'hh:mm:ss')
-        this.dateYear = this.$tools.formatTime(new Date(), 'yyyy-MM-dd')
-      }, 1000)
-    },
-    /* 取消加载 */
-    cancelLoading() {
-      setTimeout(() => {
-        this.loading = false
-      }, 100)
-    },
-  },
-  computed: {
-    schoolInfo() {
-      let artInfo = this.$route.params.artInfo
-      console.log(artInfo)
-      this.artName = artInfo.name
-      if (artInfo) {
-        return {
-          schoolName: artInfo.name,
-          schoolLogo: '',
-          periodName: artInfo.perCname,
-          periodId: artInfo.perId,
-          curSemester: ''
-        }
-      } else {
-        let store_user = this.$store.state.user
-        let semesterRange = this.$tools.getSemesterTimeRange()
-        return {
-          schoolName: store_user.schoolProfile.school_base.name,
-          schoolLogo: store_user.schoolProfile.school_base.picture,
-          periodName: store_user.curPeriod.name,
-          periodId: store_user.curPeriod.id,
-          curSemester: semesterRange.name_with_year
-        }
-      }
-
-    }
-  }
-}
+	import excel from "@/utils/excel.js";
+	import RightBotR from "@/components/dashboard/art/RightBotR";
+	import RightBotL from "@/components/dashboard/art/RightBotL";
+	import LeftTop from "@/components/dashboard/art/LeftTop";
+	import LeftCenter from "@/components/dashboard/art/LeftCenter";
+	import LeftBottom from "@/components/dashboard/art/LeftBottom";
+	import RightTop from "@/components/dashboard/art/RightTop";
+	export default {
+		data() {
+			return {
+				isNoData: false,
+				schCodeFromArea: null,
+				activeAcIndex: 0,
+				acList: [],
+				curAcSummary: null,
+				subjectList: [],
+				activeMenu: "music",
+				activeClassIndex: -1,
+				activeGradeIndex: 0,
+				curSubjectIndex: 0,
+				timing: null,
+				loading: true,
+				dateDay: null,
+				dateYear: null,
+				dateWeek: null
+			};
+		},
+		components: {
+			RightBotR,
+			RightBotL,
+			LeftTop,
+			LeftCenter,
+			LeftBottom,
+			RightTop
+		},
+		mounted() {
+			this.$tools.fullScreen(document.getElementById("artIndex"));
+			this.timeFn();
+		},
+		beforeDestroy() {
+			clearInterval(this.timing);
+		},
+		created() {
+			let params = this.$route.params;
+			/* 从区级选择任意一个学校跳转过来的 */
+			console.log(params);
+			if (params.artInfo) {
+				this.findAreaSchoolAnalysis(params.artInfo);
+				this.schCodeFromArea = params.artInfo.code;
+			} else {
+				this.findArtList();
+			}
+		},
+		methods: {
+			/* 查询区级任意一个学校的艺术评测看板数据 */
+			findAreaSchoolAnalysis(artInfo) {
+				this.$api.areaArt
+					.findArtSummary({
+						id: artInfo.artId,
+						code: artInfo.code
+					})
+					.then(
+						(res) => {
+							if (!res.error) {
+								this.curAcSummary = res.art;
+								// 根据勾选的指标 展示表格的列 其中用户信息列和总分列是固定展示
+								this.subjectList = res.art.subjects;
+								this.curSubjectIndex = 0;
+								let curSubjectId = this.subjectList[this.curSubjectIndex].id;
+								this.acList = [
+									{
+										id: artInfo.artId,
+										name: res.art.name
+									}
+								];
+								this.loading = true;
+								// 获取看板数据
+								this.$api.areaArt
+									.findArtDashAnalysis({
+										code: artInfo.code,
+										periodId: artInfo.perId,
+										subjectId: curSubjectId,
+										areaId: sessionStorage.getItem("areaId"),
+										id: artInfo.artId,
+										classIds: res.art.classes,
+										examId: res.art.settings.find((i) => i.id === "quota_21").task.find((k) => k.subject === curSubjectId).acId
+									})
+									.then((analysisRes) => {
+										console.log(analysisRes);
+										if (analysisRes.code === 500) {
+											this.$Message.error("数据获取异常");
+										} else {
+											console.error(analysisRes);
+											// 保存到vuex
+											this.$store.commit("artDashboard/setAnalysisJson", analysisRes);
+										}
+										this.cancelLoading();
+									});
+							}
+						},
+						(err) => {
+							this.$Message.error(err);
+						}
+					);
+			},
+			/* 查询活动列表 */
+			findArtList() {
+				let params = {
+					code: this.$store.state.userInfo.schoolCode
+				};
+				this.$api.areaArt.findArtList(params).then(
+					(res) => {
+						this.acList = res.arts.filter((i) => i.progress === "finish");
+						if (this.acList.length) {
+							this.onAcChange(0);
+						}
+					},
+					(err) => {}
+				);
+			},
+			/* 查询艺术活动详情 */
+			findArtSummary(acId) {
+				let params = {
+					id: acId,
+					code: this.$store.state.userInfo.schoolCode
+				};
+				this.$api.areaArt.findArtSummary(params).then(
+					(res) => {
+						if (!res.error) {
+							this.curAcSummary = res.art;
+							// 根据勾选的指标 展示表格的列 其中用户信息列和总分列是固定展示
+							this.subjectList = res.art.subjects;
+							this.curSubjectIndex = 0;
+							this.onSubjectChange();
+						}
+					},
+					(err) => {
+						this.$Message.error(err);
+					}
+				);
+			},
+			/* 活动切换 */
+			onAcChange(val) {
+				this.activeAcIndex = val;
+				this.findArtSummary(this.acList[val].id);
+			},
+			/* 科目切换 */
+			onSubjectChange() {
+				let curSubjectId = this.subjectList[this.curSubjectIndex].id;
+				this.loading = true;
+				// 获取看板数据
+				this.$api.areaArt
+					.findArtDashAnalysis({
+						code: this.schCodeFromArea || this.$store.state.userInfo.schoolCode,
+						periodId: this.schoolInfo.periodId,
+						subjectId: curSubjectId,
+						areaId: sessionStorage.getItem("areaId"),
+						id: this.acList[this.activeAcIndex].id,
+						classIds: this.curAcSummary.classes,
+						examId: this.curAcSummary.settings.find((i) => i.id === "quota_21").task.find((k) => k.subject === curSubjectId).acId
+					})
+					.then((res) => {
+						console.log(res);
+						// 保存到vuex
+						this.$store.commit("artDashboard/setAnalysisJson", res);
+						this.cancelLoading();
+					})
+					.catch((err) => {
+						console.log(err);
+					});
+			},
+			/* 返回上级 */
+			goBack() {
+				this.$tools.exitFullscreen();
+				// this.$router.push('/home/Dashboard')
+				// if (localStorage.getItem('platform') === 'area') {
+				//   this.$router.push('/area/areaArt')
+				// } else {
+				//   this.$router.push('/home/Dashboard')
+				// }
+				this.$router.go(-1);
+			},
+			exportArtTable() {
+				let sheets = [];
+				let analysisJson = this.$store.state.artDashboard.artAnalysisJson;
+				// 校级概况sheet
+				let schoolHeader = ["应考人数", "实考人数", "最高分(总)", "最低分(总)", "平均分(总)", "优秀率", "及格率", "标准差", "年级测评平均分", "年级测评最高分", "年级测评优秀率", "年级测评及格率"];
+				let schoolKeys = ["count", "scount", "max", "min", "average", "excellent", "pass", "pow", "gradeAverage", "gradeMax", "gradeExcellent", "gradePass"];
+				let schoolDatas = [
+					{
+						count: analysisJson.count,
+						scount: analysisJson.scount,
+						max: analysisJson.max,
+						min: analysisJson.min,
+						average: analysisJson.average,
+						excellent: parseInt(analysisJson.excellent * 100) + "%",
+						pass: parseInt(analysisJson.pass * 100) + "%",
+						pow: analysisJson.pow,
+						gradeAverage: analysisJson.gscore[0].score,
+						gradeMax: analysisJson.gscore[0].max,
+						gradeExcellent: analysisJson.gscore[0].excellent,
+						gradePass: analysisJson.gscore[0].pass
+					}
+				];
+				const schoolSheet = {
+					title: schoolHeader,
+					key: schoolKeys,
+					data: schoolDatas,
+					filename: "校级概况",
+					autoWidth: true
+				};
+				sheets.push(schoolSheet);
+				// 班级概况sheet
+				let classHeaders = ["班级名称", "平均分", "最高分", "最低分", "优秀率", "及格率"];
+				let classKeys = ["name", "average", "max", "min", "excellent", "pass"];
+				let classDatas = analysisJson.cInfo.map((classItem) => {
+					return {
+						name: classItem.name,
+						average: classItem.score,
+						max: classItem.max,
+						min: classItem.min,
+						excellent: parseInt(classItem.excellent * 100) + "%",
+						pass: parseInt(classItem.pass * 100) + "%"
+					};
+				});
+				const classSheet = {
+					title: classHeaders,
+					key: classKeys,
+					data: classDatas,
+					filename: "测评情况统计(班级)",
+					autoWidth: true
+				};
+				sheets.push(classSheet);
+				// 学生测评sheet
+				let stuHeaders = ["班级名称", "年级", "学生姓名", "学生学号", "测评得分", "测评得分率", "稳定度系数", "稳定度区级"];
+				let stuKeys = ["className", "gradeName", "name", "id", "score", "pass", "sta", "stu"];
+				let stuDatas = analysisJson.students.map((stu) => {
+					return {
+						className: stu.className,
+						gradeName: stu.gradeId,
+						name: stu.name,
+						id: stu.id,
+						score: stu.score,
+						pass: parseInt(stu.score) + "%",
+						sta: stu.sta,
+						stu: stu.stu
+					};
+				});
+				const stuSheet = {
+					title: stuHeaders,
+					key: stuKeys,
+					data: stuDatas,
+					filename: "测评详细统计(学生)",
+					autoWidth: true
+				};
+				sheets.push(stuSheet);
+				// 学生测评sheet
+				let knoHeaders = ["知识点名称", "知识块名称", "知识块配分", "知识块维度", "知识点得分率"];
+				let knoKeys = ["pointName", "blockName", "blockScore", "dim", "pointScoreRate"];
+				let knoDatas = [];
+				analysisJson.kno.forEach((point) => {
+					point.block.forEach((block) => {
+						knoDatas.push({
+							pointName: point.name,
+							blockName: block,
+							blockScore: analysisJson.blk.find((i) => i.name === block).score,
+							dim: analysisJson.blk.find((i) => i.name === block).dimension[0],
+							pointScoreRate: parseInt(point.score * 100) + "%"
+						});
+					});
+				});
+				const knoSheet = {
+					title: knoHeaders,
+					key: knoKeys,
+					data: knoDatas,
+					filename: "知识点得分率",
+					autoWidth: true
+				};
+				sheets.push(knoSheet);
+				excel.export_array_to_sheet(sheets, `${this.artName}(${this.subjectList[this.curSubjectIndex].name})- 校级艺术评测报告`);
+			},
+			/* 格式化最新时间 */
+			timeFn() {
+				this.timing = setInterval(() => {
+					this.dateDay = this.$tools.formatTime(new Date(), "hh:mm:ss");
+					this.dateYear = this.$tools.formatTime(new Date(), "yyyy-MM-dd");
+				}, 1000);
+			},
+			/* 取消加载 */
+			cancelLoading() {
+				setTimeout(() => {
+					this.loading = false;
+				}, 100);
+			}
+		},
+		computed: {
+			schoolInfo() {
+				let artInfo = this.$route.params.artInfo;
+				console.log(artInfo);
+				this.artName = artInfo.name;
+				if (artInfo) {
+					return {
+						schoolName: artInfo.name,
+						schoolLogo: "",
+						periodName: artInfo.perCname,
+						periodId: artInfo.perId,
+						curSemester: ""
+					};
+				} else {
+					let store_user = this.$store.state.user;
+					let semesterRange = this.$tools.getSemesterTimeRange();
+					return {
+						schoolName: store_user.schoolProfile.school_base.name,
+						schoolLogo: store_user.schoolProfile.school_base.picture,
+						periodName: store_user.curPeriod.name,
+						periodId: store_user.curPeriod.id,
+						curSemester: semesterRange.name_with_year
+					};
+				}
+			}
+		}
+	};
 </script>
 
 <style lang="less">
-@import "../dashboard/Art.less";
-@import "../dashboard/style.less";
+	@import "../dashboard/Art.less";
+	@import "../dashboard/style.less";
 </style>
-

+ 24 - 4
TEAMModelOS/ClientApp/src/view/classrecord/ClassRecord.vue

@@ -149,7 +149,7 @@
                     <!-- 互动数据 -->
                     <div v-for="event in item.pageData" :key="event.Time">
                       <!-- 即问即答 -->
-                      <PopQues class="event-item" v-if="event.Event === 'PopQuesLoad' || event.Event === 'ReAtmpAnsStrt'" :evtType="event.Event" :irsData="event.data" :students="baseData.student"></PopQues>
+                      <PopQues class="event-item" v-if="event.Event === 'PopQuesLoad' || event.Event === 'ReAtmpAnsStrt'" :evtType="event.Event" :irsData="event.data" :students="baseData.student" :recordInfo="recordInfo" :blobInfo="blobInfo"></PopQues>
                       <!-- 抢权 -->
                       <Buzr class="event-item student-event" v-else-if="event.Event === 'BuzrAns'" :buzrData="event.data" :students="baseData.student"></Buzr>
                       <!-- 推送 -->
@@ -164,6 +164,8 @@
                       <Exam class="event-item" :examInfo="event.data" :recordInfo="recordInfo" v-else-if="event.Event === 'SPQStrt'"></Exam>
                       <!-- 智慧评分 -->
                       <SmartRating class="event-item student-event" :recordInfo="recordInfo" :smartRate="event.data" :students="baseData.student" :vote="event.vote" :blobInfo="blobInfo" v-else-if="event.Event === 'RatingStart'"></SmartRating>
+                      <!-- 协作 -->
+                      <Cowork class="event-item student-event" :recordInfo="recordInfo" :blobInfo="blobInfo" :cowork="event.data" :students="baseData.student" v-else-if="event.Event === 'CoworkLoad'"></Cowork>
                     </div>
                   </div>
                 </div>
@@ -262,13 +264,14 @@ import Exam from './eventchart/Exam.vue'
 import Receive from './eventchart/Receive.vue'
 import DataCount from './eventchart/DataCount.vue'
 import SmartRating from './eventchart/SmartRating.vue';
+import Cowork from './eventchart/Cowork.vue';
 import CountTo from 'vue-count-to'
 import BlobTool from '@/utils/blobTool.js'
 import FileSaver from "file-saver";
 import JSZip from "jszip";
 export default {
   components: {
-    PopQues, Pick, Push, Receive, DataCount, CountTo, Buzr, Exam, WrkCmp, BaseReportPie, BaseReportRadar, SmartRating
+    PopQues, Pick, Push, Receive, DataCount, CountTo, Buzr, Exam, WrkCmp, BaseReportPie, BaseReportRadar, SmartRating, Cowork
   },
   data() {
     return {
@@ -308,7 +311,13 @@ export default {
           text: this.$t('cusMgt.rcd.filter6'),
           events: ['RatingStart'],
           count: 0
-        }
+        },
+        {
+          value: 'CoworkLoad',
+          text: this.$t('cusMgt.rcd.filter7'),
+          events: ['CoworkLoad'],
+          count: 0
+        },
       ],
       split1: 0.4,
       backPage: undefined,
@@ -317,6 +326,7 @@ export default {
       irsData: [],//irs.json
       taskData: [],//task.json
       smartData: [],//smartRating.json
+      coworkData: [],//Cowork.json
       fnEvents: [],//功能事件
       events: [],//事件ID
       hiTeachEvent: [],//需要解析的事件信息
@@ -525,7 +535,7 @@ export default {
         return
       }
       // 时间轴数据正常
-      //获取Push.json、IRS.json、Task.json、Base.json数据  新增SmartRating.json(智慧评分)
+      //获取Push.json、IRS.json、Task.json、Base.json数据  新增SmartRating.json(智慧评分)  新增Cowork.json(协作)
       try {
         let pushUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/Push.json${this.blobInfo.blob_sas}`
         this.pushData = JSON.parse(await this.$tools.getFile(pushUrl) || '[]')
@@ -564,6 +574,12 @@ export default {
       } catch (e) {
         this.smartData = []
       }
+      try {
+        let coworkUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/Cowork.json${this.blobInfo.blob_sas}`
+        this.coworkData = JSON.parse(await this.$tools.getFile(coworkUrl) || '[]')
+      } catch (e) {
+        this.coworkData = []
+      }
       let pgids = this.pageIds
       //这里需要判断录制开始的pageid
       // let startInfo = this.pageEvents?.findLast(item => item.Event === 'EzsStartRecord')
@@ -632,6 +648,10 @@ export default {
               }
               this.filterInte[5].count++
               break
+            case 'cowork':
+              e.data = this.coworkData.find(t => t.pageID == e.Pgid)
+              this.filterInte[6].count++
+              break
             default:
               break
           }

+ 14 - 8
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Buzr.vue

@@ -1,11 +1,13 @@
 <template>
     <div class="buzz-wrap">
-        <p class="event-type">
-            {{$t('cusMgt.rcd.evt1')}}
-        </p>
-        <div class="buzz-box" v-for="(item,index) in buzzClients" :key="index">
-            <!-- <Icon custom="iconfont icon-buzz" size="24" /> -->
-            <span>{{getChinese(item.name)}}</span>
+        <div>
+            <p class="event-type">
+                {{$t('cusMgt.rcd.evt1')}}
+            </p>
+            <div class="buzz-box" v-for="(item,index) in buzzClients" :key="index">
+                <!-- <Icon custom="iconfont icon-buzz" size="24" /> -->
+                <span>{{getChinese(item.name)}}</span>
+            </div>
         </div>
         <StudentClient></StudentClient>
     </div>
@@ -106,8 +108,12 @@ export default {
     }
 }
 .event-type {
-    margin-right: 20px;
+    /* margin-right: 20px;
     font-size: 15px;
-    font-weight: 600;
+    font-weight: 600; */
+    
+    text-align: right;
+    font-weight: bold;
+    margin: 0 10px 5px 0;
 }
 </style>

+ 107 - 0
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Cowork.vue

@@ -0,0 +1,107 @@
+<template>
+    <div>
+        <div>
+            <p class="action-type">{{ cowork.coworkType === 'All' ? '全体协作' : (cowork.coworkType === 'Group' ? '分组协作' : '差异化协作') }}</p>
+            <div class="cowork-box">
+                <div v-for="(item, index) in coworkData" :key="index" style="">
+                    <img :src="item.snapshotUrl" class="receive-img" alt="" @click="viewImage(item.snapshotUrl)">
+                    <p>
+                        {{ item.title }}
+                        <Tooltip placement="bottom" v-show="cowork.coworkType != 'All'">
+                            <Icon type="ios-contacts" size="20" color="#2D8CF0" />
+                            <template #content>
+                                <span v-for="(stu, sIndex) in item.stuList" :key="sIndex">
+                                    <span v-if="stu">
+                                        {{ stu.name }}
+                                        <span v-show="sIndex != (item.stuList.length - 1)">、</span>
+                                    </span>
+                                </span>
+                            </template>
+                        </Tooltip>
+                    </p>
+                </div>
+            </div>
+        </div>
+        <StudentClient class="receive-student"></StudentClient>
+    </div>
+</template>
+
+<script>
+import StudentClient from './StudentClient.vue'
+export default {
+    components: {
+        StudentClient
+    },
+    props: {
+        recordInfo: {
+            type: Object,
+            default: () => {
+                return {}
+            }
+        },
+        cowork: {
+            type: Object,
+            default: () => {
+                return {}
+            }
+        },
+        blobInfo: {
+            type: Object,
+            default: () => {
+                return {}
+            }
+        },
+        students: {
+            type: Array,
+            default: () => {
+                return []
+            }
+        },
+    },
+    computed: {
+        coworkData() {
+            let data = []
+            if(this.cowork.coworkGroupInfoList.length) {
+                data = this._.cloneDeep(this.cowork.coworkGroupInfoList)
+                data.forEach(item => {
+                    item.snapshotUrl = `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}${item.snapshot}${this.blobInfo.blob_sas}`
+                    item.stuList = item.members.map(members => {
+                        return this.students.find(stu => stu.seatID == members)
+                    })
+                })
+            }
+            return data
+        }
+    },
+    methods: {
+        viewImage(url) {
+            this.$hevueImgPreview(url)
+        },
+    }
+}
+</script>
+
+<style lang="less" scoped>
+.action-type {
+    text-align: right;
+    font-weight: bold;
+    margin: 0 10px 5px 0;
+}
+.cowork-box {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: flex-end;
+
+    &>div {
+        margin: 0 10px 15px;
+        text-align: center;
+    }
+
+    .receive-img {
+        max-width: 150px;
+        max-height: 150px;
+        border: 1px solid #eeeeee;
+        cursor: pointer;
+    }
+}
+</style>

+ 14 - 8
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Pick.vue

@@ -1,12 +1,14 @@
 <template>
     <!-- 随机挑人 -->
     <div class="pick-wrap">
-        <p class="event-type">
-            {{$t('cusMgt.rcd.evt3')}}
-        </p>
-        <div class="pick-item" v-for="(item,index) in pickRes" :key="index">
-            <p class="student-no">{{item.seatNo}}</p>
-            <p class="student-name">{{item.name}}</p>
+        <div>
+            <p class="event-type">
+                {{$t('cusMgt.rcd.evt3')}}
+            </p>
+            <div class="pick-item" v-for="(item,index) in pickRes" :key="index">
+                <p class="student-no">{{item.seatNo}}</p>
+                <p class="student-name">{{item.name}}</p>
+            </div>
         </div>
         <StudentClient></StudentClient>
     </div>
@@ -109,8 +111,12 @@ export default {
     }
 }
 .event-type {
-    margin-right: 20px;
+    /* margin-right: 20px;
     font-size: 15px;
-    font-weight: 600;
+    font-weight: 600; */
+    
+    text-align: right;
+    font-weight: bold;
+    margin: 0 10px 5px 0;
 }
 </style>

+ 47 - 27
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/PopQues.vue

@@ -1,30 +1,34 @@
 <template>
     <div class="pop-ques-wrap">
         <TeacherClient></TeacherClient>
-        <p class="event-type">
-            {{evtType == 'PopQuesLoad' ? $t('studentWeb.hiteachNote.qA') : $t('studentWeb.hiteachNote.qaAgain')}}
-            <Tooltip :content="$t('talMgmt.text47')">
-            <v-icon class="qu-flip-icon" :style="{'color':isOverview ? '':'#2d8cf0'}" :iconClass="imgSrc" v-show="quType === 'single' || quType === 'multiple' || quType === 'judge'" @click.native="isOverview = !isOverview" />
-            </Tooltip>
-        </p>
-        <!-- 统计数据 -->
-        <template v-if="isOverview">
-            <!-- 单选、多选、判断选项分布 -->
-            <OptionCount v-if="quType === 'single' || quType === 'multiple' || quType === 'judge'" :optionCount="optionData" :answer="answer"></OptionCount>
-            <!-- 填空题(文字题) -->
-            <CompleteAns v-else-if="quType === 'complete'" :answer="answerData" :students="students"></CompleteAns>
-            <!-- 如果有设置正确答案的正确率统计 -->
-            <CorrectRate :correctData="correctData" v-if="hasAnswer"></CorrectRate>
-        </template>
-        <div v-else>
-            <p v-for="key in Object.keys(optionData)" :key="key">
-                <Tag :color="key == 'noAns' ? 'warning' : 'primary'">
-                    {{key == 'noAns' ? $t('cusMgt.rcd.noAns') : key}}
-                </Tag>
-                <Tag color="default" v-for="s in optionData[key]" :key="s">
-                    {{s}}
-                </Tag>
+        <div>
+            <p class="event-type">
+                {{evtType == 'PopQuesLoad' ? $t('studentWeb.hiteachNote.qA') : $t('studentWeb.hiteachNote.qaAgain')}}
+                <Tooltip :content="$t('talMgmt.text47')">
+                <v-icon class="qu-flip-icon" :style="{'color':isOverview ? '':'#2d8cf0'}" :iconClass="imgSrc" v-show="quType === 'single' || quType === 'multiple' || quType === 'judge'" @click.native="isOverview = !isOverview" />
+                </Tooltip>
             </p>
+            <!-- 统计数据 -->
+            <div v-if="isOverview">
+                <!-- 单选、多选、判断选项分布 -->
+                <OptionCount v-if="quType === 'single' || quType === 'multiple' || quType === 'judge'" :optionCount="optionData" :answer="answer"></OptionCount>
+                <!-- 填空题(文字题) -->
+                <CompleteAns v-else-if="quType === 'complete'" :answer="answerData" :students="students"></CompleteAns>
+                <!-- 如果有设置正确答案的正确率统计 -->
+                <CorrectRate :correctData="correctData" v-if="hasAnswer"></CorrectRate>
+                <!-- 问答题(文字、图片、音频) -->
+                <SubjectiveAns v-else-if="quType === 'subjective'" :answer="answerData" :students="students" :recordInfo="recordInfo" :blobInfo="blobInfo" :answerType="irsData.question?.exercise?.answerType" />
+            </div>
+            <div v-else>
+                <p v-for="key in Object.keys(optionData)" :key="key">
+                    <Tag :color="key == 'noAns' ? 'warning' : 'primary'">
+                        {{key == 'noAns' ? $t('cusMgt.rcd.noAns') : key}}
+                    </Tag>
+                    <Tag color="default" v-for="s in optionData[key]" :key="s">
+                        {{s}}
+                    </Tag>
+                </p>
+            </div>
         </div>
     </div>
 </template>
@@ -33,8 +37,15 @@ import TeacherClient from './TeacherClient.vue'
 import CorrectRate from './CorrectRate.vue'
 import OptionCount from './OptionCount.vue'
 import CompleteAns from './CompleteAns.vue'
+import SubjectiveAns from './SubjectiveAns.vue'
 export default {
     props: {
+        recordInfo: {
+            type: Object,
+            default: () => {
+                return {}
+            }
+        },
         irsData: {
             type: Object,
             default: () => {
@@ -50,7 +61,13 @@ export default {
             default: () => {
                 return []
             }
-        }
+        },
+        blobInfo: {
+            type: Object,
+            default: () => {
+                return {}
+            }
+        },
     },
     data() {
         require('@/icons/svg/flop.svg')
@@ -78,7 +95,7 @@ export default {
         }
     },
     components: {
-        OptionCount, CorrectRate, TeacherClient, CompleteAns
+        OptionCount, CorrectRate, TeacherClient, CompleteAns, SubjectiveAns
     },
     watch: {
         irsData: {
@@ -162,8 +179,11 @@ export default {
     display: flex;
 }
 .event-type {
-    margin-right: 20px;
+    /* margin-right: 20px;
     font-size: 15px;
-    font-weight: 600;
+    font-weight: 600; */
+    
+    font-weight: bold;
+    margin-bottom: 5px;
 }
 </style>

+ 4 - 2
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Push.vue

@@ -37,8 +37,10 @@ export default {
 </script>
 <style lang="less" scoped>
 .text-label{
-    display: inline-block;
-    vertical-align: top;
+    // display: inline-block;
+    // vertical-align: top;
+    font-weight: bold;
+    margin-bottom: 5px;
 }
 .tea-push-img{
     max-width: 120px;

+ 55 - 41
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Receive.vue

@@ -1,47 +1,51 @@
 <template>
     <!-- 作品收集 -->
     <div class="receive-wrap">
-        <p class="clt-type">
-            <!-- {{cltTypeMap[collateType].text}}收集:{{collateType}} -->
-            {{$t('cusMgt.rcd.evt4')}}
-        </p>
-        <div v-for="(item) in receiveData" :key="item.seatID+item.groupID" class="receive-item">
-            <div v-if="collateType == 0">
-                {{$t('cusMgt.rcd.evt5')}}
-            </div>
-            <!-- 图片类型作品 -->
-            <div v-else-if="collateType == 'Image'">
-                <img v-for="(blob,index) in item.blobFiles" :key="index" class="receive-img" :src="blob" alt="" @click="viewImage(blob)">
-            </div>
-            <!-- HTEX作品类型 -->
-            <div v-else-if="collateType == 'Htex'">
-                <!-- 收集的HTEX作品 -->
-            </div>
-            <!-- 音频 -->
-            <div v-else-if="collateType == 'Audio'">
-                <div v-for="(blob,index) in item.blobFiles" :key="index" class="audio-box" @click="viewAudio(blob)">
-                    <Icon class="collate-type-icon" custom="iconfont icon-audio-outline" />
-                </div>
-            </div>
-            <!-- 视频 -->
-            <div v-else-if="collateType == 'Video'">
-                <div v-for="(blob,index) in item.blobFiles" :key="index" class="audio-box" @click="viewAudio(blob)">
-                    <Icon class="collate-type-icon" custom="iconfont icon-video-outline" />
-                </div>
-            </div>
-            <!-- 文字 -->
-            <div v-else-if="collateType == 'Text'">
-                收集的文字
-            </div>
-            <!-- 附件 -->
-            <div v-else-if="collateType == 'File'">
-                <div v-for="(blob,index) in item.blobFiles" :key="index" class="audio-box" @click="downloadFile(blob,item)">
-                    <Icon class="collate-type-icon" custom="iconfont icon-file" />
+        <div>
+            <p class="clt-type">
+                <!-- {{cltTypeMap[collateType].text}}收集:{{collateType}} -->
+                {{$t('cusMgt.rcd.evt4')}}
+            </p>
+            <div class="receive-box">
+                <div v-for="(item) in receiveData" :key="item.seatID+item.groupID" class="receive-item">
+                    <div v-if="collateType == 0">
+                        {{$t('cusMgt.rcd.evt5')}}
+                    </div>
+                    <!-- 图片类型作品 -->
+                    <div v-else-if="collateType == 'Image'">
+                        <img v-for="(blob,index) in item.blobFiles" :key="index" class="receive-img" :src="blob" alt="" @click="viewImage(blob)">
+                    </div>
+                    <!-- HTEX作品类型 -->
+                    <div v-else-if="collateType == 'Htex'">
+                        <!-- 收集的HTEX作品 -->
+                    </div>
+                    <!-- 音频 -->
+                    <div v-else-if="collateType == 'Audio'">
+                        <div v-for="(blob,index) in item.blobFiles" :key="index" class="audio-box" @click="viewAudio(blob)">
+                            <Icon class="collate-type-icon" custom="iconfont icon-audio-outline" />
+                        </div>
+                    </div>
+                    <!-- 视频 -->
+                    <div v-else-if="collateType == 'Video'">
+                        <div v-for="(blob,index) in item.blobFiles" :key="index" class="audio-box" @click="viewAudio(blob)">
+                            <Icon class="collate-type-icon" custom="iconfont icon-video-outline" />
+                        </div>
+                    </div>
+                    <!-- 文字 -->
+                    <div v-else-if="collateType == 'Text'">
+                        收集的文字
+                    </div>
+                    <!-- 附件 -->
+                    <div v-else-if="collateType == 'File'">
+                        <div v-for="(blob,index) in item.blobFiles" :key="index" class="audio-box" @click="downloadFile(blob,item)">
+                            <Icon class="collate-type-icon" custom="iconfont icon-file" />
+                        </div>
+                    </div>
+                    <p class="name-text">
+                        {{ item.isGroupItem ? item.groupID : item.sName}}
+                    </p>
                 </div>
             </div>
-            <p class="name-text">
-                {{ item.isGroupItem ? item.groupID : item.sName}}
-            </p>
         </div>
         <StudentClient class="receive-student"></StudentClient>
         <!--文件预览-->
@@ -230,8 +234,14 @@ export default {
     right: 0px;
     top: 5px;
 }
+.receive-box {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: flex-end;
+}
 .receive-item {
     margin-right: 20px;
+    text-align: center;
 }
 .receive-img {
     max-width: 150px;
@@ -260,8 +270,12 @@ export default {
     font-size: 30px;
 }
 .clt-type {
-    margin-right: 10px;
+    /* margin-right: 10px;
     font-size: 15px;
-    font-weight: 600;
+    font-weight: 600; */
+    
+    text-align: right;
+    font-weight: bold;
+    margin: 0 10px 5px 0;
 }
 </style>

+ 38 - 33
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/SmartRating.vue

@@ -6,38 +6,39 @@
             mutualSummary:互评
             mutualDetailSummary:互评数据
          -->
-        <div class="smart-wrap">
+        <div>
             <p class="clt-type">
                 {{ smartType.name }}
                 <Icon type="md-eye-off" :title="$t('cusMgt.rcd.anonymousSub')" v-if="smartRate.smartRateSummary.rateInfo.AnonyCandi" />
-                :
             </p>
-            <template v-if="smartType.value === 'vote'">
-                <!-- <div v-for="(item, index) in scoreListNew" :key="index" style="margin-bottom: 10px;"> -->
-                    {{ $t('answerSheet.tip2') }}{{ vote.round }}{{ $t('cusMgt.rcd.wheel') }}({{ vote.votes }}{{ $t('studentWeb.vote.tickets') }})
-                    <Icon :title="$t('cusMgt.rcd.viewCom')" type="md-chatbubbles" size="17" color="#2EC7C9" @click="openComment('vote')" style="cursor: pointer; margin-top: 3px; margin-right: 5px;" />
-                    <SmartVote :smartData="scoreListNew"></SmartVote>
-                <!-- </div> -->
-            </template>
-            <template v-else-if="smartType.value === 'score'">
-                <SmartScore :smartData="scoreListNew"></SmartScore>
-            </template>
-            <template v-else>
-                <div v-for="(item, index) in scoreListNew" :key="index" class="smart-list">
-                    <p style="height: 21px;">
-                        <Icon type="md-trophy" v-if="item.king" color="#ff880d" />
-                    </p>
-                    <p>
-                        <span style="color: #2d8cf0;">{{ item.name }}
-                            <span v-show="!item.isGeneral">({{ item.id }})</span>
-                        </span>
-                        <Icon type="md-chatbubbles" color="#2EC7C9" style="cursor: pointer;" @click="openComment('mutal', index, item)" />
-                    </p>
-                    <p>{{ $t('cusMgt.rcd.avgScore') }}:{{ item.result }}</p>
-                    <img v-if="smartRate.smartRateSummary.rateInfo.RatingSource === 'StudentWork'" :src="item.material" @click="$hevueImgPreview(item.material)" />
-                    <p v-if="smartRate.smartRateSummary.rateInfo.RatingSource === 'IRS'" v-html="item.material" class="smart-material"></p>
-                </div>
-            </template>
+            <div class="smart-wrap">
+                <template v-if="smartType.value === 'vote'">
+                    <!-- <div v-for="(item, index) in scoreListNew" :key="index" style="margin-bottom: 10px;"> -->
+                        {{ $t('answerSheet.tip2') }}{{ vote.round }}{{ $t('cusMgt.rcd.wheel') }}({{ vote.votes }}{{ $t('studentWeb.vote.tickets') }})
+                        <Icon :title="$t('cusMgt.rcd.viewCom')" type="md-chatbubbles" size="17" color="#2EC7C9" @click="openComment('vote')" style="cursor: pointer; margin-top: 3px; margin-right: 5px;" />
+                        <SmartVote :smartData="scoreListNew"></SmartVote>
+                    <!-- </div> -->
+                </template>
+                <template v-else-if="smartType.value === 'score'">
+                    <SmartScore :smartData="scoreListNew"></SmartScore>
+                </template>
+                <template v-else>
+                    <div v-for="(item, index) in scoreListNew" :key="index" class="smart-list">
+                        <p style="height: 21px;">
+                            <Icon type="md-trophy" v-if="item.king" color="#ff880d" />
+                        </p>
+                        <p>
+                            <span style="color: #2d8cf0;">{{ item.name }}
+                                <span v-show="!item.isGeneral">({{ item.id }})</span>
+                            </span>
+                            <Icon type="md-chatbubbles" color="#2EC7C9" style="cursor: pointer;" @click="openComment('mutal', index, item)" />
+                        </p>
+                        <p>{{ $t('cusMgt.rcd.avgScore') }}:{{ item.result }}</p>
+                        <img v-if="smartRate.smartRateSummary.rateInfo.RatingSource === 'StudentWork'" :src="item.material" @click="$hevueImgPreview(item.material)" />
+                        <p v-if="smartRate.smartRateSummary.rateInfo.RatingSource === 'IRS'" v-html="item.material" class="smart-material"></p>
+                    </div>
+                </template>
+            </div>
         </div>
         <StudentClient></StudentClient>
         <Modal v-model="isComment" :title="$t('homework.table.comment')" :footer-hide="true">
@@ -257,17 +258,21 @@ export default {
 </script>
 
 <style lang="less" scoped>
+.clt-type {
+    /* margin-right: 10px;
+    font-size: 15px;
+    font-weight: 600; */
+    
+    text-align: right;
+    font-weight: bold;
+    margin: 0 10px 5px 0;
+}
 .smart-wrap {
     display: flex;
     flex-wrap: wrap;
     justify-content: end;
     position: relative;
 
-    .clt-type {
-        margin-right: 10px;
-        font-size: 15px;
-        font-weight: 600;
-    }
 
     .smart-vote {
         width: 200px;

+ 135 - 0
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/SubjectiveAns.vue

@@ -0,0 +1,135 @@
+<template>
+    <div class="text-answer-item">
+        <div v-for="(student) in fullData" :key="student.seatID" @click="handleShowContent(student)">
+            <span class="student-name">{{ student.name }}:</span>
+            <div v-for="(item, index) in student.answer" :key="index">
+                <!-- 文本、画记 -->
+                <template v-if="answerType === 'text' || answerType === 'text_Image'">
+                    <div v-html="item" class="popques-svg"></div>
+                </template>
+                <template v-else>
+                    <div v-if="item.type === 'image'" class="popques-img">
+                        <img :src="item.url" alt="" @click="viewImage(item.url)">
+                    </div>
+                    <div v-if="item.type === 'audio'">
+                        <audio controls>
+                            <source :src="item.url">
+                            {{$t('teachContent.notAudio')}}
+                        </audio>
+                    </div>
+                    <div v-if="item.type === 'video'">
+                        <video :src="item.url" width="870" controls="controls" style="max-height: 800px;"></video>
+                    </div>
+                </template>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import Video from '../../video/Video.vue'
+export default {
+    components: { Video },
+    props: {
+        recordInfo: {
+            type: Object,
+            default: () => {
+                return {}
+            }
+        },
+        answer: {
+            type: Array,
+            default: () => {
+                return []
+            }
+        },
+        students: {
+            type: Array,
+            default: () => {
+                return []
+            }
+        },
+        answerType: {
+            type: String,
+            default: '',
+        },
+        blobInfo: {
+            type: Object,
+            default: () => {
+                return {}
+            }
+        },
+    },
+    computed: {
+        fullData() {
+            if (this.answer && this.answer.length) {
+                if (this.students && this.students.length) {
+                    let students = this._.cloneDeep(this.students)
+                    students.forEach((student, index) => {
+                        if(this.answerType != 'text' && this.answerType != 'text_Image') {
+                            student.answer = this.answer[index].map(item => {
+                                // 示例: "/Clients/202106001/Ans/1-1709794642933001.png"
+                                let url = {
+                                    type: '',
+                                    url: `${this.blobInfo.blob_uri}/records/${this.recordInfo.id}${item}${this.blobInfo.blob_sas}`
+                                }
+                                if(this.answerType === 'file') {
+                                    let suffix = item.substr(item.lastIndexOf(".") + 1)
+                                    let isImg = ['jpg', 'png', 'gif'].includes(suffix)
+                                    let isDoc = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf'].includes(suffix)
+                                    let isPdf = suffix === 'pdf'
+                                    let isVideo = suffix === 'mp4' || suffix === 'webm'
+                                    let isAudio = ['mp3', 'wav'].includes(suffix)
+                                    url.type = isImg ? 'image' : isVideo ? 'video' : isAudio ? 'audio' : (isDoc ? 'doc' : 'other')
+                                } else {
+                                    url.type = this.answerType
+                                }
+                                return url
+                            })
+                        } else {
+                            student.answer = this.answer[index]
+                        }
+                    });
+                    students = students.filter(s => !!s.answer?.length)
+                    console.log('完整数据', students)
+                    return students
+                }
+            } else {
+                return []
+            }
+        }
+    },
+    methods: {
+        viewImage(url) {
+            this.$hevueImgPreview(url)
+        },
+    }
+}
+</script>
+
+<style lang="less" scoped>
+.text-answer-item {
+    display: flex;
+    flex-wrap: wrap;
+
+    &>div {
+        margin-right: 20px;
+        display: flex;
+
+        .student-name {
+            margin-right: 5px;
+        }
+    }
+}
+.popques-img img{
+    cursor: pointer;
+    width: 100px !important;
+    height: 100px !important;
+}
+</style>
+<style lang="less">
+.popques-svg svg{
+    width: 200px;
+    height: auto;
+}
+</style>

+ 53 - 40
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/WrkCmp.vue

@@ -1,46 +1,50 @@
 <template>
     <!-- 作品收集 -->
     <div class="receive-wrap">
-        <p class="clt-type">
-            {{$t('cusMgt.rcd.wrkCmp')}}:
-        </p>
-        <div v-for="(item) in cmpDataList" :key="item.url" class="receive-item">
-            <div v-if="collateType == 0">
-                {{$t('cusMgt.rcd.evt5')}}
-            </div>
-            <!-- 图片类型作品 -->
-            <div v-else-if="collateType == 1">
-                <img class="receive-img" :src="item.url" alt="" @click="viewImage(item.url)">
-            </div>
-            <!-- HTEX作品类型 -->
-            <div v-else-if="collateType == 2">
-                <!-- 收集的HTEX作品 -->
-            </div>
-            <!-- 音频 -->
-            <div v-else-if="collateType == 3">
-                <div class="audio-box" @click="viewAudio(item.url)">
-                    <Icon class="collate-type-icon" custom="iconfont icon-audio-outline" />
-                </div>
-            </div>
-            <!-- 视频 -->
-            <div v-else-if="collateType == 4">
-                <div v-for="(blob,index) in item.blobFiles" :key="index" class="audio-box" @click="viewAudio(item.url)">
-                    <Icon class="collate-type-icon" custom="iconfont icon-video-outline" />
-                </div>
-            </div>
-            <!-- 文字 -->
-            <div v-else-if="collateType == 5">
-                收集的文字
-            </div>
-            <!-- 附件 -->
-            <div v-else-if="collateType == 6">
-                <div class="audio-box" @click="downloadFile(item.url,item)">
-                    <Icon class="collate-type-icon" custom="iconfont icon-file" />
+        <div>
+            <p class="clt-type">
+                {{$t('cusMgt.rcd.wrkCmp')}}:
+            </p>
+            <div class="receive-box">
+                <div v-for="(item) in cmpDataList" :key="item.url" class="receive-item">
+                    <div v-if="collateType == 0">
+                        {{$t('cusMgt.rcd.evt5')}}
+                    </div>
+                    <!-- 图片类型作品 -->
+                    <div v-else-if="collateType == 1">
+                        <img class="receive-img" :src="item.url" alt="" @click="viewImage(item.url)">
+                    </div>
+                    <!-- HTEX作品类型 -->
+                    <div v-else-if="collateType == 2">
+                        <!-- 收集的HTEX作品 -->
+                    </div>
+                    <!-- 音频 -->
+                    <div v-else-if="collateType == 3">
+                        <div class="audio-box" @click="viewAudio(item.url)">
+                            <Icon class="collate-type-icon" custom="iconfont icon-audio-outline" />
+                        </div>
+                    </div>
+                    <!-- 视频 -->
+                    <div v-else-if="collateType == 4">
+                        <div v-for="(blob,index) in item.blobFiles" :key="index" class="audio-box" @click="viewAudio(item.url)">
+                            <Icon class="collate-type-icon" custom="iconfont icon-video-outline" />
+                        </div>
+                    </div>
+                    <!-- 文字 -->
+                    <div v-else-if="collateType == 5">
+                        收集的文字
+                    </div>
+                    <!-- 附件 -->
+                    <div v-else-if="collateType == 6">
+                        <div class="audio-box" @click="downloadFile(item.url,item)">
+                            <Icon class="collate-type-icon" custom="iconfont icon-file" />
+                        </div>
+                    </div>
+                    <p class="name-text">
+                        {{ item.isGroupItem ? item.groupID : item.sName}}
+                    </p>
                 </div>
             </div>
-            <p class="name-text">
-                {{ item.isGroupItem ? item.groupID : item.sName}}
-            </p>
         </div>
         <StudentClient></StudentClient>
         <!--文件预览-->
@@ -223,6 +227,11 @@ export default {
 .receive-wrap {
     display: flex;
 }
+.receive-box {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: flex-end;
+}
 .receive-item {
     margin-right: 20px;
 }
@@ -253,8 +262,12 @@ export default {
     font-size: 30px;
 }
 .clt-type {
-    margin-right: 10px;
+    /* margin-right: 10px;
     font-size: 15px;
-    font-weight: 600;
+    font-weight: 600; */
+    
+    text-align: right;
+    font-weight: bold;
+    margin: 0 10px 5px 0;
 }
 </style>

+ 463 - 416
TEAMModelOS/ClientApp/src/view/dashboard/Art.vue

@@ -1,426 +1,473 @@
 <template>
-  <div id="artIndex" ref="appRef">
-    <div class="bg">
-      <dv-loading v-if="loading">{{ $t('researchCenter.dashboard.loading') }}</dv-loading>
-      <div v-else class="host-body">
-        <!-- 实时北京时间 -->
-        <div class="tools">
-          <span class="time-text">{{ dateYear }} <span style="display: inline-block; margin: 0 5px;color: #0fa2fe;">{{ dateDay }}</span> </span>
-          <span class="icon iconfont icon-download" v-if="!isNoData" style="font-size: 22px;margin-right:10px" :title="`下载艺术评测数据表`" @click="exportArtTable"></span>
-          <span class="icon iconfont icon-tuichuquanping" style="font-size: 22px;" :title="$t('researchCenter.dashboard.quit')" @click="goBack"></span>
-        </div>
-        <!-- 学校基础信息 及 活动、科目选择 -->
-        <div class="school-info">
-          <img :src="schoolInfo.schoolLogo">
-          <span class="school-info-name">{{ schoolInfo.schoolName }}</span>
-          <span class="school-info-period">{{ schoolInfo.periodName }}</span>
-          <span class="school-info-semester" v-if="!$route.params.artInfo">{{ schoolInfo.curSemester }}</span>
-          <div style="margin-left: 15px">
-            <Select v-model="activeAcIndex" @on-change="onAcChange">
-              <Option v-for="(item,index) in acList" :value="index">{{ item.name }}</Option>
-            </Select>
-          </div>
-          <div class="dashboard-select-subject">
-            <Select v-model="curSubjectIndex" @on-change="onSubjectChange">
-              <Option v-for="(item,index) in subjectList" :value="index">{{ item.name }}</Option>
-            </Select>
-          </div>
-        </div>
-        <!-- 头部标题 -->
-        <div class="d-flex jc-center" style="margin-top:-5px">
-          <dv-decoration-10 class="dv-dec-10" />
-          <div class="d-flex jc-center">
-            <dv-decoration-8 class="dv-dec-8" :color="['#568aea', '#000000']" />
-            <div class="title">
-              <span class="dash-title-text">艺术测评看板</span>
-              <dv-decoration-6 class="dv-dec-6" :reverse="true" :color="['#50e3c2', '#67a1e5']" />
-            </div>
-            <dv-decoration-8 class="dv-dec-8" :reverse="true" :color="['#568aea', '#000000']" />
-          </div>
-          <dv-decoration-10 class="dv-dec-10-s" />
-        </div>
-        <div v-if="isNoData">
-          <dv-border-box-12 class="no-data-wrap">
-            <p style="color:#50e3c2">【 {{ artName }} 】</p>
-            <p style="margin-top:20px">暂无评测数据</p>
-          </dv-border-box-12>
-        </div>
-        <!-- 图表区域 -->
-        <div class="body-box" v-if="!isNoData">
-          <div class="left-box">
-            <div class="left-box-top">
-              <dv-border-box-12>
-                <LeftTop />
-              </dv-border-box-12>
-            </div>
-            <div class="left-box-center">
-              <dv-border-box-12>
-                <RightTop />
-              </dv-border-box-12>
-            </div>
-          </div>
+	<div id="artIndex" ref="appRef">
+		<div class="bg">
+			<dv-loading v-if="loading">{{ $t("researchCenter.dashboard.loading") }}</dv-loading>
+			<div v-else class="host-body">
+				<!-- 实时北京时间 -->
+				<div class="tools">
+					<Select v-model="semesterValue" @on-change="onSemesterChange" style="width: 160px; margin-right: 60px">
+						<Option v-for="(item, index) in semesterList" :value="index">{{ item.year }}{{ item.name }}</Option>
+					</Select>
+					<!-- <span class="time-text">{{ dateYear }} <span style="display: inline-block; margin: 0 5px;color: #0fa2fe;">{{ dateDay }}</span> </span> -->
+					<span class="icon iconfont icon-download" v-if="!isNoData" style="font-size: 22px; margin-right: 10px" :title="`下载艺术评测数据表`" @click="exportArtTable"></span>
+					<span class="icon iconfont icon-tuichuquanping" style="font-size: 22px" :title="$t('researchCenter.dashboard.quit')" @click="goBack"></span>
+				</div>
+				<!-- 学校基础信息 及 活动、科目选择 -->
+				<div class="school-info">
+					<img :src="schoolInfo.schoolLogo" />
+					<span class="school-info-name">{{ schoolInfo.schoolName }}</span>
+					<span class="school-info-period">{{ schoolInfo.periodName }}</span>
+					<!-- <span class="school-info-semester" v-if="!$route.params.artInfo">{{ schoolInfo.curSemester }}</span> -->
+					<div style="margin-left: 15px">
+						<Select v-model="activeAcIndex" @on-change="onAcChange">
+							<Option v-for="(item, index) in acList" :value="index">{{ item.name }}</Option>
+						</Select>
+					</div>
+					<div class="dashboard-select-subject">
+						<Select v-model="curSubjectIndex" @on-change="onSubjectChange">
+							<Option v-for="(item, index) in subjectList" :value="index">{{ item.name }}</Option>
+						</Select>
+					</div>
+				</div>
+				<!-- 头部标题 -->
+				<div class="d-flex jc-center" style="margin-top: -5px">
+					<dv-decoration-10 class="dv-dec-10" />
+					<div class="d-flex jc-center">
+						<dv-decoration-8 class="dv-dec-8" :color="['#568aea', '#000000']" />
+						<div class="title">
+							<span class="dash-title-text">艺术测评看板</span>
+							<dv-decoration-6 class="dv-dec-6" :reverse="true" :color="['#50e3c2', '#67a1e5']" />
+						</div>
+						<dv-decoration-8 class="dv-dec-8" :reverse="true" :color="['#568aea', '#000000']" />
+					</div>
+					<dv-decoration-10 class="dv-dec-10-s" />
+				</div>
+				<div v-if="isNoData">
+					<dv-border-box-12 class="no-data-wrap">
+						<p style="color: #50e3c2">【 {{ artName }} 】</p>
+						<p style="margin-top: 20px">暂无评测数据</p>
+					</dv-border-box-12>
+				</div>
+        <div v-if="isNoAc">
+					<dv-border-box-12 class="no-data-wrap">
+						<p style="margin-top: 20px">该学期暂无评测记录</p>
+					</dv-border-box-12>
+				</div>
+				<!-- 图表区域 -->
+				<div class="body-box" v-if="!isNoData">
+					<div class="left-box">
+						<div class="left-box-top">
+							<dv-border-box-12>
+								<LeftTop />
+							</dv-border-box-12>
+						</div>
+						<div class="left-box-center">
+							<dv-border-box-12>
+								<RightTop />
+							</dv-border-box-12>
+						</div>
+					</div>
 
-          <div class="right-box">
-            <div class="right-box-top">
-              <dv-border-box-12>
-                <LeftBottom />
-              </dv-border-box-12>
-            </div>
-            <div class="right-box-bottom">
-              <div class="right-bottom-single">
-                <dv-border-box-12>
-                  <RightBotL />
-                </dv-border-box-12>
-              </div>
-              <div class="right-bottom-single">
-                <dv-border-box-12>
-                  <RightBotR />
-                </dv-border-box-12>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
+					<div class="right-box">
+						<div class="right-box-top">
+							<dv-border-box-12>
+								<LeftBottom />
+							</dv-border-box-12>
+						</div>
+						<div class="right-box-bottom">
+							<div class="right-bottom-single">
+								<dv-border-box-12>
+									<RightBotL />
+								</dv-border-box-12>
+							</div>
+							<div class="right-bottom-single">
+								<dv-border-box-12>
+									<RightBotR />
+								</dv-border-box-12>
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
 </template>
 
 <script>
-import excel from '@/utils/excel.js'
-import RightBotR from '@/components/dashboard/art/RightBotR'
-import RightBotL from '@/components/dashboard/art/RightBotL'
-import LeftTop from '@/components/dashboard/art/LeftTop'
-import LeftCenter from '@/components/dashboard/art/LeftCenter'
-import LeftBottom from '@/components/dashboard/art/LeftBottom'
-import RightTop from '@/components/dashboard/art/RightTop'
-export default {
-  data() {
-    return {
-      artName: '',
-      isNoData: false,
-      activeAcIndex: 0,
-      acList: [],
-      curAcSummary: null,
-      subjectList: [],
-      activeMenu: 'music',
-      activeClassIndex: -1,
-      activeGradeIndex: 0,
-      curSubjectIndex: 0,
-      timing: null,
-      loading: true,
-      dateDay: null,
-      dateYear: null,
-      dateWeek: null,
-    }
-  },
-  components: {
-    RightBotR,
-    RightBotL,
-    LeftTop,
-    LeftCenter,
-    LeftBottom,
-    RightTop,
-  },
-  mounted() {
-    // setTimeout(() => {
-    //   this.$tools.fullScreen(document.getElementById('artIndex'))
-    // }, 600)
-    this.timeFn()
-  },
-  beforeDestroy() {
-    clearInterval(this.timing)
-  },
-  created() {
-    let params = this.$route.params
-    /* 从区级选择任意一个学校跳转过来的 */
-    console.log(params)
-    if (params.artInfo) {
-      this.findAreaSchoolAnalysis(params.artInfo)
-      this.$tools.fullScreen(document.getElementById('artIndex'))
-    } else {
-      this.findArtList()
-    }
-  },
-  methods: {
-    /* 查询区级任意一个学校的艺术评测看板数据 */
-    findAreaSchoolAnalysis(artInfo) {
-      this.$api.areaArt.findArtSummary({
-        id: artInfo.artId,
-        code: artInfo.code
-      }).then(
-        (res) => {
-          if (!res.error) {
-            this.curAcSummary = res.art
-            // 根据勾选的指标 展示表格的列 其中用户信息列和总分列是固定展示
-            this.subjectList = res.art.subjects
-            this.curSubjectIndex = 0
-            let curSubjectId = this.subjectList[this.curSubjectIndex].id
-            this.acList = [{
-              id: artInfo.artId,
-              name: res.art.name
-            }]
-            this.loading = true
-            // 获取看板数据
-            this.$api.areaArt.findArtDashAnalysis({
-              "code": artInfo.code,
-              "periodId": artInfo.perId,
-              "subjectId": curSubjectId,
-              "areaId": sessionStorage.getItem('areaId'),
-              "id": artInfo.artId,
-              "classIds": res.art.classes,
-              'examId': res.art.settings.find(i => i.id === 'quota_21').task.find(k => k.subject === curSubjectId).acId
-            }).then(analysisRes => {
-              console.log(`output->analysisRes`, analysisRes)
-              this.artName = this.acList[this.activeAcIndex].name
-              if (analysisRes.code === 500) {
-                this.isNoData = true
-              } else {
-                this.isNoData = false
-                // 保存到vuex
-                this.$store.commit('artDashboard/setAnalysisJson', analysisRes)
-              }
+	import excel from "@/utils/excel.js";
+	import RightBotR from "@/components/dashboard/art/RightBotR";
+	import RightBotL from "@/components/dashboard/art/RightBotL";
+	import LeftTop from "@/components/dashboard/art/LeftTop";
+	import LeftCenter from "@/components/dashboard/art/LeftCenter";
+	import LeftBottom from "@/components/dashboard/art/LeftBottom";
+	import RightTop from "@/components/dashboard/art/RightTop";
+	export default {
+		data() {
+			return {
+				artName: "",
+				isNoData: false,
+        isNoAc:false,
+				activeAcIndex: 0,
+				acList: [],
+				curAcSummary: null,
+				subjectList: [],
+				activeMenu: "music",
+				activeClassIndex: -1,
+				activeGradeIndex: 0,
+				curSubjectIndex: 0,
+				timing: null,
+				loading: true,
+				dateDay: null,
+				dateYear: null,
+				dateWeek: null,
+				semesterList: [],
+				filterSemesterId: "",
+				semesterValue: 1,
+				curSemester: null
+			};
+		},
+		components: {
+			RightBotR,
+			RightBotL,
+			LeftTop,
+			LeftCenter,
+			LeftBottom,
+			RightTop
+		},
+		mounted() {
+			// setTimeout(() => {
+			//   this.$tools.fullScreen(document.getElementById('artIndex'))
+			// }, 600)
+			this.timeFn();
+		},
+		beforeDestroy() {
+			clearInterval(this.timing);
+		},
+		created() {
+			let params = this.$route.params;
+			/* 从区级选择任意一个学校跳转过来的 */
+			console.log(params);
+			if (params.artInfo) {
+				this.findAreaSchoolAnalysis(params.artInfo);
+				this.$tools.fullScreen(document.getElementById("artIndex"));
+			} else {
+				this.findArtList();
+			}
+			this.getSemesterList();
+		},
+		methods: {
+			getSemesterList() {
+				let curYear = new Date().getFullYear();
+				let curPeriod = this.$store.state.user.curPeriod;
+				let semesterArr = this._.cloneDeep(curPeriod.semesters).sort((a, b) => b.start - a.start);
+				this.curSemester = this.$store.state.user.curSemester;
+				let gradeCount = curPeriod.grades.length;
+				// let listYearCount = gradeCount + 1; // 可选年份范围是当前学段下年级数量 再往后推一年(可能会查看未来的排课表)
+				let listYearCount = 1; // 可选年份范围是当前学段下年级数量 再往后推一年(可能会查看未来的排课表)
+				let oldYear = curYear - 1;
+				let arr = [];
+				for (let i = 0; i <= listYearCount; i++) {
+					for (let j = 0; j < semesterArr.length; j++) {
+						arr.push({
+							year: oldYear + i,
+							name: semesterArr[j].name,
+							index: curPeriod.semesters.findIndex(k => k.id === semesterArr[j].id),
+							id: semesterArr[j].id
+						});
+					}
+				}
+				this.semesterList = arr;
+				this.semesterValue = this.semesterList.findIndex((i) => i.year === this.curSemester.year && i.id === this.curSemester.id);
+				this.studyYear = this.curSemester.year;
+			},
+			onSemesterChange(val) {
+        console.log(JSON.stringify(this.semesterList[val]))
+				this.findArtList(this.semesterList[val]);
+			},
+			/* 查询区级任意一个学校的艺术评测看板数据 */
+			findAreaSchoolAnalysis(artInfo) {
+				this.$api.areaArt
+					.findArtSummary({
+						id: artInfo.artId,
+						code: artInfo.code
+					})
+					.then(
+						(res) => {
+							if (!res.error) {
+								this.curAcSummary = res.art;
+								// 根据勾选的指标 展示表格的列 其中用户信息列和总分列是固定展示
+								this.subjectList = res.art.subjects;
+								this.curSubjectIndex = 0;
+								let curSubjectId = this.subjectList[this.curSubjectIndex].id;
+								this.acList = [
+									{
+										id: artInfo.artId,
+										name: res.art.name
+									}
+								];
+								this.loading = true;
+								// 获取看板数据
+								this.$api.areaArt
+									.findArtDashAnalysis({
+										code: artInfo.code,
+										periodId: artInfo.perId,
+										subjectId: curSubjectId,
+										areaId: sessionStorage.getItem("areaId"),
+										id: artInfo.artId,
+										classIds: res.art.classes,
+										examId: res.art.settings.find((i) => i.id === "quota_21").task.find((k) => k.subject === curSubjectId).acId
+									})
+									.then((analysisRes) => {
+										console.log(`output->analysisRes`, analysisRes);
+										this.artName = this.acList[this.activeAcIndex].name;
+										if (analysisRes.code === 500) {
+											this.isNoData = true;
+										} else {
+											this.isNoData = false;
+											// 保存到vuex
+											this.$store.commit("artDashboard/setAnalysisJson", analysisRes);
+										}
+										this.cancelLoading();
+									});
+							}
+						},
+						(err) => {
+							this.$Message.error(err);
+						}
+					);
+			},
+			/* 查询活动列表 */
+			findArtList(semesterInfo) {
+				let n = semesterInfo || this.$store.state.user.curSemester;
+				let semesterRange = this.$tools.getStTimeByYearAndSemester(n.year, n.index);
+				let curPeriod = JSON.parse(localStorage.getItem("curPeriod"));
+				let params = {
+					code: this.$store.state.userInfo.schoolCode,
+					periodId: curPeriod.id,
+					periodType: curPeriod.periodType,
+					stime: semesterRange.stime,
+					etime: semesterRange.etime
+				};
+        this.loading = true
+				this.$api.areaArt.findArtList(params).then(
+					(res) => {
+						this.acList = res.arts.filter((i) => i.progress === "finish");
+						if (this.acList.length) {
+							this.$tools.fullScreen(document.getElementById("artIndex"));
+							this.onAcChange(0);
+              this.isNoAc = false
+						} else {
+							this.$tools.fullScreen(document.getElementById("artIndex"));
+              this.isNoAc = true
               this.cancelLoading()
-            })
-          }
-        },
-        (err) => {
-          this.$Message.error(err)
-        }
-      )
-    },
-    /* 查询活动列表 */
-    findArtList() {
-      let curPeriod = JSON.parse(localStorage.getItem('curPeriod'))
-      let params = {
-        code: this.$store.state.userInfo.schoolCode,
-        periodId: curPeriod.id,
-        periodType: curPeriod.periodType
-      }
-      this.$api.areaArt.findArtList(params).then(
-        (res) => {
-          this.acList = res.arts.filter(i => i.progress === 'finish')
-          if (this.acList.length) {
-            this.$tools.fullScreen(document.getElementById('artIndex'))
-            this.onAcChange(0)
-          } else {
-            setTimeout(() => {
-              this.$Modal.confirm({
-                title: '温馨提示',
-                content: '<p>未查询到已结束的艺术评测活动!</p>',
-                cancelText: '',
-                onOk: () => {
-                  this.$router.go(-1)
-                }
-              });
-            }, 1000)
-            // this.cancelLoading()
-          }
-        },
-        (err) => { }
-      )
-    },
-    /* 查询艺术活动详情 */
-    findArtSummary(acId) {
-      let params = {
-        id: acId,
-        code: this.$store.state.userInfo.schoolCode
-      }
-      this.$api.areaArt.findArtSummary(params).then(
-        (res) => {
-          if (!res.error) {
-            this.curAcSummary = res.art
-            // 根据勾选的指标 展示表格的列 其中用户信息列和总分列是固定展示
-            this.subjectList = res.art.subjects
-            this.curSubjectIndex = 0
-            this.onSubjectChange()
-          }
-        },
-        (err) => {
-          this.$Message.error(err)
-        }
-      )
-    },
-    /* 活动切换 */
-    onAcChange(val) {
-      this.activeAcIndex = val
-      this.findArtSummary(this.acList[val].id)
-    },
-    /* 科目切换 */
-    onSubjectChange() {
-      let curSubjectId = this.subjectList[this.curSubjectIndex].id
-      this.loading = true
-      // 获取看板数据
-      this.$api.areaArt.findArtDashAnalysis({
-        "code": this.$store.state.userInfo.schoolCode,
-        "periodId": this.schoolInfo.periodId,
-        "subjectId": curSubjectId,
-        "areaId": sessionStorage.getItem('areaId'),
-        "id": this.acList[this.activeAcIndex].id,
-        "classIds": this.curAcSummary.classes,
-        'examId': this.curAcSummary.settings.find(i => i.id === 'quota_21').task.find(k => k.subject === curSubjectId).acId
-      }).then(res => {
-        console.log(`output->res`, res)
-        this.artName = this.acList[this.activeAcIndex].name
-        if (res.scount) {
-          // 保存到vuex
-          this.isNoData = false
-          this.$store.commit('artDashboard/setAnalysisJson', res)
-        } else {
-          this.isNoData = true
-        }
-        this.cancelLoading()
-      }).catch(err => {
-        console.log(`output->err`, err)
-      })
-    },
-    /* 返回上级 */
-    goBack() {
-      this.$tools.exitFullscreen()
-      this.$router.go(-1)
-    },
-    exportArtTable() {
-      let sheets = []
-      let analysisJson = this.$store.state.artDashboard.artAnalysisJson
-      // 校级概况sheet
-      let schoolHeader = ['应考人数', '实考人数', '最高分(总)', '最低分(总)','平均分(总)','优秀率','及格率','标准差','年级测评平均分', '年级测评最高分', '年级测评优秀率','年级测评及格率']
-      let schoolKeys = ['count','scount','max','min','average','excellent','pass','pow','gradeAverage','gradeMax','gradeExcellent','gradePass']
-      let schoolDatas = [{
-        count:analysisJson.count,
-        scount:analysisJson.scount,
-        max:analysisJson.max,
-        min:analysisJson.min,
-        average:analysisJson.average,
-        excellent: parseInt(analysisJson.excellent * 100) + '%',
-        pass:parseInt(analysisJson.pass * 100) + '%',
-        pow:analysisJson.pow,
-        gradeAverage:analysisJson.gscore[0].score,
-        gradeMax:analysisJson.gscore[0].max,
-        gradeExcellent:analysisJson.gscore[0].excellent,
-        gradePass:analysisJson.gscore[0].pass
-      }]
-      const schoolSheet = {
-        title: schoolHeader,
-        key: schoolKeys,
-        data: schoolDatas,
-        filename: '校级概况',
-        autoWidth: true
-      }
-      sheets.push(schoolSheet)
-      // 班级概况sheet
-      let classHeaders = ['班级名称','平均分','最高分','最低分','优秀率','及格率']
-      let classKeys = ['name', 'average', 'max', 'min', 'excellent', 'pass']
-      let classDatas = analysisJson.cInfo.map(classItem => {
-        return {
-          name: classItem.name,
-          average: classItem.score,
-          max: classItem.max,
-          min: classItem.min,
-          excellent: parseInt(classItem.excellent * 100) + '%',
-          pass: parseInt(classItem.pass * 100) + '%'
-        }
-      })
-      const classSheet = {
-        title: classHeaders,
-        key: classKeys,
-        data: classDatas,
-        filename: '测评情况统计(班级)',
-        autoWidth: true
-      }
-      sheets.push(classSheet)
-      // 学生测评sheet
-      let stuHeaders = ['班级名称', '年级', '学生姓名', '学生学号', '测评得分', '测评得分率','稳定度系数','稳定度区级']
-      let stuKeys = ['className', 'gradeName', 'name', 'id', 'score', 'pass','sta','stu']
-      let stuDatas = analysisJson.students.map(stu => {
-        return {
-          className: stu.className,
-          gradeName: stu.gradeId,
-          name: stu.name,
-          id: stu.id,
-          score: stu.score,
-          pass: parseInt(stu.score) + '%',
-          sta: stu.sta,
-          stu: stu.stu
-        }
-      })
-      const stuSheet = {
-        title: stuHeaders,
-        key: stuKeys,
-        data: stuDatas,
-        filename: '测评详细统计(学生)',
-        autoWidth: true
-      }
-      sheets.push(stuSheet)
-      // 学生测评sheet
-      let knoHeaders = ['知识点名称','知识块名称','知识块配分','知识块维度','知识点得分率']
-      let knoKeys = ['pointName', 'blockName', 'blockScore', 'dim', 'pointScoreRate']
-      let knoDatas = []
-      analysisJson.kno.forEach(point => {
-        point.block.forEach(block => {
-          knoDatas.push(
-            {
-              pointName: point.name,
-              blockName: block,
-              blockScore: analysisJson.blk.find(i => i.name === block).score,
-              dim: analysisJson.blk.find(i => i.name === block).dimension[0],
-              pointScoreRate: parseInt(point.score * 100) + '%'
-            }
-          )
-        })
-      })
-      const knoSheet = {
-        title: knoHeaders,
-        key: knoKeys,
-        data: knoDatas,
-        filename: '知识点得分率',
-        autoWidth:true
-      }
-      sheets.push(knoSheet)
-      excel.export_array_to_sheet(sheets, `${ this.artName }(${ this.subjectList[this.curSubjectIndex].name })- 校级艺术评测报告`)
-    },
-    /* 格式化最新时间 */
-    timeFn() {
-      this.timing = setInterval(() => {
-        this.dateDay = this.$tools.formatTime(new Date(), 'hh:mm:ss')
-        this.dateYear = this.$tools.formatTime(new Date(), 'yyyy-MM-dd')
-      }, 1000)
-    },
-    /* 取消加载 */
-    cancelLoading() {
-      setTimeout(() => {
-        this.loading = false
-      }, 100)
-    },
-  },
-  computed: {
-    schoolInfo() {
-      let artInfo = this.$route.params.artInfo
-      if (artInfo) {
-        return {
-          schoolName: artInfo.name,
-          schoolLogo: '',
-          periodName: artInfo.perCname,
-          periodId: artInfo.perId,
-          curSemester: ''
-        }
-      } else {
-        let store_user = this.$store.state.user
-        let semesterRange = this.$tools.getSemesterTimeRange()
-        return {
-          schoolName: store_user.schoolProfile.school_base.name,
-          schoolLogo: store_user.schoolProfile.school_base.picture,
-          periodName: store_user.curPeriod.name,
-          periodId: store_user.curPeriod.id,
-          curSemester: semesterRange.name_with_year
-        }
-      }
-
-    }
-  }
-}
+						}
+					},
+					(err) => {}
+				);
+			},
+			/* 查询艺术活动详情 */
+			findArtSummary(acId) {
+				let params = {
+					id: acId,
+					code: this.$store.state.userInfo.schoolCode
+				};
+				this.$api.areaArt.findArtSummary(params).then(
+					(res) => {
+						if (!res.error) {
+							this.curAcSummary = res.art;
+							// 根据勾选的指标 展示表格的列 其中用户信息列和总分列是固定展示
+							this.subjectList = res.art.subjects;
+							this.curSubjectIndex = 0;
+							this.onSubjectChange();
+						}
+					},
+					(err) => {
+						this.$Message.error(err);
+					}
+				);
+			},
+			/* 活动切换 */
+			onAcChange(val) {
+				this.activeAcIndex = val;
+				this.findArtSummary(this.acList[val].id);
+			},
+			/* 科目切换 */
+			onSubjectChange() {
+				let curSubjectId = this.subjectList[this.curSubjectIndex].id;
+				this.loading = true;
+				// 获取看板数据
+				this.$api.areaArt
+					.findArtDashAnalysis({
+						code: this.$store.state.userInfo.schoolCode,
+						periodId: this.schoolInfo.periodId,
+						subjectId: curSubjectId,
+						areaId: sessionStorage.getItem("areaId"),
+						id: this.acList[this.activeAcIndex].id,
+						classIds: this.curAcSummary.classes,
+						examId: this.curAcSummary.settings.find((i) => i.id === "quota_21").task.find((k) => k.subject === curSubjectId).acId
+					})
+					.then((res) => {
+						console.log(`output->res`, res);
+						this.artName = this.acList[this.activeAcIndex].name;
+						if (res.scount) {
+							// 保存到vuex
+							this.isNoData = false;
+							this.$store.commit("artDashboard/setAnalysisJson", res);
+						} else {
+							this.isNoData = true;
+						}
+						this.cancelLoading();
+					})
+					.catch((err) => {
+						console.log(`output->err`, err);
+					});
+			},
+			/* 返回上级 */
+			goBack() {
+				this.$tools.exitFullscreen();
+				this.$router.go(-1);
+			},
+			exportArtTable() {
+				let sheets = [];
+				let analysisJson = this.$store.state.artDashboard.artAnalysisJson;
+				// 校级概况sheet
+				let schoolHeader = ["应考人数", "实考人数", "最高分(总)", "最低分(总)", "平均分(总)", "优秀率", "及格率", "标准差", "年级测评平均分", "年级测评最高分", "年级测评优秀率", "年级测评及格率"];
+				let schoolKeys = ["count", "scount", "max", "min", "average", "excellent", "pass", "pow", "gradeAverage", "gradeMax", "gradeExcellent", "gradePass"];
+				let schoolDatas = [
+					{
+						count: analysisJson.count,
+						scount: analysisJson.scount,
+						max: analysisJson.max,
+						min: analysisJson.min,
+						average: analysisJson.average,
+						excellent: parseInt(analysisJson.excellent * 100) + "%",
+						pass: parseInt(analysisJson.pass * 100) + "%",
+						pow: analysisJson.pow,
+						gradeAverage: analysisJson.gscore[0].score,
+						gradeMax: analysisJson.gscore[0].max,
+						gradeExcellent: analysisJson.gscore[0].excellent,
+						gradePass: analysisJson.gscore[0].pass
+					}
+				];
+				const schoolSheet = {
+					title: schoolHeader,
+					key: schoolKeys,
+					data: schoolDatas,
+					filename: "校级概况",
+					autoWidth: true
+				};
+				sheets.push(schoolSheet);
+				// 班级概况sheet
+				let classHeaders = ["班级名称", "平均分", "最高分", "最低分", "优秀率", "及格率"];
+				let classKeys = ["name", "average", "max", "min", "excellent", "pass"];
+				let classDatas = analysisJson.cInfo.map((classItem) => {
+					return {
+						name: classItem.name,
+						average: classItem.score,
+						max: classItem.max,
+						min: classItem.min,
+						excellent: parseInt(classItem.excellent * 100) + "%",
+						pass: parseInt(classItem.pass * 100) + "%"
+					};
+				});
+				const classSheet = {
+					title: classHeaders,
+					key: classKeys,
+					data: classDatas,
+					filename: "测评情况统计(班级)",
+					autoWidth: true
+				};
+				sheets.push(classSheet);
+				// 学生测评sheet
+				let stuHeaders = ["班级名称", "年级", "学生姓名", "学生学号", "测评得分", "测评得分率", "稳定度系数", "稳定度区级"];
+				let stuKeys = ["className", "gradeName", "name", "id", "score", "pass", "sta", "stu"];
+				let stuDatas = analysisJson.students.map((stu) => {
+					return {
+						className: stu.className,
+						gradeName: stu.gradeId,
+						name: stu.name,
+						id: stu.id,
+						score: stu.score,
+						pass: parseInt(stu.score) + "%",
+						sta: stu.sta,
+						stu: stu.stu
+					};
+				});
+				const stuSheet = {
+					title: stuHeaders,
+					key: stuKeys,
+					data: stuDatas,
+					filename: "测评详细统计(学生)",
+					autoWidth: true
+				};
+				sheets.push(stuSheet);
+				// 学生测评sheet
+				let knoHeaders = ["知识点名称", "知识块名称", "知识块配分", "知识块维度", "知识点得分率"];
+				let knoKeys = ["pointName", "blockName", "blockScore", "dim", "pointScoreRate"];
+				let knoDatas = [];
+				analysisJson.kno.forEach((point) => {
+					point.block.forEach((block) => {
+						knoDatas.push({
+							pointName: point.name,
+							blockName: block,
+							blockScore: analysisJson.blk.find((i) => i.name === block).score,
+							dim: analysisJson.blk.find((i) => i.name === block).dimension[0],
+							pointScoreRate: parseInt(point.score * 100) + "%"
+						});
+					});
+				});
+				const knoSheet = {
+					title: knoHeaders,
+					key: knoKeys,
+					data: knoDatas,
+					filename: "知识点得分率",
+					autoWidth: true
+				};
+				sheets.push(knoSheet);
+				excel.export_array_to_sheet(sheets, `${this.artName}(${this.subjectList[this.curSubjectIndex].name})- 校级艺术评测报告`);
+			},
+			/* 格式化最新时间 */
+			timeFn() {
+				this.timing = setInterval(() => {
+					this.dateDay = this.$tools.formatTime(new Date(), "hh:mm:ss");
+					this.dateYear = this.$tools.formatTime(new Date(), "yyyy-MM-dd");
+				}, 1000);
+			},
+			/* 取消加载 */
+			cancelLoading() {
+				setTimeout(() => {
+					this.loading = false;
+				}, 100);
+			}
+		},
+		computed: {
+			schoolInfo() {
+				let artInfo = this.$route.params.artInfo;
+				if (artInfo) {
+					return {
+						schoolName: artInfo.name,
+						schoolLogo: "",
+						periodName: artInfo.perCname,
+						periodId: artInfo.perId,
+						curSemester: ""
+					};
+				} else {
+					let store_user = this.$store.state.user;
+					let semesterRange = this.$tools.getSemesterTimeRange();
+					return {
+						schoolName: store_user.schoolProfile.school_base.name,
+						schoolLogo: store_user.schoolProfile.school_base.picture,
+						periodName: store_user.curPeriod.name,
+						periodId: store_user.curPeriod.id,
+						curSemester: semesterRange.name_with_year
+					};
+				}
+			}
+		}
+	};
 </script>
 
 <style lang="less">
-@import "Art.less";
-@import "style.less";
+	@import "Art.less";
+	@import "style.less";
 </style>
-

+ 35 - 17
TEAMModelOS/Controllers/Analysis/ArtAnalysisController.cs

@@ -567,30 +567,48 @@ namespace TEAMModelOS.Controllers.Analysis
                     {
                         var itemPersent = kno.Count > 0 ? 1 / Convert.ToDouble(kno.Count) : 0;
                         OnePoint += point[n] * itemPersent;
-                        //获取知识点每个学生的得分
-                        foreach (string id in exam.studentIds)
+                        foreach (string id in exam.studentIds) {
+                            scores += exam.studentScores[index][n] * itemPersent;
+                        }
+                    }
+                    n++;
+                });
+                foreach (string id in exam.studentIds)
+                {
+                    double stuScore = 0;
+                    int stuIndex = exam.studentIds.IndexOf(id);
+                    int a = 0;
+                    info.papers[index].knowledge.ForEach(kno =>
+                    {
+                        if (kno.Contains(knowledgeName[k]))
                         {
-                            double stuScore = 0;
-                            int index = exam.studentIds.IndexOf(id);
-                            if (exam.studentScores[index][n] > 0)
-                            {
-                                scores += exam.studentScores[index][n] * itemPersent;
-                                stuScore = exam.studentScores[index][n] * itemPersent;
-                            }
-                            stuInfo.Add((knowledgeName[k], stuScore, OnePoint, id));
+                            var itemPersent = kno.Count > 0 ? 1 / Convert.ToDouble(kno.Count) : 0;                           
+                            stuScore += exam.studentScores[stuIndex][a] * itemPersent;
+                            
                         }
-                        foreach (var cla in exam.classes)
+                        a++;
+                    });                                    
+                    stuInfo.Add((knowledgeName[k], stuScore, OnePoint, id));
+                }
+
+                foreach (var cla in exam.classes)
+                {
+                    double classScores = 0;
+                    int b = 0;
+                    info.papers[index].knowledge.ForEach(kno =>
+                    {
+                        if (kno.Contains(knowledgeName[k]))
                         {
-                            double classScores = 0;
+                            var itemPersent = kno.Count > 0 ? 1 / Convert.ToDouble(kno.Count) : 0;
                             for (int i = cla.range[0]; i <= cla.range[1]; i++)
                             {
-                                classScores += exam.studentScores[i][n] * itemPersent;
+                                classScores += exam.studentScores[i][b] * itemPersent;
                             }
-                            classInfo.Add((knowledgeName[k], classScores, OnePoint, cla.id));
                         }
-                    }
-                    n++;
-                });
+                        b++;
+                    });                    
+                    classInfo.Add((knowledgeName[k], classScores, OnePoint, cla.id));
+                }
                 Score.Add(scores);
 
                 //该知识点平均得分

+ 1 - 1
TEAMModelOS/Controllers/Client/AClassONEController.cs

@@ -1346,7 +1346,7 @@ namespace TEAMModelOS.Controllers
         /// <param name="request"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
-        //[Authorize(Roles = "AClassONE")]
+        [Authorize(Roles = "AClassONE")]
         [HttpPost("find-activity")]
         public async Task<IActionResult> FindExam(JsonElement request)
         {

+ 1 - 1
TEAMModelOS/Controllers/Common/ExamController.cs

@@ -504,7 +504,7 @@ namespace TEAMModelOS.Controllers
                 var (userId, _, _, school) = HttpContext.GetAuthTokenInfo();
 
 
-                StringBuilder stringBuilder = new($"select c.id,c.name,c.code,c.period,c.startTime,c.endTime,c.stuCount,c.type,c.progress,c.examType,c.createTime,c.source, c.subjects, c.grades,c.owner, c.scope,c.classes, c.stuLists, c.sRate,c.lostStu,c.sStatus,c.qamode,c.school,c.cloudas from c where (c.status<>404 or IS_DEFINED(c.status) = false) and c.pk = 'Exam' ");
+                StringBuilder stringBuilder = new($"select c.id,c.name,c.code,c.period,c.startTime,c.endTime,c.stuCount,c.type,c.progress,c.examType,c.createTime,c.source, c.subjects, c.grades,c.owner, c.scope,c.classes, c.stuLists, c.sRate,c.lostStu,c.sStatus,c.qamode,c.school,c.cloudas from c where (c.status<>404 or IS_DEFINED(c.status) = false) and c.pk = 'Exam' and  c.owner = 'teacher'");
                 /*if (request.TryGetProperty("classIds", out JsonElement classIds))
                 {
                     List<string> ids = classIds.ToObject<List<string>>();

+ 16 - 31
TEAMModelOS/Controllers/System/CoreController.cs

@@ -681,9 +681,7 @@ namespace TEAMModelOS.Controllers
             string currentDirectory = Path.GetDirectoryName(attr.Assembly.Location);
             Assembly assembly = Assembly.LoadFrom($"{currentDirectory}\\TEAMModelOS.dll");
             var description = assembly.GetCustomAttribute<AssemblyDescriptionAttribute>().Description;
-            //var v1 = Assembly.GetEntryAssembly().GetName().Version;
-            //var v2 = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
-            // var description = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyDescriptionAttribute>().Description;
+           
             var version = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
             long.TryParse(version.PadRight(12, '0').Replace(".", ""),out long aver);
             long.TryParse(_option.Version.PadRight(12, '0').Replace(".", ""),out long bver );
@@ -691,17 +689,6 @@ namespace TEAMModelOS.Controllers
                 version = _option.Version;
             }
             long nowtime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
-            //Console.WriteLine($"Assembly.GetEntryAssembly().GetName().Version: " +
-
-            //                  $"{Assembly.GetEntryAssembly().GetName().Version}");5.2107.12.1
-
-            //Console.WriteLine($"Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version:" +
-            //                  $"{Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version}");5.2107.12.1
-
-            //Console.WriteLine($"Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion:" +
-
-            //                  $"{Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion}");5.2107.12
-
             var IpPort = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
             if (string.IsNullOrEmpty(IpPort))
             {
@@ -712,24 +699,22 @@ namespace TEAMModelOS.Controllers
                 IpPort = "127.0.0.1";
             }
             string ip = IpPort.Split(":")[0];
-            string os = "";
-            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
-            {//Linux
-                os = "Linux";
-            }
-            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
-            {//Windows
-                os = "Windows";
-            }
-            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
-            {//OSX
-                os = "OSX";
-            } 
+            //string os = "";
+            //if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+            //{//Linux
+            //    os = "Linux";
+            //}
+            //else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            //{//Windows
+            //    os = "Windows";
+            //}
+            //else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+            //{//OSX
+            //    os = "OSX";
+            //} 
             string region = await _searcher.SearchIpAsync(ip);
-            TimeZoneInfo localTimezone = TimeZoneInfo.Local; // 获取本地时区信息
-            var nowTime = DateTimeOffset.UtcNow.GetGMTTime();
-            int difference = (DayOfWeek.Sunday - nowTime.DayOfWeek + 7) % 7;
-            return Ok(new { difference,os, version, description, nowtime, region, ip, localTimezone , Hours = localTimezone.BaseUtcOffset.Hours, ticks=localTimezone.BaseUtcOffset.Ticks, utcNowoff =  DateTimeOffset.UtcNow, nowoff = DateTimeOffset.Now,utcNow =DateTime.UtcNow,now =DateTime.Now });
+          
+            return Ok(new {  version, description, nowtime, region, ip  });
         }
         /// <summary>
         /// 等待P1V3,啟動Dcoker,支持EMF GDI+

+ 119 - 117
TEAMModelOS/Controllers/XTest/TestController.cs

@@ -2545,122 +2545,124 @@ namespace TEAMModelOS.Controllers
             }
         }
 
-        //自主學習綱領 資料架構測試
-        [HttpPost("test-selflearn-structure")]
-        public async Task<IActionResult> TestSelfLearnStructure(JsonElement json)
-        {
-            string tmid = "1595321354";
-            PaperSimple paper = new PaperSimple()
-            {
-                id = "d774c93c-4af3-76ce-aca4-6e8a3254873b",
-                subjectId = "c5f96ea0-e65c-f15c-dc59-410da564c185",
-                code = "Paper-1595321354",
-                name = "國文洩題試卷",
-                blob = "/exam/0bfe6855-289b-4d7a-b5f5-9a027acf277c/paper/c5f96ea0-e65c-f15c-dc59-410da564c185",
-                scope = "private",
-                multipleRule = 1,
-                point = new List<double>() { 25, 25, 25, 25 },
-                answers = new List<List<string>>() { new List<string>() { "D", "C", "B", "A" } },
-                type = new List<string>() { "single", "single", "single", "single" },
-                field = new List<int>() { 1, 1, 1, 1 }
-            };
-            ////個人課程
-            //主體
-            SelfLearn selfLearnT = new SelfLearn();
-            selfLearnT.code = $"SelfLearn-{tmid}";
-            selfLearnT.id = "a6dc752f-7cae-44a5-9b7b-92cfe71cea14";
-            selfLearnT.scope = "private";
-            selfLearnT.name = "測試課程課綱";
-            selfLearnT.course = new IdName();
-            selfLearnT.course.id = "ae64e6a4-54f3-10df-a7f3-79dbe252d295";
-            selfLearnT.course.name = "測試課程001";
-            selfLearnT.creatorId = $"{tmid}";
-            selfLearnT.creatorName = "Miss Lo";
-            selfLearnT.release = true;
-            selfLearnT.groupLists.Add(new IdName { id = "a986bf87-da87-4bd3-bd90-19ee9fd52836", name = "測試課程名單" });
-            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnT);
-            //節點:章節
-            SelfLearnNode selfLearnNodeTChapter = new SelfLearnNode();
-            selfLearnNodeTChapter.code = $"SelfLearn-{tmid}";
-            selfLearnNodeTChapter.id = "0990cbb6-3228-41d0-aeb0-62209f37dc0d";
-            selfLearnNodeTChapter.name = "第一章節";
-            selfLearnNodeTChapter.selfLearnId = selfLearnT.id;
-            selfLearnNodeTChapter.nodeType = "chapter";
-            selfLearnNodeTChapter.openType = "order";
-            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeTChapter);
-            //節點:項目
-            SelfLearnNode selfLearnNodeTContent = new SelfLearnNode();
-            selfLearnNodeTContent.code = $"SelfLearn-{tmid}";
-            selfLearnNodeTContent.id = "5627184f-e9b4-4ceb-a1d0-47727db569b1";
-            selfLearnNodeTContent.name = "四則運算";
-            selfLearnNodeTContent.selfLearnId = selfLearnT.id;
-            selfLearnNodeTContent.selfLearnNodeId = selfLearnNodeTChapter.id;
-            selfLearnNodeTContent.nodeType = "content";
-            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeTContent);
-            //內容:評量
-            SelfLearnContentExam selfLearnTContentExam = new SelfLearnContentExam();
-            selfLearnTContentExam.code = $"SelfLearn-{tmid}";
-            selfLearnTContentExam.id = "07e6fdd2-6083-4eb6-ac6d-06421edb0b48";
-            selfLearnTContentExam.name = "隨堂測驗1";
-            selfLearnTContentExam.selfLearnNodeId = selfLearnNodeTContent.id;
-            selfLearnTContentExam.contentType = "exam";
-            selfLearnTContentExam.papers.Add(paper);
-            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnTContentExam);
-
-            ////學校課程
-            //主體
-            SelfLearn selfLearnS = new SelfLearn();
-            selfLearnS.pk = "SelfLearn";
-            selfLearnS.code = $"SelfLearn-{tmid}";
-            selfLearnS.id = "f05f79f2-c58d-4e27-8214-48385e2ac3cd";
-            selfLearnS.scope = "private";
-            selfLearnS.school = "hbgl";
-            selfLearnS.name = "數學一年級上學期課綱";
-            selfLearnS.subject = new IdName();
-            selfLearnS.subject.id = "c5f96ea0-e65c-f15c-dc59-410da564c185";
-            selfLearnS.subject.name = "數學";
-            selfLearnS.period = new IdName();
-            selfLearnS.period.id = "127e71a7-0ca8-82b8-476b-5269b78066f7";
-            selfLearnS.period.name = "測試國中";
-            selfLearnS.course = new IdName();
-            selfLearnS.course.id = "0d4fa541-ad4f-bee1-c604-764275f6d10e";
-            selfLearnS.course.name = "數學一";
-            selfLearnS.creatorId = $"{tmid}";
-            selfLearnS.creatorName = "Miss Lo";
-            selfLearnS.release = true;
-            selfLearnS.classes.Add(new IdName { id = "d3090c56-21de-4cc8-a962-a7e7eaa2e913", name = "2023年A班" });
-            selfLearnS.groupLists.Add(new IdName { id = "54a39ec1-be0b-43cd-a978-f3133552f291", name = "七年A班" });
-            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnS);
-            //節點:章節
-            SelfLearnNode selfLearnNodeSChapter = new SelfLearnNode();
-            selfLearnNodeSChapter.code = $"SelfLearn-{tmid}";
-            selfLearnNodeSChapter.id = "77172663-aa17-44c6-8259-61870c44121f";
-            selfLearnNodeSChapter.name = "第一章節";
-            selfLearnNodeSChapter.selfLearnId = selfLearnS.id;
-            selfLearnNodeSChapter.nodeType = "chapter";
-            selfLearnNodeSChapter.openType = "order";
-            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeSChapter);
-            //節點:項目
-            SelfLearnNode selfLearnNodeSContent = new SelfLearnNode();
-            selfLearnNodeSContent.code = $"SelfLearn-{tmid}";
-            selfLearnNodeSContent.id = "f28c6ecd-38a6-4edb-9160-363a116b8c3b";
-            selfLearnNodeSContent.name = "四則運算";
-            selfLearnNodeSContent.selfLearnId = selfLearnS.id;
-            selfLearnNodeSContent.selfLearnNodeId = selfLearnNodeSChapter.id;
-            selfLearnNodeSContent.nodeType = "content";
-            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeSContent);
-            //內容:評量
-            SelfLearnContentExam selfLearnSContentExam = new SelfLearnContentExam();
-            selfLearnSContentExam.code = $"SelfLearn-{tmid}";
-            selfLearnSContentExam.id = "3f088f49-fefa-4af5-a324-c577ffb6d1f8";
-            selfLearnSContentExam.name = "隨堂測驗1";
-            selfLearnSContentExam.selfLearnNodeId = selfLearnNodeSContent.id;
-            selfLearnSContentExam.contentType = "exam";
-            selfLearnSContentExam.papers.Add(paper);
-            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnSContentExam);
-
-            return Ok();
-
-        }
+        /*
+          //自主學習綱領 資料架構測試
+         [HttpPost("test-selflearn-structure")]
+         public async Task<IActionResult> TestSelfLearnStructure(JsonElement json)
+         {
+             string tmid = "1595321354";
+             PaperSimple paper = new PaperSimple()
+             {
+                 id = "d774c93c-4af3-76ce-aca4-6e8a3254873b",
+                 subjectId = "c5f96ea0-e65c-f15c-dc59-410da564c185",
+                 code = "Paper-1595321354",
+                 name = "國文洩題試卷",
+                 blob = "/exam/0bfe6855-289b-4d7a-b5f5-9a027acf277c/paper/c5f96ea0-e65c-f15c-dc59-410da564c185",
+                 scope = "private",
+                 multipleRule = 1,
+                 point = new List<double>() { 25, 25, 25, 25 },
+                 answers = new List<List<string>>() { new List<string>() { "D", "C", "B", "A" } },
+                 type = new List<string>() { "single", "single", "single", "single" },
+                 field = new List<int>() { 1, 1, 1, 1 }
+             };
+             ////個人課程
+             //主體
+             SelfLearn selfLearnT = new SelfLearn();
+             selfLearnT.code = $"SelfLearn-{tmid}";
+             selfLearnT.id = "a6dc752f-7cae-44a5-9b7b-92cfe71cea14";
+             selfLearnT.scope = "private";
+             selfLearnT.name = "測試課程課綱";
+             selfLearnT.course = new IdName();
+             selfLearnT.course.id = "ae64e6a4-54f3-10df-a7f3-79dbe252d295";
+             selfLearnT.course.name = "測試課程001";
+             selfLearnT.creatorId = $"{tmid}";
+             selfLearnT.creatorName = "Miss Lo";
+             selfLearnT.release = true;
+             selfLearnT.groupLists.Add(new IdName { id = "a986bf87-da87-4bd3-bd90-19ee9fd52836", name = "測試課程名單" });
+             await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnT);
+             //節點:章節
+             SelfLearnNode selfLearnNodeTChapter = new SelfLearnNode();
+             selfLearnNodeTChapter.code = $"SelfLearn-{tmid}";
+             selfLearnNodeTChapter.id = "0990cbb6-3228-41d0-aeb0-62209f37dc0d";
+             selfLearnNodeTChapter.name = "第一章節";
+             selfLearnNodeTChapter.selfLearnId = selfLearnT.id;
+             selfLearnNodeTChapter.nodeType = "chapter";
+             selfLearnNodeTChapter.openType = "order";
+             await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeTChapter);
+             //節點:項目
+             SelfLearnNode selfLearnNodeTContent = new SelfLearnNode();
+             selfLearnNodeTContent.code = $"SelfLearn-{tmid}";
+             selfLearnNodeTContent.id = "5627184f-e9b4-4ceb-a1d0-47727db569b1";
+             selfLearnNodeTContent.name = "四則運算";
+             selfLearnNodeTContent.selfLearnId = selfLearnT.id;
+             selfLearnNodeTContent.selfLearnNodeId = selfLearnNodeTChapter.id;
+             selfLearnNodeTContent.nodeType = "content";
+             await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeTContent);
+             //內容:評量
+             SelfLearnContentExam selfLearnTContentExam = new SelfLearnContentExam();
+             selfLearnTContentExam.code = $"SelfLearn-{tmid}";
+             selfLearnTContentExam.id = "07e6fdd2-6083-4eb6-ac6d-06421edb0b48";
+             selfLearnTContentExam.name = "隨堂測驗1";
+             selfLearnTContentExam.selfLearnNodeId = selfLearnNodeTContent.id;
+             selfLearnTContentExam.contentType = "exam";
+             selfLearnTContentExam.papers.Add(paper);
+             await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnTContentExam);
+
+             ////學校課程
+             //主體
+             SelfLearn selfLearnS = new SelfLearn();
+             selfLearnS.pk = "SelfLearn";
+             selfLearnS.code = $"SelfLearn-{tmid}";
+             selfLearnS.id = "f05f79f2-c58d-4e27-8214-48385e2ac3cd";
+             selfLearnS.scope = "private";
+             selfLearnS.school = "hbgl";
+             selfLearnS.name = "數學一年級上學期課綱";
+             selfLearnS.subject = new IdName();
+             selfLearnS.subject.id = "c5f96ea0-e65c-f15c-dc59-410da564c185";
+             selfLearnS.subject.name = "數學";
+             selfLearnS.period = new IdName();
+             selfLearnS.period.id = "127e71a7-0ca8-82b8-476b-5269b78066f7";
+             selfLearnS.period.name = "測試國中";
+             selfLearnS.course = new IdName();
+             selfLearnS.course.id = "0d4fa541-ad4f-bee1-c604-764275f6d10e";
+             selfLearnS.course.name = "數學一";
+             selfLearnS.creatorId = $"{tmid}";
+             selfLearnS.creatorName = "Miss Lo";
+             selfLearnS.release = true;
+             selfLearnS.classes.Add(new IdName { id = "d3090c56-21de-4cc8-a962-a7e7eaa2e913", name = "2023年A班" });
+             selfLearnS.groupLists.Add(new IdName { id = "54a39ec1-be0b-43cd-a978-f3133552f291", name = "七年A班" });
+             await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnS);
+             //節點:章節
+             SelfLearnNode selfLearnNodeSChapter = new SelfLearnNode();
+             selfLearnNodeSChapter.code = $"SelfLearn-{tmid}";
+             selfLearnNodeSChapter.id = "77172663-aa17-44c6-8259-61870c44121f";
+             selfLearnNodeSChapter.name = "第一章節";
+             selfLearnNodeSChapter.selfLearnId = selfLearnS.id;
+             selfLearnNodeSChapter.nodeType = "chapter";
+             selfLearnNodeSChapter.openType = "order";
+             await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeSChapter);
+             //節點:項目
+             SelfLearnNode selfLearnNodeSContent = new SelfLearnNode();
+             selfLearnNodeSContent.code = $"SelfLearn-{tmid}";
+             selfLearnNodeSContent.id = "f28c6ecd-38a6-4edb-9160-363a116b8c3b";
+             selfLearnNodeSContent.name = "四則運算";
+             selfLearnNodeSContent.selfLearnId = selfLearnS.id;
+             selfLearnNodeSContent.selfLearnNodeId = selfLearnNodeSChapter.id;
+             selfLearnNodeSContent.nodeType = "content";
+             await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeSContent);
+             //內容:評量
+             SelfLearnContentExam selfLearnSContentExam = new SelfLearnContentExam();
+             selfLearnSContentExam.code = $"SelfLearn-{tmid}";
+             selfLearnSContentExam.id = "3f088f49-fefa-4af5-a324-c577ffb6d1f8";
+             selfLearnSContentExam.name = "隨堂測驗1";
+             selfLearnSContentExam.selfLearnNodeId = selfLearnNodeSContent.id;
+             selfLearnSContentExam.contentType = "exam";
+             selfLearnSContentExam.papers.Add(paper);
+             await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnSContentExam);
+
+             return Ok();
+
+         }
+         */
     }
 }

+ 4 - 3
TEAMModelOS/Filter/BlobLoggerProvider.cs

@@ -55,19 +55,20 @@ namespace TEAMModelOS.Filter
             return true;
         }
 
-        public async void Log<TState> ( LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
+        public  async void Log<TState> ( LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
         {
             if (formatter == null)
             {
                 throw new ArgumentNullException(nameof(formatter));
             }
-            if (_categoryName.Equals("TEAMModelOS.Filter.RequestAuditFilter", StringComparison.OrdinalIgnoreCase)) {
+            if (_categoryName.Equals("TEAMModelOS.Filter.RequestAuditFilter", StringComparison.OrdinalIgnoreCase))
+            {
                 var message = formatter(state, exception);
                 var appendBlob = _containerClient.GetAppendBlobClient($"{_categoryName}/{DateTimeOffset.UtcNow:yyyy-MM-dd}.log");
                 // var blobClient = _containerClient.GetBlobClient($"{_categoryName}/{DateTimeOffset.UtcNow:yyyy-MM-dd}.log");
                 if (!appendBlob.Exists())
                 {
-                    await appendBlob.CreateAsync();
+                    appendBlob.Create();
                     using var stream = new MemoryStream(Encoding.UTF8.GetBytes(message));
                     await appendBlob.AppendBlockAsync(stream);
                 }

+ 43 - 16
TEAMModelOS/Filter/RequestAuditFilter.cs

@@ -12,26 +12,30 @@ using System.IdentityModel.Tokens.Jwt;
 using System.Linq;
 using Azure.Core;
 using DocumentFormat.OpenXml.Office2016.Excel;
+using TEAMModelOS.SDK.DI;
+using Microsoft.Extensions.Primitives;
+using HTEXLib.Helpers.ShapeHelpers;
 
 namespace TEAMModelOS.Filter
 {
     public class RequestAuditFilter : IAsyncActionFilter
     {
-        private readonly ILogger _logger;
-      
-        public RequestAuditFilter(ILoggerFactory loggerFactory)
+        //private readonly ILogger _logger;
+        private readonly HttpTrigger _httpTrigger;
+        public RequestAuditFilter(/*ILoggerFactory loggerFactory*/HttpTrigger httpTrigger)
         {
-            _logger = loggerFactory.CreateLogger<RequestAuditFilter>();
+          //  _logger = loggerFactory.CreateLogger<RequestAuditFilter>();
+            _httpTrigger = httpTrigger;
         }
         public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
         {
             //============== 这里是执行方法之前获取数据 ====================
 
             // 获取控制器、路由信息
-            var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
+            //var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
 
             // 获取请求的方法
-            var method = actionDescriptor.MethodInfo;
+            //var method = actionDescriptor.MethodInfo;
 
             // 获取 HttpContext 和 HttpRequest 对象
             var httpContext = context.HttpContext;
@@ -51,8 +55,18 @@ namespace TEAMModelOS.Filter
             var parameters = context.ActionArguments;
 
             // 获取操作人(必须授权访问才有值)"userId" 为你存储的 claims type,jwt 授权对应的是 payload 中存储的键名
-            var userId = httpContext.User?.FindFirstValue("userId");
+            //var userId = httpContext.User?.FindFirstValue("userId");
             var authtoken = context.HttpContext.GetXAuth("AuthToken");
+            string tokenSha = string.Empty,client = string.Empty;
+            if (context.HttpContext.Request.Headers.TryGetValue("Authorization", out StringValues Authorization)) 
+            {
+                try {
+                    string token = Authorization.ToString().Replace("Bearer ", "");
+                    var jwt = new JwtSecurityTokenHandler().ReadJwtToken(token);
+                      tokenSha = ShaHashHelper.GetSHA1(token);
+                    client = jwt.Claims.FirstOrDefault(claim => claim.Type.Equals("roles"))?.Value;
+                } catch (Exception ex ) { }
+            }
             string id = string.Empty, name = string.Empty, picture = string.Empty, school = string.Empty;
             if (!string.IsNullOrWhiteSpace(authtoken)) {
                 var jwt = new JwtSecurityTokenHandler().ReadJwtToken(authtoken);
@@ -61,22 +75,35 @@ namespace TEAMModelOS.Filter
                 name = jwt.Claims.FirstOrDefault(claim => claim.Type.Equals("name"))?.Value;
             }
             // 请求时间
-            var requestedTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
-
+            var requestedTime = DateTimeOffset.Now.GetGMTTime(8).ToUnixTimeMilliseconds();
             //============== 这里是执行方法之后获取数据 ====================
             var actionContext = await next();
-
             // 获取返回的结果
-            var returnResult = actionContext.Result;
+            // var returnResult = actionContext.Result;
 
             // 判断是否请求成功,没有异常就是请求成功
-            var isRequestSucceed = actionContext.Exception == null;
+            // var isRequestSucceed = actionContext.Exception == null;
 
             // 获取调用堆栈信息,提供更加简单明了的调用和异常堆栈
-           // var stackTrace = EnhancedStackTrace.Current();
-           // string region = await _searcher.SearchIpAsync(remoteIPv4);
-           //同一个账号,同一IP,同一接口,UA标识(UA标识随意切换则表示可能会存在DDOS),时间段
-            _logger.LogInformation(new{ ua=httpContext.GetUserAgent(), ip=remoteIPv4,time=requestedTime,path =$"{httpRequest.PathBase}{httpRequest.Path}",host= $"{httpRequest.Host}", param=parameters,id ,name ,school,succeed =isRequestSucceed }.ToJsonString());
+            // var stackTrace = EnhancedStackTrace.Current();
+            // string region = await _searcher.SearchIpAsync(remoteIPv4);
+            //同一个账号,同一IP,同一接口,UA标识(UA标识随意切换则表示可能会存在DDOS),时间段
+             //_logger.LogInformation(new{ ua=httpContext.GetUserAgent(), ip=remoteIPv4,time=requestedTime,path =$"{httpRequest.PathBase}{httpRequest.Path}",host= $"{httpRequest.Host}", param=parameters,id ,name ,school,succeed =isRequestSucceed }.ToJsonString());
+            var data = new {
+                //ua = httpContext.GetUserAgent(),
+                ip = remoteIPv4,
+                time = requestedTime,
+                path = $"{httpRequest.PathBase}{httpRequest.Path}",
+                host = $"{httpRequest.Host}",
+                param = parameters,
+                id,
+                name,
+                school,
+                client,tid= tokenSha,
+                p="os",
+            };
+            _= _httpTrigger.RequestHttpTrigger(data, "China", "http-log");
+            
         }
     }
 }

+ 10 - 8
TEAMModelOS/Program.cs

@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Hosting;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
 using System;
+using TEAMModelOS.Filter;
 using TEAMModelOS.SDK;
 
 namespace TEAMModelOS
@@ -17,14 +18,15 @@ namespace TEAMModelOS
 
         public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
-            //.ConfigureLogging(logging => {
-            //    logging.ClearProviders();
-            //    logging.AddConsole();
-            //    logging.AddDebug();
-            //    logging.AddEventLog();
-            //    logging.AddAzureWebAppDiagnostics();
-            //    logging.AddProvider(new BlobLoggerProvider());
-            //})
+               //.ConfigureLogging(logging =>
+               //{
+               //    logging.ClearProviders();
+               //    logging.AddConsole();
+               //    logging.AddDebug();
+               //    logging.AddEventLog();
+               //    logging.AddAzureWebAppDiagnostics();
+               //    logging.AddProvider(new BlobLoggerProvider());
+               //})
                .ConfigureWebHostDefaults(webBuilder =>
                {
 #if DEBUG 

+ 2 - 2
TEAMModelOS/Startup.cs

@@ -193,8 +193,8 @@ namespace TEAMModelOS
             services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));
             services.AddXkwAPIHttpService(Configuration);
             //services.AddHostedService<>
-            //services.AddSingleton<ILoggerProvider, BlobLoggerProvider>();
-            //services.AddMvcFilter<RequestAuditFilter>();
+           // services.AddSingleton<ILoggerProvider, BlobLoggerProvider>();
+            services.AddMvcFilter<RequestAuditFilter>();
             services.AddNetMail(Configuration.GetSection("MailOption").Get<MailOptions>());
 #if !DEBUG
  //第一步: 配置gzip与br的压缩等级为最优