소스 검색

!1076 增加首页可拖拽看板
Merge pull request !1076 from SW/next

zuohuaijun 1 년 전
부모
커밋
30b61d584c

+ 40 - 0
.vscode/launch.json

@@ -0,0 +1,40 @@
+{
+  // Use IntelliSense to learn about possible attributes.
+  // Hover to view descriptions of existing attributes.
+  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "web",
+      "command": "vite",
+      "request": "launch",
+      "type": "node-terminal",
+      "cwd": "${workspaceFolder}/Web"
+    },
+    {
+      "name": ".NET",
+      "type": "coreclr",
+      "request": "launch",
+      "preLaunchTask": "build",
+      "program": "${workspaceFolder}/Admin.NET/Admin.NET.Web.Entry/bin/Debug/net6.0/Admin.NET.Web.Entry.dll",
+      "args": [],
+      "cwd": "${workspaceFolder}/Admin.NET/Admin.NET.Web.Entry",
+      "stopAtEntry": false,
+      "serverReadyAction": {
+        "action": "openExternally",
+        "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
+      },
+      "env": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      },
+      "sourceFileMap": {
+        "/Views": "${workspaceFolder}/Views"
+      }
+    },
+    {
+      "name": ".NET Core Attach",
+      "type": "coreclr",
+      "request": "attach"
+    }
+  ]
+}

+ 41 - 0
.vscode/tasks.json

@@ -0,0 +1,41 @@
+{
+  "version": "2.0.0",
+  "tasks": [
+    {
+      "label": "build",
+      "command": "dotnet",
+      "type": "process",
+      "args": [
+        "build",
+        "${workspaceFolder}/Admin.NET/Admin.NET.sln",
+        "/property:GenerateFullPaths=true",
+        "/consoleloggerparameters:NoSummary;ForceNoAlign"
+      ],
+      "problemMatcher": "$msCompile"
+    },
+    {
+      "label": "publish",
+      "command": "dotnet",
+      "type": "process",
+      "args": [
+        "publish",
+        "${workspaceFolder}/Admin.NET/Admin.NET.sln",
+        "/property:GenerateFullPaths=true",
+        "/consoleloggerparameters:NoSummary;ForceNoAlign"
+      ],
+      "problemMatcher": "$msCompile"
+    },
+    {
+      "label": "watch",
+      "command": "dotnet",
+      "type": "process",
+      "args": [
+        "watch",
+        "run",
+        "--project",
+        "${workspaceFolder}/Admin.NET/Admin.NET.sln"
+      ],
+      "problemMatcher": "$msCompile"
+    }
+  ]
+}

+ 3 - 0
Admin.NET/Admin.NET.Core/Logging/DatabaseLoggingWriter.cs

@@ -51,6 +51,9 @@ public class DatabaseLoggingWriter : IDatabaseLoggingWriter, IDisposable
             return;
         }
 
+        var loggingMonitor1 = JSON.Deserialize<JObject>(jsonStr);
+        // 不记录数据校验日志
+        if (loggingMonitor1["validation"] != null) return;
         var loggingMonitor = JSON.Deserialize<dynamic>(jsonStr);
         // 不记录数据校验日志
         if (loggingMonitor.validation != null) return;

+ 1 - 0
Web/package.json

@@ -59,6 +59,7 @@
 		"vue-router": "^4.3.2",
 		"vue-signature-pad": "^3.0.2",
 		"vue3-tree-org": "^4.2.2",
+		"vuedraggable": "4.0.3",
 		"xlsx-js-style": "^1.2.0"
 	},
 	"devDependencies": {

+ 236 - 0
Web/src/assets/img/ver.svg

@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 456 262.1" style="enable-background:new 0 0 456 262.1;" xml:space="preserve">
+<style type="text/css">
+	.st0{opacity:0.4;fill:url(#SVGID_1_);enable-background:new    ;}
+	.st1{opacity:0.7;}
+	.st2{opacity:0.4;fill:url(#SVGID_2_);enable-background:new    ;}
+	.st3{opacity:0.4;fill:url(#SVGID_3_);enable-background:new    ;}
+	.st4{opacity:0.4;fill:url(#SVGID_4_);enable-background:new    ;}
+	.st5{opacity:0.4;fill:url(#SVGID_5_);enable-background:new    ;}
+	.st6{opacity:0.6;}
+	.st7{fill:#0073CD;}
+	.st8{fill:#40A8F5;}
+	.st9{fill:#53B9F5;}
+	.st10{fill:#85D3FF;}
+	.st11{fill:#8CD7FF;}
+	.st12{fill:#EBFCFF;}
+	.st13{fill:none;stroke:url(#SVGID_6_);stroke-width:2;stroke-miterlimit:10;}
+	.st14{fill:none;stroke:url(#SVGID_7_);stroke-width:2;stroke-miterlimit:10;}
+	.st15{fill:none;stroke:url(#SVGID_8_);stroke-width:2;stroke-miterlimit:10;}
+	.st16{fill:none;stroke:url(#SVGID_9_);stroke-width:2;stroke-miterlimit:10;}
+	.st17{fill:none;stroke:url(#SVGID_10_);stroke-width:2;stroke-miterlimit:10;}
+	.st18{fill:none;stroke:url(#SVGID_11_);stroke-width:2;stroke-miterlimit:10;}
+</style>
+<title>升级中</title>
+<g id="图层_2_1_">
+	<g id="图层_1-2">
+		
+			<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="232.745" y1="39.57" x2="232.745" y2="1.88" gradientTransform="matrix(1 0 0 -1 0 264)">
+			<stop  offset="0" style="stop-color:#81CFFF"/>
+			<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+		</linearGradient>
+		<path class="st0" d="M412.3,262.1c-23-23-61-37.7-179.5-37.7S76.2,239.1,53.2,262.1H412.3z"/>
+		<g class="st1">
+			
+				<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="349.365" y1="237.3224" x2="349.365" y2="59.9676" gradientTransform="matrix(1 0 0 -1 0 264)">
+				<stop  offset="0" style="stop-color:#81CFFF"/>
+				<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+			</linearGradient>
+			<path class="st2" d="M380.7,26.7h-62.6c-1.5-0.1-2.8,1.1-2.8,2.6v172.2c0.1,1.5,1.3,2.7,2.8,2.6h62.6c1.5,0.1,2.7-1.1,2.8-2.6
+				V29.3C383.4,27.8,382.2,26.6,380.7,26.7z M328.3,147c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.8c0,0,0,0,0,0
+				v-19.7c0-0.5,0.4-0.9,0.9-0.9c0,0,0,0,0,0h3.6c0.5,0,0.9,0.4,0.9,0.9c0,0,0,0,0,0V147z M328.3,116.8c0,0.5-0.4,0.9-0.9,0.9
+				c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0V97c0-0.5,0.4-0.9,0.9-0.9c0,0,0,0,0,0h3.6c0.5,0,0.9,0.4,0.9,0.9
+				c0,0,0,0,0,0V116.8z M328.3,86.5c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0V66.8
+				c0-0.5,0.4-0.9,0.9-0.9c0,0,0,0,0,0h3.6c0.5,0,0.9,0.4,0.9,0.9c0,0,0,0,0,0V86.5z M328.3,56.3c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0
+				h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0V36.6c0-0.5,0.4-0.9,0.9-0.9c0,0,0,0,0,0h3.6c0.5,0,0.9,0.4,0.9,0.9c0,0,0,0,0,0V56.3z
+				 M340,147c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0v-19.7c0-0.5,0.4-0.9,1-0.9h3.6
+				c0.5,0,0.9,0.4,0.9,0.9V147z M340,116.8c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-1-0.9V97c0-0.5,0.4-0.9,1-0.9h3.6
+				c0.5,0,0.9,0.4,0.9,0.9V116.8z M340,86.5c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-1-0.9V66.8c0-0.5,0.4-0.9,1-0.9h3.6
+				c0.5,0,0.9,0.4,0.9,0.9V86.5z M340,56.3c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-1-0.9V36.6c0-0.5,0.4-0.9,1-0.9h3.6
+				c0.5,0,0.9,0.4,0.9,0.9V56.3z M351.7,147c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0v-19.7
+				c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V147z M351.7,116.8c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V97
+				c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V116.8z M351.7,86.5c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V66.8
+				c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V86.5z M351.7,56.3c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V36.6
+				c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V56.3z M363.4,147c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6
+				c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0v-19.7c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V147z M363.4,116.8
+				c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V97c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V116.8z M363.4,86.5
+				c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V66.8c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V86.5z M363.4,56.3
+				c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V36.6c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V56.3z M375.1,147
+				c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0v-19.7c0-0.5,0.4-0.9,0.9-0.9h3.6
+				c0.5,0,0.9,0.4,1,0.9V147z M375.1,116.8c0,0.5-0.4,0.9-1,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V97c0-0.5,0.4-0.9,0.9-0.9h3.6
+				c0.5,0,0.9,0.4,1,0.9V116.8z M375.1,86.5c0,0.5-0.4,0.9-1,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V66.8c0-0.5,0.4-0.9,0.9-0.9h3.6
+				c0.5,0,0.9,0.4,1,0.9V86.5z M375.1,56.3c0,0.5-0.4,0.9-1,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V36.6c0-0.5,0.4-0.9,0.9-0.9h3.6
+				c0.5,0,0.9,0.4,1,0.9V56.3z"/>
+			
+				<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="201.46" y1="208.3924" x2="201.46" y2="59.9976" gradientTransform="matrix(1 0 0 -1 0 264)">
+				<stop  offset="0" style="stop-color:#81CFFF"/>
+				<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+			</linearGradient>
+			<path class="st3" d="M231.1,55.6h-59.3c-1.5-0.1-2.7,1.1-2.8,2.6v143.2c0.1,1.5,1.3,2.6,2.8,2.6h59.3c1.5,0.1,2.8-1.1,2.8-2.6
+				V58.2C233.9,56.7,232.6,55.5,231.1,55.6z M182.5,159.4c0,0.6-0.6,1.1-1.2,1.1h-5.4c-0.6,0-1.2-0.5-1.2-1.1v-5.2
+				c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V159.4z M182.5,146.5c0,0.6-0.6,1.1-1.2,1.1
+				c0,0,0,0,0,0h-5.4c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1V146.5z
+				 M182.5,133.6c0,0.6-0.6,1.1-1.2,1.1h-5.4c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4
+				c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V133.6z M182.5,120.7c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-5.4c-0.6,0-1.2-0.5-1.2-1.1
+				c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1V120.7z M182.5,107.8c0,0.6-0.6,1.1-1.2,1.1h-5.4
+				c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V107.8z M182.5,94.9
+				c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-5.4c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4
+				c0.6,0,1.2,0.5,1.2,1.1V94.9z M182.5,82.1c0,0.6-0.6,1.1-1.2,1.1h-5.4c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1
+				c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V82.1z M182.5,69.2c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-5.4
+				c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0V64c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1V69.2z M192.6,159.4
+				c0,0.6-0.6,1.1-1.2,1.1H186c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1
+				c0,0,0,0,0,0L192.6,159.4z M192.6,146.5c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H186c-0.6,0-1.2-0.5-1.2-1.1v-5.2
+				c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1L192.6,146.5z M192.6,133.6c0,0.6-0.6,1.1-1.2,1.1H186
+				c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L192.6,133.6z
+				 M192.6,120.7c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H186c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4
+				c0.6,0,1.2,0.5,1.2,1.1L192.6,120.7z M192.6,107.8c0,0.6-0.6,1.1-1.2,1.1H186c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2
+				c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L192.6,107.8z M192.6,94.9c0,0.6-0.6,1.1-1.2,1.1
+				c0,0,0,0,0,0H186c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1L192.6,94.9z
+				 M192.6,82.1c0,0.6-0.6,1.1-1.2,1.1H186c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4
+				c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L192.6,82.1z M192.6,69.2c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H186c-0.6,0-1.2-0.5-1.2-1.1V64
+				c0-0.6,0.5-1.2,1.2-1.2c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1L192.6,69.2z M202.6,159.4c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H196
+				c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1L202.6,159.4z M202.6,146.5
+				c0,0.6-0.6,1.1-1.2,1.1H196c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1
+				c0,0,0,0,0,0L202.6,146.5z M202.6,133.6c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H196c-0.6,0-1.2-0.5-1.2-1.1v-5.2
+				c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1L202.6,133.6z M202.6,120.7c0,0.6-0.6,1.1-1.2,1.1H196
+				c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L202.6,120.7z
+				 M202.6,107.8c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H196c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4
+				c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L202.6,107.8z M202.6,94.9c0,0.6-0.6,1.1-1.2,1.1H196c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0
+				v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L202.6,94.9z M202.6,82.1c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0
+				H196c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L202.6,82.1z
+				 M202.6,69.2c0,0.6-0.6,1.1-1.2,1.1H196c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0V64c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.4,1.2,1.1
+				c0,0,0,0,0,0V69.2z M227.8,159.4c0,0.6-0.6,1.1-1.2,1.1h-20.5c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0
+				h20.5c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L227.8,159.4z M227.8,146.5c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-20.5
+				c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h20.5c0.6,0,1.2,0.5,1.2,1.1L227.8,146.5z M227.8,133.6
+				c0,0.6-0.6,1.1-1.2,1.1h-20.5c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h20.5c0.6,0,1.2,0.5,1.2,1.1
+				c0,0,0,0,0,0L227.8,133.6z M227.8,120.7c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-20.5c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2
+				c0-0.6,0.6-1.1,1.2-1.1h20.5c0.6,0,1.2,0.5,1.2,1.1L227.8,120.7z M227.8,107.8c0,0.6-0.6,1.1-1.2,1.1h-20.5
+				c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h20.5c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L227.8,107.8z
+				 M227.8,94.9c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-20.5c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h20.5
+				c0.6,0,1.2,0.5,1.2,1.1L227.8,94.9z M227.8,82.1c0,0.6-0.6,1.1-1.2,1.1h-20.5c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1
+				c0,0,0,0,0,0h20.5c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L227.8,82.1z M227.8,69.2c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-20.5
+				c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0V64c0-0.6,0.6-1.1,1.2-1.1h20.5c0.6,0,1.2,0.5,1.2,1.1L227.8,69.2z"/>
+			
+				<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="122.975" y1="237.3228" x2="122.975" y2="59.9971" gradientTransform="matrix(1 0 0 -1 0 264)">
+				<stop  offset="0" style="stop-color:#81CFFF"/>
+				<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+			</linearGradient>
+			<path class="st4" d="M161.1,26.7H84.8c-1.5-0.1-2.8,1.1-2.8,2.6c0,0,0,0,0,0v172.2c0.1,1.5,1.3,2.6,2.8,2.6h76.3
+				c1.5,0.1,2.8-1.1,2.8-2.6V29.3C163.9,27.8,162.6,26.6,161.1,26.7z M154.3,161c0,0.6-0.6,1.1-1.2,1.1H92.8c-0.6,0-1.2-0.5-1.2-1.1
+				c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V161z M154.3,146.3
+				c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H92.8c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3
+				c0.6,0,1.2,0.5,1.2,1.1V146.3z M154.3,131.6c0,0.6-0.6,1.1-1.2,1.1H92.8c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2
+				c0-0.6,0.6-1.1,1.2-1.1h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V131.6z M154.3,117c0,0.6-0.6,1.1-1.2,1.1H92.8
+				c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V117z
+				 M154.3,102.3c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H92.8c-0.6,0-1.2-0.5-1.2-1.1V97c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3
+				c0.6,0,1.2,0.5,1.2,1.1V102.3z M154.3,87.6c0,0.6-0.6,1.1-1.2,1.1H92.8c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.3
+				c0-0.6,0.6-1.1,1.2-1.1h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V87.6z M154.3,72.9c0,0.6-0.6,1.1-1.2,1.1H92.8
+				c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.3c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V72.9z
+				 M154.3,58.3c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H92.8c-0.6,0-1.2-0.5-1.2-1.1V53c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3
+				c0.6,0,1.2,0.5,1.2,1.1V58.3z M154.3,43.6c0,0.6-0.6,1.1-1.2,1.1H92.8c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.3
+				c0-0.6,0.6-1.1,1.2-1.1h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V43.6z"/>
+			
+				<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="273.51" y1="264" x2="273.51" y2="54.46" gradientTransform="matrix(1 0 0 -1 0 264)">
+				<stop  offset="0" style="stop-color:#81CFFF"/>
+				<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+			</linearGradient>
+			<path class="st5" d="M306.2,0h-65.4c-1.4,0-2.5,1.2-2.4,2.6v204.4c-0.1,1.4,1,2.5,2.4,2.6c0,0,0,0,0,0h65.4
+				c1.4-0.1,2.5-1.2,2.4-2.6V2.6C308.7,1.2,307.6,0.1,306.2,0z M300.4,119.6c0,0.6-0.4,1.1-1,1.1h-51.7c-0.6,0-1-0.5-1-1.1v-5.2
+				c0-0.6,0.4-1.1,1-1.1h51.7c0.6,0,1,0.5,1,1.1L300.4,119.6z M300.4,90.3c0,0.6-0.4,1.1-1,1.1h-51.7c-0.6,0-1-0.5-1-1.1V85
+				c0-0.6,0.4-1.1,1-1.1h51.7c0.6,0,1,0.5,1,1.1L300.4,90.3z M300.4,60.9c0,0.6-0.4,1.1-1,1.1h-51.7c-0.6,0-1-0.5-1-1.1v-5.2
+				c0-0.6,0.4-1.1,1-1.1h51.7c0.6,0,1,0.5,1,1.1L300.4,60.9z M300.4,31.5c0,0.6-0.4,1.1-1,1.1h-51.7c-0.6,0-1-0.5-1-1.1v-5.2
+				c0-0.6,0.4-1.1,1-1.1h51.7c0.6,0,1,0.5,1,1.1L300.4,31.5z M300.4,16.9c0,0.6-0.4,1.1-1,1.1h-51.7c-0.6,0-1-0.5-1-1.1v-5.2
+				c0-0.6,0.4-1.1,1-1.1h51.7c0.6,0,1,0.5,1,1.1L300.4,16.9z"/>
+		</g>
+		<g class="st6">
+			<path class="st7" d="M244.2,130.7c3.3,1.9,5.7,13.6,1,20.7c-5.3,6.8-7,9-6.1,14c-4.3-7.3-0.6-7.4-5.8-14.2
+				c-4.6-6.2-2.5-17.4,0.7-20.5C237.4,131.3,240.8,131.3,244.2,130.7L244.2,130.7z"/>
+			<path class="st8" d="M280.4,211.9c-0.1,0.6-0.1,1.2-0.1,1.7c0,0.7,0.1,1.3,0.2,2c-2.1-0.8-4.3-1.2-6.5-1.2
+				c-2.6,0-5.2,0.6-7.5,1.7c-0.8-4.2-4.8-7-9-6.2c-2.8,0.5-5,2.5-5.9,5.2c-3.4-2.1-7.7-2-11.1,0.1c-0.4-5.7-4.1-0.8-9.8-0.8
+				c-6,0-11.8-4.4-11.8,1.7c0,1.1,0.2,2.2,0.4,3.2c-1.1,0.1-2.1,0.5-3,1c-0.9-7-6.8-12.4-13.9-12.7c22.6-10.3,22.4-44.6,24.8-74.6
+				c0.1-1.7,1.2-4.1,1.8-4.4l0,0c1.5,1.1,3.2,1.8,5.1,2.1c-3.2,3.1-5.4,14.3-0.7,20.5c5.3,6.8,1.6,6.9,5.8,14.2
+				c-0.9-5,0.8-7.2,6.1-14c4.8-7.2,2.3-18.8-1-20.7c1.8-0.3,3.6-1,5.1-2.1l0,0c0.6,0.3,1.7,2.7,1.8,4.4
+				C253.6,164.6,250.4,198.5,280.4,211.9z"/>
+			<path class="st9" d="M303.3,203.2c-5.4,0-9.8,4.4-9.8,9.8c0,0.3,0,0.6,0,0.9c-1.5-1.7-3.7-2.6-6-2.5c-0.7,0-1.4,0.1-2.1,0.3
+				c0.7-1.3,1.1-2.8,1.1-4.3c-0.1-4.6-3.9-8.3-8.5-8.2c-4,0.1-7.4,3-8.1,6.9c-0.1,0.4-0.1,0.9-0.1,1.3c0,0.5,0,1,0.1,1.6
+				c-3.5-1.4-7.4-1.3-10.8,0.4c-0.7-3.2-3.9-5.3-7.2-4.6c-2,0.4-3.6,1.9-4.3,3.8c-1.3-0.8-2.7-1.2-4.2-1.2c-1.5,0-3.1,0.4-4.4,1.3
+				c-0.2-4.6-4.1-8.2-8.7-8s-8.2,4.1-8,8.7l0,0c0,0.8,0.1,1.7,0.3,2.5c-0.8,0.1-1.6,0.4-2.3,0.8c-0.7-5.4-5.2-9.6-10.7-9.8h-0.4
+				c-3.4,0-6.7,1.6-8.8,4.3c-3-6.2-10.4-8.9-16.7-5.9c-2.9,1.4-5.2,3.9-6.3,7c4.1,3,6.6,7.8,6.6,12.9c0,2.3-0.5,4.6-1.5,6.6
+				c2-2.2,4.8-3.4,7.8-3.4c0.9,0,1.8,0.1,2.7,0.3c-2.9-5-1.2-11.5,3.8-14.4c1.2-0.7,2.6-1.2,3.9-1.3c0.5-0.1,0.9-0.1,1.4-0.1
+				c5.8,0,10.6,4.7,10.6,10.6l0,0c0,0.6-0.1,1.3-0.2,1.9c4.4-1.7,9.3-1.6,13.6,0.4c0.9-4.1,4.9-6.7,9-5.8c2.6,0.6,4.7,2.4,5.5,4.9
+				c1.6-0.9,3.5-1.4,5.3-1.4c1.9,0,3.8,0.5,5.4,1.5l0.1,0.1c0.3-4.5,3.6-8.4,8-9.4c0.8-0.2,1.7-0.3,2.5-0.3
+				c5.8,0,10.6,4.7,10.6,10.6c0,1-0.2,2-0.4,3c1.1,0.1,2.1,0.5,3,1c1-7,7-12.1,14-12.1c1.5,0,3,0.2,4.4,0.7c2.6,0.8,5,2.5,6.7,4.6
+				c2.4-4.8,7-8.2,12.4-8.8C311.4,205.9,307.6,203.2,303.3,203.2z"/>
+			<path class="st10" d="M314.4,209.9c-0.6,0-1.2,0-1.8,0.1c-5.4,0.6-10.1,3.9-12.5,8.7c-1.7-2.2-4-3.8-6.7-4.6
+				c-1.4-0.5-2.9-0.7-4.4-0.7c-7,0-13,5.2-14,12.1c-0.9-0.5-1.9-0.9-3-1c0.3-1,0.4-2,0.4-3c0-5.8-4.7-10.5-10.5-10.5
+				c-0.8,0-1.7,0.1-2.5,0.3c-4.4,1.1-7.7,4.9-8,9.4l-0.1-0.1c-1.6-1-3.5-1.5-5.4-1.5c-1.9,0-3.7,0.5-5.3,1.4c-1.4-3.9-5.7-6-9.6-4.6
+				c-2.5,0.9-4.3,3-4.9,5.5c-4.3-2-9.2-2.1-13.6-0.4c0.1-0.6,0.2-1.3,0.2-1.9c0-5.8-4.7-10.6-10.6-10.6l0,0c-0.5,0-0.9,0-1.4,0.1
+				c-5.8,0.8-9.9,6.1-9.1,11.8c0.2,1.4,0.6,2.7,1.3,3.9c-0.9-0.2-1.8-0.3-2.7-0.3c-2.9,0-5.8,1.2-7.8,3.4c1-2.1,1.5-4.3,1.5-6.6
+				c0-5.1-2.4-9.9-6.6-12.9l0,0c-7.1-5.2-17-3.6-22.2,3.5c-5.2,7.1-3.6,17,3.5,22.2c6.8,5,16.4,3.7,21.7-2.8
+				c-2.1,5.5,0.7,11.6,6.1,13.6c5.5,2.1,11.6-0.7,13.6-6.1c0.5-1.2,0.7-2.5,0.7-3.7c0-1.9,0.4-0.1,0.4,2.7c0,9.7,7.8,17.6,17.5,17.6
+				c9.7,0,17.6-7.8,17.6-17.5c0-2.4-0.5-4.8-1.4-7l0.5-0.1c0.5,5.8,5.7,10.1,11.5,9.5c5-0.5,9-4.4,9.5-9.4c1.7,1,3.6,1.6,5.5,1.6
+				c0.6,0,1.2,0,1.7-0.1v0.1c0,4.2,3.4,7.6,7.6,7.5c2.6,0,5-1.4,6.4-3.6c4.7,6.3,13.5,7.5,19.8,2.9c1.5-1.1,2.8-2.5,3.7-4.2
+				c4.9,7.3,14.8,9.1,22.1,4.2s9.1-14.8,4.2-22.1C324.5,212.5,319.6,209.9,314.4,209.9L314.4,209.9z"/>
+		</g>
+		<path class="st11" d="M239.1,70c6.4,0,11.6,5.2,11.6,11.6c0,6.4-5.2,11.6-11.6,11.6c-6.4,0-11.6-5.2-11.6-11.6c0,0,0,0,0,0
+			C227.5,75.2,232.7,70,239.1,70z"/>
+		<path class="st8" d="M239.1,137.2c8.3,0,13.5-1.7,16.6-7.9c0,3.2-1.5,6.2-4.1,8.1c-1.9,1.3-4,2.2-6.2,2.6c-4.1,0.8-8.4,0.8-12.5,0
+			c-2.2-0.4-4.3-1.3-6.2-2.6c-2.6-1.9-4.2-4.9-4.2-8.1C225.6,135.5,230.7,137.2,239.1,137.2z"/>
+		<path class="st8" d="M288.4,151.7c0,0.5-0.3,0.8-0.8,0.8c-0.3,0-0.5-0.1-0.7-0.3c-7.6-10.3-25.5-25-30.4-24.7
+			c2.4-6.1,3.4-15.9,3.6-31.2C271.5,100.3,288.3,122.4,288.4,151.7z"/>
+		<path class="st8" d="M218.1,96.3c0.3,15.2,1.2,25,3.6,31.1l-0.2,0.1c-4.9-0.3-22.8,14.5-30.4,24.7c-0.3,0.4-0.8,0.5-1.1,0.2
+			c-0.2-0.2-0.4-0.4-0.3-0.7C189.7,122.3,206.6,100.2,218.1,96.3L218.1,96.3z"/>
+		<path class="st8" d="M250.7,81.6c0-6.4-5.2-11.6-11.6-11.6c-6.4,0-11.6,5.2-11.6,11.6s5.2,11.6,11.6,11.6l0,0
+			C245.5,93.2,250.7,88,250.7,81.6z M252.9,81.6c0,7.6-6.2,13.8-13.8,13.8c-7.6,0-13.8-6.2-13.8-13.8c0-7.6,6.2-13.8,13.8-13.8
+			c0,0,0,0,0,0C246.7,67.8,252.9,74,252.9,81.6z"/>
+		<path class="st8" d="M239.1,48.7c5.7,0,10.7-2,13.8-4.9c0.5,1.3,1,2.6,1.4,4c-3.3,3.3-8.9,5.4-15.3,5.4s-11.9-2.1-15.3-5.4
+			c0.5-1.3,1-2.7,1.4-4C228.4,46.8,233.4,48.7,239.1,48.7z"/>
+		<path class="st9" d="M252.9,43.8c-3.1,3-8.1,4.9-13.8,4.9s-10.7-2-13.8-4.9c2-5.1,4.5-10,7.6-14.5c0.5-0.7,0.9-1.3,1.4-1.9
+			c2-2.7,5.8-3.2,8.5-1.2c0.4,0.3,0.8,0.7,1.2,1.2c0.5,0.6,0.9,1.2,1.4,1.9C248.4,33.8,250.9,38.7,252.9,43.8z"/>
+		<path class="st10" d="M260.1,96.4c-0.3,15.3-1.2,25-3.6,31.2c-0.2,0.6-0.5,1.2-0.8,1.7c-3.1,6.2-8.3,7.9-16.6,7.9
+			s-13.5-1.7-16.6-7.9c-0.3-0.6-0.5-1.1-0.8-1.8c-2.4-6.2-3.4-15.9-3.6-31.1c-0.1-3.4-0.1-7.1-0.1-11.1c-0.1-12.7,1.8-25.4,5.8-37.5
+			c3.3,3.3,8.9,5.4,15.3,5.4s11.9-2.1,15.3-5.4c4,12.1,6,24.8,5.8,37.5C260.2,89.2,260.1,92.9,260.1,96.4z M252.9,81.6
+			c0-7.6-6.2-13.8-13.8-13.8c-7.6,0-13.8,6.2-13.8,13.8c0,7.6,6.2,13.8,13.8,13.8c0,0,0,0,0,0C246.7,95.4,252.9,89.2,252.9,81.6
+			L252.9,81.6z"/>
+		<path class="st12" d="M139.2,246.1l18.4,0.4v0.7l-19.4-0.4v-0.7V246C138.4,246.1,138.6,246.1,139.2,246.1z"/>
+		
+			<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="112.2357" y1="190.775" x2="112.2357" y2="101.005" gradientTransform="matrix(1 0 0 -1 0 264)">
+			<stop  offset="0" style="stop-color:#81CFFF"/>
+			<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+		</linearGradient>
+		<line class="st13" x1="112.2" y1="73.2" x2="112.2" y2="163"/>
+		
+			<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="348.955" y1="195.605" x2="348.955" y2="105.835" gradientTransform="matrix(1 0 0 -1 0 264)">
+			<stop  offset="0" style="stop-color:#81CFFF"/>
+			<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+		</linearGradient>
+		<line class="st14" x1="349" y1="68.4" x2="349" y2="158.2"/>
+		
+			<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="40.9" y1="120.12" x2="40.9" y2="64.49" gradientTransform="matrix(1 0 0 -1 0 264)">
+			<stop  offset="0" style="stop-color:#81CFFF"/>
+			<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+		</linearGradient>
+		<line class="st15" x1="40.9" y1="143.9" x2="40.9" y2="199.5"/>
+		
+			<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="64.97" y1="168.64" x2="64.97" y2="140.83" gradientTransform="matrix(1 0 0 -1 0 264)">
+			<stop  offset="0" style="stop-color:#81CFFF"/>
+			<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+		</linearGradient>
+		<line class="st16" x1="65" y1="95.4" x2="65" y2="123.2"/>
+		
+			<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="397.23" y1="159.8" x2="397.23" y2="131.98" gradientTransform="matrix(1 0 0 -1 0 264)">
+			<stop  offset="0" style="stop-color:#81CFFF"/>
+			<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+		</linearGradient>
+		<line class="st17" x1="397.2" y1="104.2" x2="397.2" y2="132"/>
+		
+			<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="424.75" y1="130.51" x2="424.75" y2="74.87" gradientTransform="matrix(1 0 0 -1 0 264)">
+			<stop  offset="0" style="stop-color:#81CFFF"/>
+			<stop  offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
+		</linearGradient>
+		<line class="st18" x1="424.8" y1="133.5" x2="424.8" y2="189.1"/>
+	</g>
+</g>
+</svg>

+ 74 - 0
Web/src/components/scEcharts/echarts-theme-T.js

@@ -0,0 +1,74 @@
+const T = {
+	"color": [
+		"#409EFF",
+		"#36CE9E",
+		"#f56e6a",
+		"#626c91",
+		"#edb00d",
+		"#909399"
+	],
+	'grid': {
+		'left': '3%',
+		'right': '3%',
+		'bottom': '10',
+		'top': '40',
+		'containLabel': true
+	},
+	"legend": {
+		"textStyle": {
+			"color": "#999"
+		},
+		"inactiveColor": "rgba(128,128,128,0.4)"
+	},
+	"categoryAxis": {
+		"axisLine": {
+			"show": true,
+			"lineStyle": {
+				"color": "rgba(128,128,128,0.2)",
+				"width": 1
+			}
+		},
+		"axisTick": {
+			"show": false,
+			"lineStyle": {
+				"color": "#333"
+			}
+		},
+		"axisLabel": {
+			"color": "#999"
+		},
+		"splitLine": {
+			"show": false,
+			"lineStyle": {
+				"color": [
+					"#eee"
+				]
+			}
+		},
+		"splitArea": {
+			"show": false,
+			"areaStyle": {
+				"color": [
+					"rgba(255,255,255,0.01)",
+					"rgba(0,0,0,0.01)"
+				]
+			}
+		}
+	},
+	"valueAxis": {
+		"axisLine": {
+			"show": false,
+			"lineStyle": {
+				"color": "#999"
+			}
+		},
+		"splitLine": {
+			"show": true,
+			"lineStyle": {
+				"color": "rgba(128,128,128,0.2)"
+			}
+		}
+	}
+}
+
+export default T

+ 68 - 0
Web/src/components/scEcharts/index.vue

@@ -0,0 +1,68 @@
+<template>
+	<div ref="scEcharts" :style="{height:height, width:width}"></div>
+</template>
+
+<script>
+import * as echarts from 'echarts';
+import T from './echarts-theme-T.js';
+
+echarts.registerTheme('T', T);
+const unwarp = (obj) => obj && (obj.__v_raw || obj.valueOf() || obj);
+
+export default {
+	...echarts,
+	name: "scEcharts",
+	props: {
+		height: {type: String, default: "100%"},
+		width: {type: String, default: "100%"},
+		nodata: {type: Boolean, default: false},
+		option: {
+			type: Object, default: () => {
+			}
+		}
+	},
+	data() {
+		return {
+			isActivat: false,
+			myChart: null
+		}
+	},
+	watch: {
+		option: {
+			deep: true,
+			handler(v) {
+				unwarp(this.myChart).setOption(v);
+			}
+		}
+	},
+	computed: {
+		myOptions: function () {
+			return this.option || {};
+		}
+	},
+	activated() {
+		if (!this.isActivat) {
+			this.$nextTick(() => {
+				this.myChart.resize()
+			})
+		}
+	},
+	deactivated() {
+		this.isActivat = false;
+	},
+	mounted() {
+		this.isActivat = true;
+		this.$nextTick(() => {
+			this.draw();
+		})
+	},
+	methods: {
+		draw() {
+			let myChart = echarts.init(this.$refs.scEcharts, 'T');
+			myChart.setOption(this.myOptions);
+			this.myChart = myChart;
+			window.addEventListener('resize', () => myChart.resize());
+		}
+	}
+}
+</script>

+ 2 - 2
Web/src/router/index.ts

@@ -84,11 +84,11 @@ export function formatTwoStageRoutes(arr: any) {
 			// 路径:/@/layout/routerView/parent.vue
 			if (newArr[0].meta.isKeepAlive && v.meta.isKeepAlive) {
 				cacheList.push(v.name);
-				const stores = useKeepALiveNames(pinia);
-				stores.setCacheKeepAlive(cacheList);
 			}
 		}
 	});
+	const stores = useKeepALiveNames(pinia);
+	stores.setCacheKeepAlive(cacheList);
 	return newArr;
 }
 

+ 35 - 0
Web/src/views/home/test.vue

@@ -0,0 +1,35 @@
+<template>
+	<div v-if="pageLoading">
+		<el-main>
+			<el-card shadow="never">
+				<el-skeleton :rows="1"></el-skeleton>
+			</el-card>
+			<el-card shadow="never" style="margin-top: 15px">
+				<el-skeleton></el-skeleton>
+			</el-card>
+		</el-main>
+	</div>
+	<div v-else>
+		<widgets></widgets>
+	</div>
+</template>
+
+<script setup lang='ts' name='homepage'>
+import { defineAsyncComponent, onMounted, reactive } from 'vue';
+// import { useHomepage } from 'src/stores/homepage';
+const widgets = defineAsyncComponent(() => import('./widgets/index.vue'));
+// const homepageStore = useHomepage();
+
+const state = reactive({
+	name: 'dashboard',
+	pageLoading: true,
+	dashboard: '0',
+});
+
+onMounted(() => {
+	state.pageLoading = false;
+});
+</script>
+
+<style>
+</style>

+ 27 - 0
Web/src/views/home/widgets/components/about.vue

@@ -0,0 +1,27 @@
+<template>
+	<el-card shadow="hover" header="关于项目" class="item-background">
+		<p>高性能 / 精致 / 优雅。基于Vue3 + Element-Plus 的中后台前端解决方案,如果喜欢就点个星星支持一下。</p>
+		<p>
+			<a href='https://gitee.com/pi3b/Admin.NET.git' target="_blank">
+				<img src='https://gitee.com/pi3b/Admin.NET/badge/star.svg?theme=dark' alt='star' style="vertical-align: middle">
+			</a>
+		</p>
+	</el-card>
+</template>
+
+<script>
+	export default {
+		title: "关于项目",
+		icon: "el-icon-setting",
+		description: "点个星星支持一下",
+		data() {
+			return {
+				
+			}
+		}
+	}
+</script>
+
+<style scoped>
+	.item-background p {color: #999;margin-top:10px;line-height: 1.8;}
+</style>

+ 98 - 0
Web/src/views/home/widgets/components/echarts.vue

@@ -0,0 +1,98 @@
+<template>
+	<el-card shadow="hover" header="实时收入" v-loading="loading">
+		<scEcharts ref="c1" height="300px" :option="option"></scEcharts>
+	</el-card>
+</template>
+
+<script>
+	import scEcharts from '/@/components/scEcharts/index.vue';
+
+	export default {
+		title: "实时收入",
+		icon: "el-icon-data-line",
+		description: "Echarts组件演示",
+		components: {
+			scEcharts
+		},
+		data() {
+			return {
+				loading: true,
+				option: {}
+			}
+		},
+		created() {
+			var _this = this;
+			setTimeout(function() {
+				_this.loading = false
+			}, 500);
+
+			var option = {
+				tooltip: {
+					trigger: 'axis'
+				},
+				xAxis: {
+					boundaryGap: false,
+					type: 'category',
+					data: (function (){
+						var now = new Date();
+						var res = [];
+						var len = 30;
+						while (len--) {
+							res.unshift(now.toLocaleTimeString().replace(/^\D*/,''));
+							now = new Date(now - 2000);
+						}
+						return res;
+					})()
+				},
+				yAxis: [{
+					type: 'value',
+					name: '价格',
+					"splitLine": {
+						"show": false
+					}
+				}],
+				series: [
+					{
+						name: '收入',
+						type: 'line',
+						symbol: 'none',
+						lineStyle: {
+							width: 1,
+							color: '#409EFF'
+						},
+						areaStyle: {
+							opacity: 0.1,
+							color: '#79bbff'
+						},
+						data: (function (){
+							var res = [];
+							var len = 30;
+							while (len--) {
+								res.push(Math.round(Math.random() * 0));
+							}
+							return res;
+						})()
+					},
+				],
+			};
+			this.option = option;
+
+		},
+		mounted(){
+			 var _this = this;
+			setInterval(function (){
+				var o = _this.option;
+
+				o.series[0].data.shift()
+				o.series[0].data.push(Math.round(Math.random() * 100));
+
+				o.xAxis.data.shift();
+				o.xAxis.data.push((new Date()).toLocaleTimeString().replace(/^\D*/, ''));
+
+
+				//_this.$refs.c1.myChart.setOption(o)
+			},2100)
+
+		},
+	}
+</script>

+ 9 - 0
Web/src/views/home/widgets/components/index.js

@@ -0,0 +1,9 @@
+import {markRaw} from 'vue';
+const resultComps = {}
+let requireComponent = import.meta.glob('./*.vue',{eager: true})
+Object.keys(requireComponent).forEach(fileName => {
+	//replace(/(\.\/|\.js)/g, '')
+	resultComps[fileName.replace(/^\.\/(.*)\.\w+$/, '$1')] = requireComponent[fileName].default
+})
+export default markRaw(resultComps)
+

+ 208 - 0
Web/src/views/home/widgets/components/myapp.vue

@@ -0,0 +1,208 @@
+<template>
+	<el-card shadow="hover" header="快捷入口">
+		<ul class="myMods">
+			<!-- <li v-for="mod in myMods" :key="mod.path" :style="{ background:mod.meta.color||'#eeeeee'}"> -->
+			<li v-for="mod in myMods" :key="mod.path">
+				<a v-if="mod.meta.type == 'link'" :href="mod.path" target="_blank">
+					<el-icon><component :is="mod.meta.icon || el - icon - menu" /></el-icon>
+					<p>{{ mod.meta.title }}</p>
+				</a>
+				<router-link v-else :to="{ path: mod.path }">
+					<el-icon><component :is="mod.meta.icon || el - icon - menu" /></el-icon>
+					<p>{{ mod.meta.title }}</p>
+				</router-link>
+			</li>
+			<li class="modItem-add" @click="addMods">
+				<a href="javascript:void(0)">
+					<el-icon><el-icon-plus :style="{ color: '#fff' }" /></el-icon>
+				</a>
+			</li>
+		</ul>
+
+		<el-drawer title="添加应用" v-model="modsDrawer" :size="570" destroy-on-close>
+			<div class="setMods">
+				<h4>我的常用 ( {{ myMods.length }} )</h4>
+				<draggable tag="ul" v-model="myMods" animation="200" item-key="path" group="people">
+					<template #item="{ element }">
+						<li>
+							<el-icon><component :is="element.meta.icon || el - icon - menu" /></el-icon>
+							<p>{{ element.meta.title }}</p>
+						</li>
+					</template>
+				</draggable>
+			</div>
+			<div class="setMods">
+				<h4>全部应用 ( {{ filterMods.length }} )</h4>
+				<draggable tag="ul" v-model="filterMods" animation="200" item-key="path" :sort="false" group="people">
+					<template #item="{ element }">
+						<li :style="{ background: element.meta.color || '#909399' }">
+							<el-icon><component :is="element.meta.icon || el - icon - menu" /></el-icon>
+							<p>{{ element.meta.title }}</p>
+						</li>
+					</template>
+				</draggable>
+			</div>
+			<template #footer>
+				<el-button @click="modsDrawer = false">取消</el-button>
+				<el-button type="primary" @click="saveMods">保存</el-button>
+			</template>
+		</el-drawer>
+	</el-card>
+</template>
+
+<script>
+import draggable from 'vuedraggable';
+import tool from '../tool';
+import { useRequestOldRoutes } from '/@/stores/requestOldRoutes';
+export default {
+	title: '快捷入口',
+	icon: 'el-icon-monitor',
+	description: '可以配置的快捷入口',
+	components: {
+		draggable,
+	},
+	data() {
+		return {
+			mods: [],
+			myMods: [],
+			myModsName: [],
+			filterMods: [],
+			modsDrawer: false,
+		};
+	},
+	mounted() {
+		this.getMods();
+	},
+	methods: {
+		addMods() {
+			this.modsDrawer = true;
+		},
+		getMods() {
+			this.myModsName = tool.data.get('my-mods') || [];
+			var menuTree = useRequestOldRoutes().requestOldRoutes || [];
+			this.filterMenu(menuTree);
+			this.myMods = this.mods.filter((item) => {
+				return this.myModsName.includes(item.name);
+			});
+			this.filterMods = this.mods.filter((item) => {
+				return !this.myModsName.includes(item.name);
+			});
+		},
+		filterMenu(map) {
+			map.forEach((item) => {
+				if (item.meta.isHide || item.type == 3 || item.status != 1) {
+					return false;
+				}
+				if (item.meta.isIframe) {
+					item.path = `/i/${item.name}`;
+				}
+				if (item.children && item.children.length > 0) {
+					this.filterMenu(item.children);
+				} else {
+					this.mods.push(item);
+				}
+			});
+		},
+		saveMods() {
+			const myModsName = this.myMods.map((v) => v.name);
+			tool.data.set('my-mods', myModsName);
+			this.$message.success('设置常用成功');
+			this.modsDrawer = false;
+		},
+	},
+};
+</script>
+
+<style scoped lang='scss'>
+.myMods {
+	list-style: none;
+	margin: -10px;
+}
+.myMods li {
+	display: inline-block;
+	width: 100px;
+	height: 100px;
+	vertical-align: top;
+	transition: all 0.3s ease;
+	margin: 10px;
+	border-radius: 5px;
+	background: var(--el-color-primary);
+}
+.myMods li:hover {
+	opacity: 0.5;
+}
+.myMods li a {
+	width: 100%;
+	height: 100%;
+	padding: 10px;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+	text-align: center;
+	color: #fff;
+}
+.myMods li i {
+	font-size: 26px;
+	color: #fff;
+}
+.myMods li p {
+	font-size: 14px;
+	color: #fff;
+	margin-top: 10px;
+	width: 100%;
+	white-space: nowrap;
+	text-overflow: ellipsis;
+	overflow: hidden;
+}
+
+.modItem-add {
+	border: 1px dashed #ddd;
+	cursor: pointer;
+}
+.modItem-add i {
+	font-size: 30px;
+	color: #999 !important;
+}
+.modItem-add:hover,
+.modItem-add:hover i {
+	border-color: #409eff;
+	color: #409eff !important;
+}
+
+.setMods {
+	padding: 0 20px;
+}
+.setMods h4 {
+	font-size: 14px;
+	font-weight: normal;
+}
+.setMods ul {
+	margin: 20px -5px;
+	min-height: 90px;
+}
+.setMods li {
+	display: inline-block;
+	width: 80px;
+	height: 80px;
+	text-align: center;
+	margin: 5px;
+	color: #fff;
+	vertical-align: top;
+	padding: 4px;
+	padding-top: 15px;
+	cursor: move;
+	border-radius: 3px;
+	background: var(--el-color-primary);
+}
+.setMods li i {
+	font-size: 20px;
+}
+.setMods li p {
+	font-size: 12px;
+	margin-top: 10px;
+}
+.setMods li.sortable-ghost {
+	opacity: 0.3;
+}
+</style>

+ 32 - 0
Web/src/views/home/widgets/components/progress.vue

@@ -0,0 +1,32 @@
+<template>
+	<el-card shadow="hover" header="进度环">
+		<div class="progress">
+			<el-progress type="dashboard" :percentage="85.5" :width="160">
+				<template #default="{ percentage }">
+				    <div class="percentage-value">{{ percentage }}%</div>
+				    <div class="percentage-label">当前进度</div>
+				  </template>
+			</el-progress>
+		</div>
+
+	</el-card>
+</template>
+
+<script>
+	export default {
+		title: "进度环",
+		icon: "el-icon-odometer",
+		description: "进度环原子组件演示",
+		data() {
+			return {
+
+			}
+		}
+	}
+</script>
+
+<style scoped>
+	.progress {text-align: center;}
+	.progress .percentage-value {font-size: 28px;}
+	.progress .percentage-label {font-size: 12px;margin-top: 10px;}
+</style>

+ 50 - 0
Web/src/views/home/widgets/components/time.vue

@@ -0,0 +1,50 @@
+<template>
+	<el-card shadow="hover" header="时钟" class="item-background">
+		<div class="time">
+			<h2>{{ time }}</h2>
+			<p>{{ day }}</p>
+		</div>
+	</el-card>
+</template>
+
+<script>
+import tool from '../tool';
+export default {
+	title: '时钟',
+	icon: 'el-icon-clock',
+	description: '演示部件效果',
+	data() {
+		return {
+			time: '',
+			day: '',
+		};
+	},
+	mounted() {
+		this.showTime();
+		setInterval(() => {
+			this.showTime();
+		}, 1000);
+	},
+	methods: {
+		showTime() {
+			this.time = tool.dateFormat(new Date(), 'hh:mm:ss');
+			this.day = tool.dateFormat(new Date(), 'yyyy年MM月dd日');
+		},
+	},
+};
+</script>
+
+<style scoped>
+.item-background {
+	background: linear-gradient(to right, #8e54e9, #4776e6);
+	color: #fff;
+}
+.time h2 {
+	font-size: 40px;
+}
+.time p {
+	font-size: 14px;
+	margin-top: 13px;
+	opacity: 0.7;
+}
+</style>

+ 42 - 0
Web/src/views/home/widgets/components/ver.vue

@@ -0,0 +1,42 @@
+<template>
+	<el-card shadow="hover" header="版本信息">
+		<div style="height: 210px;text-align: center;">
+			<img src="/@/assets/img/ver.svg" style="height:140px" />
+			<h2 style="margin-top: 15px;">admin.net </h2>
+			<p style="margin-top: 5px;">最新版本 {{ ver }}</p>
+		</div>
+		<div style="margin-top: 20px;">
+			<el-button type="primary" plain round @click="golog">更新日志</el-button>
+			<el-button type="primary" plain round @click="gogit">gitee</el-button>
+		</div>
+	</el-card>
+</template>
+
+<script>
+// import demo from '@/api/model/demo.js'
+export default {
+	title: "版本信息",
+	icon: "el-icon-monitor",
+	description: "当前项目版本信息",
+	data() {
+		return {
+			ver: 'loading...'
+		}
+	},
+	mounted() {
+		this.getVer()
+	},
+	methods: {
+		async getVer() {
+			// const ver = await demo.ver.get()
+			this.ver = '11'
+		},
+		golog() {
+			window.open("https://gitee.com/pi3b/Admin.NET/issues")
+		},
+		gogit() {
+			window.open("https://gitee.com/pi3b/Admin.NET.git")
+		}
+	}
+}
+</script>

+ 103 - 0
Web/src/views/home/widgets/components/welcome.vue

@@ -0,0 +1,103 @@
+<template>
+	<el-card shadow="hover" header="欢迎">
+		<div class="welcome">
+			<div class="logo">
+				<img src="/@/assets/logo.png">
+				<h2>欢迎体验myhomepage</h2>
+			</div>
+			<div class="tips">
+				<div class="tips-item">
+					<div class="tips-item-icon"><el-icon><el-icon-menu /></el-icon></div>
+					<div class="tips-item-message">这里是项目控制台,你可以点击右上方的“自定义”按钮来添加移除或者移动部件。</div>
+				</div>
+				<div class="tips-item">
+					<div class="tips-item-icon"><el-icon><el-icon-promotion /></el-icon></div>
+					<div class="tips-item-message">在提高前端算力、减少带宽请求和代码执行力上多次优化,并且持续着。</div>
+				</div>
+				<div class="tips-item">
+					<div class="tips-item-icon"><el-icon><el-icon-milk-tea /></el-icon></div>
+					<div class="tips-item-message">项目目的:让前端工作更快乐</div>
+				</div>
+			</div>
+			<div class="actions">
+				<el-button type="primary" icon="el-icon-check" size="large" @click="godoc">文档</el-button>
+			</div>
+		</div>
+	</el-card>
+</template>
+
+<script>
+export default {
+	title: "欢迎",
+	icon: "el-icon-present",
+	description: "项目特色以及文档链接",
+	data() {
+		return {
+
+		}
+	},
+	methods: {
+		godoc() {
+			window.open("https://gitee.com/pi3b/Admin.NET.git")
+		}
+	}
+}
+</script>
+
+<style scoped>
+.welcome {}
+
+.welcome .logo {
+	text-align: center;
+}
+
+.welcome .logo img {
+	vertical-align: bottom;
+	width: 100px;
+	height: 100px;
+	margin-bottom: 20px;
+}
+
+.welcome .logo h2 {
+	font-size: 30px;
+	font-weight: normal;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+
+.tips {
+	margin-top: 20px;
+	padding: 0 40px;
+}
+
+.tips-item {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	padding: 7.5px 0;
+}
+
+.tips-item-icon {
+	width: 40px;
+	height: 40px;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	border-radius: 50%;
+	font-size: 18px;
+	margin-right: 20px;
+	color: var(--el-color-primary);
+	background: rgba(180, 180, 180, 0.1);
+}
+
+.tips-item-message {
+	flex: 1;
+	font-size: 14px;
+}
+
+.actions {
+	text-align: center;
+	margin: 40px 0 20px 0;
+}
+</style>

+ 451 - 0
Web/src/views/home/widgets/index.vue

@@ -0,0 +1,451 @@
+<template>
+	<div :class="['widgets-home', customizing ? 'customizing' : '']" ref="main">
+		<div class="widgets-content">
+			<div class="widgets-top">
+				<div class="widgets-top-title">控制台</div>
+				<div class="widgets-top-actions">
+					<el-button v-if="customizing" type="primary" icon="el-icon-check" round @click="save">完成</el-button>
+					<el-button v-else type="primary" icon="el-icon-edit" round @click="custom">自定义</el-button>
+				</div>
+			</div>
+			<div class="widgets" ref="widgets">
+				<div class="widgets-wrapper">
+					<div v-if="nowCompsList.length <= 0" class="no-widgets">
+						<el-empty image="img/no-widgets.svg" description="没有部件啦" :image-size="280"></el-empty>
+					</div>
+					<el-row :gutter="15">
+						<el-col v-for="(item, index) in grid.layout" v-bind:key="index" :md="item" :xs="24">
+							<draggable
+								v-model="grid.copmsList[index]"
+								animation="200"
+								handle=".customize-overlay"
+								group="people"
+								item-key="com"
+								dragClass="aaaaa"
+								force-fallback
+								fallbackOnBody
+								class="draggable-box"
+							>
+								<template #item="{ element }">
+									<div class="widgets-item">
+										<component :is="allComps[element]"></component>
+										<div v-if="customizing" class="customize-overlay">
+											<el-button class="close" type="danger" plain icon="el-icon-close" size="small" @click="remove(element)"></el-button>
+											<label
+												><el-icon><component :is="allComps[element].icon" /></el-icon>{{ allComps[element].title }}</label
+											>
+										</div>
+									</div>
+								</template>
+							</draggable>
+						</el-col>
+					</el-row>
+				</div>
+			</div>
+		</div>
+		<div v-if="customizing" class="widgets-aside">
+			<el-container>
+				<el-header>
+					<div class="widgets-aside-title">
+						<el-icon><el-icon-circle-plus-filled /></el-icon>添加部件
+					</div>
+					<div class="widgets-aside-close" @click="close()">
+						<el-icon><el-icon-close /></el-icon>
+					</div>
+				</el-header>
+				<el-header style="height: auto">
+					<div class="selectLayout">
+						<div class="selectLayout-item item01" :class="{ active: grid.layout.join(',') == '12,6,6' }" @click="setLayout([12, 6, 6])">
+							<el-row :gutter="2">
+								<el-col :span="12"><span></span></el-col>
+								<el-col :span="6"><span></span></el-col>
+								<el-col :span="6"><span></span></el-col>
+							</el-row>
+						</div>
+						<div class="selectLayout-item item02" :class="{ active: grid.layout.join(',') == '24,16,8' }" @click="setLayout([24, 16, 8])">
+							<el-row :gutter="2">
+								<el-col :span="24"><span></span></el-col>
+								<el-col :span="16"><span></span></el-col>
+								<el-col :span="8"><span></span></el-col>
+							</el-row>
+						</div>
+						<div class="selectLayout-item item03" :class="{ active: grid.layout.join(',') == '24' }" @click="setLayout([24])">
+							<el-row :gutter="2">
+								<el-col :span="24"><span></span></el-col>
+								<el-col :span="24"><span></span></el-col>
+								<el-col :span="24"><span></span></el-col>
+							</el-row>
+						</div>
+					</div>
+				</el-header>
+				<el-main class="nopadding">
+					<div class="widgets-list">
+						<div v-if="myCompsList.length <= 0" class="widgets-list-nodata">
+							<el-empty description="没有部件啦" :image-size="60"></el-empty>
+						</div>
+						<div v-for="item in myCompsList" :key="item.title" class="widgets-list-item">
+							<div class="item-logo">
+								<el-icon><component :is="item.icon" /></el-icon>
+							</div>
+							<div class="item-info">
+								<h2>{{ item.title }}</h2>
+								<p>{{ item.description }}</p>
+							</div>
+							<div class="item-actions">
+								<el-button type="primary" icon="el-icon-plus" size="small" @click="push(item)"></el-button>
+							</div>
+						</div>
+					</div>
+				</el-main>
+				<el-footer style="height: 51px">
+					<el-button size="small" @click="backDefaul()">恢复默认</el-button>
+				</el-footer>
+			</el-container>
+		</div>
+	</div>
+</template>
+
+<script>
+import { ConsoleLogger } from '@microsoft/signalr/dist/esm/Utils';
+import draggable from 'vuedraggable';
+import allComps from './components';
+import tool from './tool';
+export default {
+	components: {
+		draggable,
+	},
+	data() {
+		return {
+			customizing: false,
+			allComps: allComps,
+			selectLayout: [],
+			defaultGrid: {
+				//默认分栏数量和宽度 例如 [24] [18,6] [8,8,8] [6,12,6]
+				layout: [12, 6, 6],
+				//小组件分布,com取值:views/home/components 文件名
+				copmsList: [['welcome'], ['about', 'ver'], ['time', 'progress']],
+			},
+			grid: [],
+		};
+	},
+	created() {
+		this.grid = tool.data.get('grid') || JSON.parse(JSON.stringify(this.defaultGrid));
+	},
+	mounted() {
+		// this.$emit('on-mounted');
+	},
+	computed: {
+		allCompsList() {
+			var allCompsList = [];
+			for (var key in this.allComps) {
+				allCompsList.push({
+					key: key,
+					title: allComps[key].title,
+					icon: allComps[key].icon,
+					description: allComps[key].description,
+				});
+			}
+			var myCopmsList = this.grid.copmsList.reduce(function (a, b) {
+				return a.concat(b);
+			});
+			for (let comp of allCompsList) {
+				const _item = myCopmsList.find((item) => {
+					return item === comp.key;
+				});
+				if (_item) {
+					//如果界面有,则右边不可选
+					comp.disabled = true;
+				}
+			}
+			return allCompsList;
+		},
+		myCompsList() {
+			var myGrid = tool.data.get('DASHBOARDGRID');
+			if (!myGrid) myGrid = ['welcome', 'myapp', 'ver', 'time', 'progress', 'echarts', 'about'];
+			return this.allCompsList.filter((item) => !item.disabled && myGrid.includes(item.key));
+		},
+		nowCompsList() {
+			return this.grid.copmsList.reduce(function (a, b) {
+				return a.concat(b);
+			});
+		},
+	},
+	methods: {
+		//开启自定义
+		custom() {
+			this.customizing = true;
+			const oldWidth = this.$refs.widgets.offsetWidth;
+			this.$nextTick(() => {
+				const scale = this.$refs.widgets.offsetWidth / oldWidth;
+				this.$refs.widgets.style.setProperty('transform', `scale(${scale})`);
+			});
+		},
+		//设置布局
+		setLayout(layout) {
+			this.grid.layout = layout;
+			if (layout.join(',') == '24') {
+				this.grid.copmsList[0] = [...this.grid.copmsList[0], ...this.grid.copmsList[1], ...this.grid.copmsList[2]];
+				this.grid.copmsList[1] = [];
+				this.grid.copmsList[2] = [];
+			}
+		},
+		//追加
+		push(item) {
+			let target = this.grid.copmsList[0];
+			target.push(item.key);
+		},
+		//隐藏组件
+		remove(item) {
+			var newCopmsList = this.grid.copmsList;
+			newCopmsList.forEach((obj, index) => {
+				var newObj = obj.filter((o) => o != item);
+				newCopmsList[index] = newObj;
+			});
+		},
+		//保存
+		save() {
+			this.customizing = false;
+			this.$refs.widgets.style.removeProperty('transform');
+			tool.data.set('grid', this.grid);
+		},
+		//恢复默认
+		backDefaul() {
+			this.customizing = false;
+			this.$refs.widgets.style.removeProperty('transform');
+			this.grid = JSON.parse(JSON.stringify(this.defaultGrid));
+			tool.data.remove('grid');
+		},
+		//关闭
+		close() {
+			this.customizing = false;
+			this.$refs.widgets.style.removeProperty('transform');
+		},
+	},
+};
+</script>
+
+<style scoped lang="scss">
+.widgets-home {
+	display: flex;
+	flex-direction: row;
+	flex: 1;
+	height: 100%;
+}
+.widgets-content {
+	flex: 1;
+	overflow: auto;
+	overflow-x: hidden;
+	padding: 15px;
+}
+.widgets-aside {
+	width: 360px;
+	background: #fff;
+	box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+	position: relative;
+	overflow: auto;
+}
+.widgets-aside-title {
+	font-size: 14px;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+.widgets-aside-title i {
+	margin-right: 10px;
+	font-size: 18px;
+}
+.widgets-aside-close {
+	font-size: 18px;
+	width: 30px;
+	height: 30px;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	border-radius: 3px;
+	cursor: pointer;
+}
+.widgets-aside-close:hover {
+	background: rgba(180, 180, 180, 0.1);
+}
+
+.widgets-top {
+	margin-bottom: 15px;
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+}
+.widgets-top-title {
+	font-size: 18px;
+	font-weight: bold;
+}
+
+.widgets {
+	transform-origin: top left;
+	transition: transform 0.15s;
+}
+
+.draggable-box {
+	height: 100%;
+}
+
+.customizing .widgets-wrapper {
+	margin-right: -360px;
+}
+.customizing .widgets-wrapper .el-col {
+	padding-bottom: 15px;
+}
+.customizing .widgets-wrapper .draggable-box {
+	border: 1px dashed var(--el-color-primary);
+	padding: 15px;
+}
+.customizing .widgets-wrapper .no-widgets {
+	display: none;
+}
+.customizing .widgets-item {
+	position: relative;
+	margin-bottom: 15px;
+}
+.customize-overlay {
+	position: absolute;
+	top: 0;
+	right: 0;
+	bottom: 0;
+	left: 0;
+	z-index: 1;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+	background: rgba(255, 255, 255, 0.9);
+	cursor: move;
+}
+.customize-overlay label {
+	background: var(--el-color-primary);
+	color: #fff;
+	height: 40px;
+	padding: 0 30px;
+	border-radius: 40px;
+	font-size: 18px;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	cursor: move;
+}
+.customize-overlay label i {
+	margin-right: 15px;
+	font-size: 24px;
+}
+.customize-overlay .close {
+	position: absolute;
+	top: 15px;
+	right: 15px;
+}
+.customize-overlay .close:focus,
+.customize-overlay .close:hover {
+	background: var(--el-button-hover-color);
+}
+
+.widgets-list {
+}
+.widgets-list-item {
+	display: flex;
+	flex-direction: row;
+	padding: 15px;
+	align-items: center;
+}
+.widgets-list-item .item-logo {
+	width: 40px;
+	height: 40px;
+	border-radius: 50%;
+	background: rgba(180, 180, 180, 0.1);
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	font-size: 18px;
+	margin-right: 15px;
+	color: #6a8bad;
+}
+.widgets-list-item .item-info {
+	flex: 1;
+}
+.widgets-list-item .item-info h2 {
+	font-size: 16px;
+	font-weight: normal;
+	cursor: default;
+}
+.widgets-list-item .item-info p {
+	font-size: 12px;
+	color: #999;
+	cursor: default;
+}
+.widgets-list-item:hover {
+	background: rgba(180, 180, 180, 0.1);
+}
+
+.widgets-wrapper .sortable-ghost {
+	opacity: 0.5;
+}
+
+.selectLayout {
+	width: 100%;
+	display: flex;
+}
+.selectLayout-item {
+	width: 60px;
+	height: 60px;
+	border: 2px solid var(--el-border-color-light);
+	padding: 5px;
+	cursor: pointer;
+	margin-right: 15px;
+}
+.selectLayout-item span {
+	display: block;
+	background: var(--el-border-color-light);
+	height: 46px;
+}
+.selectLayout-item.item02 span {
+	height: 30px;
+}
+.selectLayout-item.item02 .el-col:nth-child(1) span {
+	height: 14px;
+	margin-bottom: 2px;
+}
+.selectLayout-item.item03 span {
+	height: 14px;
+	margin-bottom: 2px;
+}
+.selectLayout-item:hover {
+	border-color: var(--el-color-primary);
+}
+.selectLayout-item.active {
+	border-color: var(--el-color-primary);
+}
+.selectLayout-item.active span {
+	background: var(--el-color-primary);
+}
+
+.dark {
+	.widgets-aside {
+		background: #2b2b2b;
+	}
+	.customize-overlay {
+		background: rgba(43, 43, 43, 0.9);
+	}
+}
+
+@media (max-width: 992px) {
+	.customizing .widgets {
+		transform: scale(1) !important;
+	}
+	.customizing .widgets-aside {
+		width: 100%;
+		position: absolute;
+		top: 50%;
+		right: 0;
+		bottom: 0;
+	}
+	.customizing .widgets-wrapper {
+		margin-right: 0;
+	}
+}
+</style>

+ 224 - 0
Web/src/views/home/widgets/tool.js

@@ -0,0 +1,224 @@
+/*
+ * @Descripttion: 工具集
+ * @version: 1.2
+ * @LastEditors: sakuya
+ * @LastEditTime: 2022年5月24日00:28:56
+ */
+
+// import CryptoJS from 'crypto-js';
+
+const tool = {}
+
+/* localStorage */
+tool.data = {
+	set(key, data, datetime = 0) {
+        let cacheValue = {
+            content: data,
+            datetime: parseInt(datetime) === 0 ? 0 : new Date().getTime() + parseInt(datetime) * 1000
+        }
+        return localStorage.setItem(key, JSON.stringify(cacheValue))
+	},
+	get(key) {
+        try {
+            const value = JSON.parse(localStorage.getItem(key))
+            if (value) {
+                let nowTime = new Date().getTime()
+                if (nowTime > value.datetime && value.datetime != 0) {
+                    localStorage.removeItem(key)
+                    return null;
+                }
+                return value.content
+            }
+            return null
+        } catch (err) {
+            return null
+        }
+	},
+	remove(key) {
+		return localStorage.removeItem(key)
+	},
+	clear() {
+		return localStorage.clear()
+	}
+}
+
+/*sessionStorage*/
+tool.session = {
+	set(table, settings) {
+		var _set = JSON.stringify(settings)
+		return sessionStorage.setItem(table, _set);
+	},
+	get(table) {
+		var data = sessionStorage.getItem(table);
+		try {
+			data = JSON.parse(data)
+		} catch (err) {
+			return null
+		}
+		return data;
+	},
+	remove(table) {
+		return sessionStorage.removeItem(table);
+	},
+	clear() {
+		return sessionStorage.clear();
+	}
+}
+
+/*cookie*/
+tool.cookie = {
+	set(name, value, config={}) {
+		var cfg = {
+			expires: null,
+			path: null,
+			domain: null,
+			secure: false,
+			httpOnly: false,
+			...config
+		}
+		var cookieStr = `${name}=${escape(value)}`
+		if(cfg.expires){
+			var exp = new Date()
+			exp.setTime(exp.getTime() + parseInt(cfg.expires) * 1000)
+			cookieStr += `;expires=${exp.toGMTString()}`
+		}
+		if(cfg.path){
+			cookieStr += `;path=${cfg.path}`
+		}
+		if(cfg.domain){
+			cookieStr += `;domain=${cfg.domain}`
+		}
+		document.cookie = cookieStr
+	},
+	get(name){
+		var arr = document.cookie.match(new RegExp("(^| )"+name+"=([^;]*)(;|$)"))
+		if(arr != null){
+			return unescape(arr[2])
+		}else{
+			return null
+		}
+	},
+	remove(name){
+		var exp = new Date()
+		exp.setTime(exp.getTime() - 1)
+		document.cookie = `${name}=;expires=${exp.toGMTString()}`
+	}
+}
+
+/* Fullscreen */
+tool.screen = function (element) {
+	var isFull = !!(document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement || document.fullscreenElement);
+	if(isFull){
+		if(document.exitFullscreen) {
+			document.exitFullscreen();
+		}else if (document.msExitFullscreen) {
+			document.msExitFullscreen();
+		}else if (document.mozCancelFullScreen) {
+			document.mozCancelFullScreen();
+		}else if (document.webkitExitFullscreen) {
+			document.webkitExitFullscreen();
+		}
+	}else{
+		if(element.requestFullscreen) {
+			element.requestFullscreen();
+		}else if(element.msRequestFullscreen) {
+			element.msRequestFullscreen();
+		}else if(element.mozRequestFullScreen) {
+			element.mozRequestFullScreen();
+		}else if(element.webkitRequestFullscreen) {
+			element.webkitRequestFullscreen();
+		}
+	}
+}
+
+/* 复制对象 */
+tool.objCopy = function (obj) {
+	return JSON.parse(JSON.stringify(obj));
+}
+
+/* 日期格式化 */
+tool.dateFormat = function (date, fmt='yyyy-MM-dd hh:mm:ss') {
+	date = new Date(date)
+	var o = {
+		"M+" : date.getMonth()+1,                 //月份
+		"d+" : date.getDate(),                    //日
+		"h+" : date.getHours(),                   //小时
+		"m+" : date.getMinutes(),                 //分
+		"s+" : date.getSeconds(),                 //秒
+		"q+" : Math.floor((date.getMonth()+3)/3), //季度
+		"S"  : date.getMilliseconds()             //毫秒
+	};
+	if(/(y+)/.test(fmt)) {
+		fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length));
+	}
+	for(var k in o) {
+		if(new RegExp("("+ k +")").test(fmt)){
+			fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
+		}
+	}
+	return fmt;
+}
+
+/* 千分符 */
+tool.groupSeparator = function (num) {
+	num = num + '';
+	if(!num.includes('.')){
+		num += '.'
+	}
+	return num.replace(/(\d)(?=(\d{3})+\.)/g, function ($0, $1) {
+		return $1 + ',';
+	}).replace(/\.$/, '');
+}
+
+// /* 常用加解密 */
+// tool.crypto = {
+// 	//MD5加密
+// 	MD5(data){
+// 		return CryptoJS.MD5(data).toString()
+// 	},
+// 	//BASE64加解密
+// 	BASE64: {
+// 		encrypt(data){
+// 			return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data))
+// 		},
+// 		decrypt(cipher){
+// 			return CryptoJS.enc.Base64.parse(cipher).toString(CryptoJS.enc.Utf8)
+// 		}
+// 	},
+// 	//AES加解密
+// 	AES: {
+// 		encrypt(data, secretKey, config={}){
+// 			if(secretKey.length % 8 != 0){
+// 				console.warn("[SCUI error]: 秘钥长度需为8的倍数,否则解密将会失败。")
+// 			}
+// 			const result = CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(secretKey), {
+// 				iv: CryptoJS.enc.Utf8.parse(config.iv || ""),
+// 				mode: CryptoJS.mode[config.mode || "ECB"],
+// 				padding: CryptoJS.pad[config.padding || "Pkcs7"]
+// 			})
+// 			return result.toString()
+// 		},
+// 		decrypt(cipher, secretKey, config={}){
+// 			const result = CryptoJS.AES.decrypt(cipher, CryptoJS.enc.Utf8.parse(secretKey), {
+// 				iv: CryptoJS.enc.Utf8.parse(config.iv || ""),
+// 				mode: CryptoJS.mode[config.mode || "ECB"],
+// 				padding: CryptoJS.pad[config.padding || "Pkcs7"]
+// 			})
+// 			return CryptoJS.enc.Utf8.stringify(result);
+// 		}
+// 	}
+// }
+
+// 查找树
+tool.treeFind = (tree, func) => {
+	for (const data of tree) {
+		if (func(data)) return data
+		if (data.children) {
+			const res = tool.treeFind(data.children, func)
+			if (res) return res
+		}
+	}
+	return null
+}
+
+export default tool