Browse Source

feat: 添加基础功能

Gaokun Wang 1 week ago
parent
commit
2751d829e0

+ 63 - 23
package-lock.json

@@ -17,12 +17,14 @@
         "@tailwindcss/vite": "^4.1.10",
         "@tailwindcss/vite": "^4.1.10",
         "@vueuse/core": "^13.3.0",
         "@vueuse/core": "^13.3.0",
         "@zklogic/draw.io": "^15.7.2-rc1",
         "@zklogic/draw.io": "^15.7.2-rc1",
+        "axios": "^1.11.0",
         "electron-updater": "^6.6.2",
         "electron-updater": "^6.6.2",
         "element-plus": "^2.10.4",
         "element-plus": "^2.10.4",
         "insert-css": "^2.0.0",
         "insert-css": "^2.0.0",
         "nprogress": "^0.2.0",
         "nprogress": "^0.2.0",
         "pinia": "^3.0.3",
         "pinia": "^3.0.3",
         "tailwindcss": "^4.1.10",
         "tailwindcss": "^4.1.10",
+        "uuid": "^11.1.0",
         "vue-router": "^4.5.1"
         "vue-router": "^4.5.1"
       },
       },
       "devDependencies": {
       "devDependencies": {
@@ -32,6 +34,7 @@
         "@typed-mxgraph/typed-mxgraph": "^1.0.8",
         "@typed-mxgraph/typed-mxgraph": "^1.0.8",
         "@types/insert-css": "^2.0.3",
         "@types/insert-css": "^2.0.3",
         "@types/node": "^22.14.1",
         "@types/node": "^22.14.1",
+        "@types/uuid": "^10.0.0",
         "@vitejs/plugin-vue": "^5.2.3",
         "@vitejs/plugin-vue": "^5.2.3",
         "electron": "^35.1.5",
         "electron": "^35.1.5",
         "electron-builder": "^25.1.8",
         "electron-builder": "^25.1.8",
@@ -2059,6 +2062,13 @@
         "@types/node": "*"
         "@types/node": "*"
       }
       }
     },
     },
+    "node_modules/@types/uuid": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmmirror.com/@types/uuid/-/uuid-10.0.0.tgz",
+      "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/@types/web-bluetooth": {
     "node_modules/@types/web-bluetooth": {
       "version": "0.0.21",
       "version": "0.0.21",
       "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
       "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
@@ -3021,7 +3031,6 @@
       "version": "0.4.0",
       "version": "0.4.0",
       "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
       "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
       "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
       "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
-      "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
     "node_modules/at-least-node": {
     "node_modules/at-least-node": {
@@ -3034,6 +3043,17 @@
         "node": ">= 4.0.0"
         "node": ">= 4.0.0"
       }
       }
     },
     },
+    "node_modules/axios": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmmirror.com/axios/-/axios-1.11.0.tgz",
+      "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.15.6",
+        "form-data": "^4.0.4",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
     "node_modules/balanced-match": {
     "node_modules/balanced-match": {
       "version": "1.0.2",
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
       "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -3424,7 +3444,6 @@
       "version": "1.0.2",
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
       "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
       "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
       "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "es-errors": "^1.3.0",
         "es-errors": "^1.3.0",
@@ -3745,7 +3764,6 @@
       "version": "1.0.8",
       "version": "1.0.8",
       "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
       "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
       "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
       "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "delayed-stream": "~1.0.0"
         "delayed-stream": "~1.0.0"
@@ -4083,7 +4101,6 @@
       "version": "1.0.0",
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
       "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
       "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
       "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
         "node": ">=0.4.0"
         "node": ">=0.4.0"
@@ -4236,7 +4253,6 @@
       "version": "1.0.1",
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz",
       "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz",
       "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
       "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "call-bind-apply-helpers": "^1.0.1",
         "call-bind-apply-helpers": "^1.0.1",
@@ -4785,7 +4801,6 @@
       "version": "1.0.1",
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
       "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
       "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
       "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
-      "devOptional": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
         "node": ">= 0.4"
         "node": ">= 0.4"
@@ -4795,7 +4810,6 @@
       "version": "1.3.0",
       "version": "1.3.0",
       "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
       "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
       "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
       "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
-      "devOptional": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
         "node": ">= 0.4"
         "node": ">= 0.4"
@@ -4805,7 +4819,6 @@
       "version": "1.1.1",
       "version": "1.1.1",
       "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
       "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
       "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
       "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "es-errors": "^1.3.0"
         "es-errors": "^1.3.0"
@@ -4818,7 +4831,6 @@
       "version": "2.1.0",
       "version": "2.1.0",
       "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
       "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
       "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
       "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "es-errors": "^1.3.0",
         "es-errors": "^1.3.0",
@@ -5378,6 +5390,26 @@
       "dev": true,
       "dev": true,
       "license": "ISC"
       "license": "ISC"
     },
     },
+    "node_modules/follow-redirects": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz",
+      "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/foreground-child": {
     "node_modules/foreground-child": {
       "version": "3.3.1",
       "version": "3.3.1",
       "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz",
       "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz",
@@ -5409,10 +5441,9 @@
       }
       }
     },
     },
     "node_modules/form-data": {
     "node_modules/form-data": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.3.tgz",
-      "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
-      "dev": true,
+      "version": "4.0.4",
+      "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz",
+      "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "asynckit": "^0.4.0",
         "asynckit": "^0.4.0",
@@ -5485,7 +5516,6 @@
       "version": "1.1.2",
       "version": "1.1.2",
       "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
       "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
       "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
       "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "funding": {
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
         "url": "https://github.com/sponsors/ljharb"
@@ -5549,7 +5579,6 @@
       "version": "1.3.0",
       "version": "1.3.0",
       "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
       "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
       "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
       "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "call-bind-apply-helpers": "^1.0.2",
         "call-bind-apply-helpers": "^1.0.2",
@@ -5574,7 +5603,6 @@
       "version": "1.0.1",
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz",
       "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz",
       "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
       "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "dunder-proto": "^1.0.1",
         "dunder-proto": "^1.0.1",
@@ -5723,7 +5751,6 @@
       "version": "1.2.0",
       "version": "1.2.0",
       "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz",
       "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz",
       "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
       "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
-      "devOptional": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
         "node": ">= 0.4"
         "node": ">= 0.4"
@@ -5797,7 +5824,6 @@
       "version": "1.1.0",
       "version": "1.1.0",
       "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz",
       "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz",
       "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
       "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
         "node": ">= 0.4"
         "node": ">= 0.4"
@@ -5810,7 +5836,6 @@
       "version": "1.0.2",
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
       "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
       "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
       "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "has-symbols": "^1.0.3"
         "has-symbols": "^1.0.3"
@@ -5833,7 +5858,6 @@
       "version": "2.0.2",
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
       "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
       "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
       "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "function-bind": "^1.1.2"
         "function-bind": "^1.1.2"
@@ -7332,7 +7356,6 @@
       "version": "1.1.0",
       "version": "1.1.0",
       "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
       "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
       "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
       "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
         "node": ">= 0.4"
         "node": ">= 0.4"
@@ -7385,7 +7408,6 @@
       "version": "1.52.0",
       "version": "1.52.0",
       "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
       "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
       "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
       "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
         "node": ">= 0.6"
         "node": ">= 0.6"
@@ -7395,7 +7417,6 @@
       "version": "2.1.35",
       "version": "2.1.35",
       "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
       "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
       "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
       "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "mime-db": "1.52.0"
         "mime-db": "1.52.0"
@@ -8358,6 +8379,12 @@
         "node": ">=10"
         "node": ">=10"
       }
       }
     },
     },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+      "license": "MIT"
+    },
     "node_modules/pump": {
     "node_modules/pump": {
       "version": "3.0.2",
       "version": "3.0.2",
       "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.2.tgz",
       "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.2.tgz",
@@ -10180,6 +10207,19 @@
         "node": ">= 4"
         "node": ">= 4"
       }
       }
     },
     },
+    "node_modules/uuid": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmmirror.com/uuid/-/uuid-11.1.0.tgz",
+      "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "license": "MIT",
+      "bin": {
+        "uuid": "dist/esm/bin/uuid"
+      }
+    },
     "node_modules/varint": {
     "node_modules/varint": {
       "version": "6.0.0",
       "version": "6.0.0",
       "resolved": "https://registry.npmmirror.com/varint/-/varint-6.0.0.tgz",
       "resolved": "https://registry.npmmirror.com/varint/-/varint-6.0.0.tgz",

+ 3 - 0
package.json

@@ -29,12 +29,14 @@
     "@tailwindcss/vite": "^4.1.10",
     "@tailwindcss/vite": "^4.1.10",
     "@vueuse/core": "^13.3.0",
     "@vueuse/core": "^13.3.0",
     "@zklogic/draw.io": "^15.7.2-rc1",
     "@zklogic/draw.io": "^15.7.2-rc1",
+    "axios": "^1.11.0",
     "electron-updater": "^6.6.2",
     "electron-updater": "^6.6.2",
     "element-plus": "^2.10.4",
     "element-plus": "^2.10.4",
     "insert-css": "^2.0.0",
     "insert-css": "^2.0.0",
     "nprogress": "^0.2.0",
     "nprogress": "^0.2.0",
     "pinia": "^3.0.3",
     "pinia": "^3.0.3",
     "tailwindcss": "^4.1.10",
     "tailwindcss": "^4.1.10",
+    "uuid": "^11.1.0",
     "vue-router": "^4.5.1"
     "vue-router": "^4.5.1"
   },
   },
   "devDependencies": {
   "devDependencies": {
@@ -44,6 +46,7 @@
     "@typed-mxgraph/typed-mxgraph": "^1.0.8",
     "@typed-mxgraph/typed-mxgraph": "^1.0.8",
     "@types/insert-css": "^2.0.3",
     "@types/insert-css": "^2.0.3",
     "@types/node": "^22.14.1",
     "@types/node": "^22.14.1",
+    "@types/uuid": "^10.0.0",
     "@vitejs/plugin-vue": "^5.2.3",
     "@vitejs/plugin-vue": "^5.2.3",
     "electron": "^35.1.5",
     "electron": "^35.1.5",
     "electron-builder": "^25.1.8",
     "electron-builder": "^25.1.8",

+ 24 - 0
src/api/interface/config.ts

@@ -0,0 +1,24 @@
+/**
+ * 查询参数
+ */
+export interface ConfigQuery extends PageQuery {
+  name?: string
+}
+
+/**
+ * 接收后端返回信息
+ */
+export interface ConfigVO extends BaseEntity {
+  id: string
+  name: string
+  type: string
+}
+
+/**
+ * 传入后端的表单信息
+ */
+export interface ConfigBO {
+  id: string
+  name: string
+  type: string
+}

+ 36 - 0
src/api/module/config.ts

@@ -0,0 +1,36 @@
+import http from '@/axios'
+import { ConfigBO, ConfigQuery, ConfigVO } from '@/api/interface/config'
+
+class ConfigApi {
+  /**
+   * @name 查询分页
+   * @returns returns
+   */
+  static page = (params: ConfigQuery): Promise<ResultData<any>> => {
+    return http.get<ConfigVO>({ url: '/system/config/page', params })
+  }
+
+  /**
+   * @name 添加
+   * @returns returns
+   */
+  static add = (data: ConfigBO): Promise<ResultData<any>> => {
+    return http.post({ url: '/system/config/add', data })
+  }
+  /**
+   * @name 更新
+   * @returns returns
+   */
+  static edit = (data: ConfigBO): Promise<ResultData<any>> => {
+    return http.put({ url: '/system/config/edit', data })
+  }
+
+  /**
+   * @name 删除
+   * @returns returns
+   */
+  static delete = (data: string[]): Promise<ResultData<any>> => {
+    return http.delete({ url: '/system/config/delete', data })
+  }
+}
+export default ConfigApi

+ 43 - 0
src/axios/checkStatus.ts

@@ -0,0 +1,43 @@
+import { ElMessage } from 'element-plus'
+
+/**
+ * @description: 校验网络请求状态码
+ * @param {Number} status
+ * @return void
+ */
+export const checkStatus = (status: number) => {
+  switch (status) {
+    case 400:
+      ElMessage.error({ message: '请求失败!请您稍后重试', duration: 500 })
+      break
+    case 401:
+      ElMessage.error({ message: '登录失效!请您重新登录', duration: 500 })
+      break
+    case 403:
+      ElMessage.error({ message: '当前账号无权限访问!', duration: 500 })
+      break
+    case 404:
+      ElMessage.error({ message: '你所访问的资源不存在!', duration: 500 })
+      break
+    case 405:
+      ElMessage.error({ message: '请求方式错误!请您稍后重试', duration: 500 })
+      break
+    case 408:
+      ElMessage.error({ message: '请求超时!请您稍后重试', duration: 500 })
+      break
+    case 500:
+      ElMessage.error({ message: '服务异常!', duration: 500 })
+      break
+    case 502:
+      ElMessage.error({ message: '网关错误!', duration: 500 })
+      break
+    case 503:
+      ElMessage.error({ message: '服务不可用!', duration: 500 })
+      break
+    case 504:
+      ElMessage.error({ message: '网关超时!', duration: 500 })
+      break
+    default:
+      ElMessage.error({ message: '请求失败!', duration: 500 })
+  }
+}

+ 24 - 0
src/axios/config.ts

@@ -0,0 +1,24 @@
+import type { InternalAxiosRequestConfig, AxiosResponse } from 'axios'
+import { ResultEnum } from '@/enums/HttpEnum'
+import { ElMessage } from 'element-plus'
+const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
+  if (config.headers && typeof config.headers.set === 'function') {
+  }
+  return config
+}
+
+const defaultResponseInterceptors = (response: AxiosResponse) => {
+  const { code, msg } = response.data
+
+  if (response?.config?.responseType === 'blob') {
+    // 如果是文件流,直接过
+    return response
+  } else if (code === ResultEnum.SUCCESS) {
+    return response.data
+  } else {
+    console.error(msg)
+    ElMessage.error(msg)
+  }
+}
+
+export { defaultResponseInterceptors, defaultRequestInterceptors }

+ 36 - 0
src/axios/index.ts

@@ -0,0 +1,36 @@
+import service from './service'
+
+const request = (option: AxiosConfig) => {
+  const { url, method, params, data, headers, responseType } = option
+  return service.request({
+    url: url,
+    method,
+    params,
+    data: data,
+    responseType: responseType,
+    headers: {
+      ...headers
+    }
+  })
+}
+
+export default {
+  get: <T = any>(option: AxiosConfig) => {
+    return request({ method: 'get', ...option }) as Promise<ResultData<T>>
+  },
+  post: <T = any>(option: AxiosConfig) => {
+    return request({ method: 'post', ...option }) as Promise<ResultData<T>>
+  },
+  delete: <T = any>(option: AxiosConfig) => {
+    return request({ method: 'delete', ...option }) as Promise<ResultData<T>>
+  },
+  put: <T = any>(option: AxiosConfig) => {
+    return request({ method: 'put', ...option }) as Promise<ResultData<T>>
+  },
+  cancelRequest: (url: string | string[]) => {
+    return service.cancelRequest(url)
+  },
+  cancelAllRequest: () => {
+    return service.cancelAllRequest()
+  }
+}

+ 106 - 0
src/axios/service.ts

@@ -0,0 +1,106 @@
+import axios, {
+  AxiosError,
+  type AxiosInstance,
+  type AxiosRequestConfig,
+  type AxiosResponse,
+  type InternalAxiosRequestConfig
+} from 'axios'
+import { ResultEnum } from '@/enums/HttpEnum'
+import { defaultRequestInterceptors, defaultResponseInterceptors } from './config'
+import { checkStatus } from './checkStatus'
+import router from '@/router'
+import { ElMessage } from 'element-plus'
+interface RequestInterceptors<T> {
+  // 请求拦截
+  requestInterceptors?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig
+  requestInterceptorsCatch?: (err: any) => any
+  // 响应拦截
+  responseInterceptors?: (config: T) => T
+  responseInterceptorsCatch?: (err: any) => any
+}
+
+interface RequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
+  interceptors?: RequestInterceptors<T>
+}
+
+export const BASE_URL = import.meta.env.VITE_API_PREFIX_PATH
+
+const abortControllerMap: Map<string, AbortController> = new Map()
+
+const config = {
+  // 默认地址请求地址,可在 .env.** 文件中修改
+  baseURL: BASE_URL as string,
+  // 设置超时时间
+  timeout: ResultEnum.TIMEOUT as number,
+  // 跨域时候允许携带凭证
+  withCredentials: true
+}
+// instantiation
+const axiosInstance: AxiosInstance = axios.create(config)
+
+axiosInstance.interceptors.request.use((res: InternalAxiosRequestConfig) => {
+  const controller = new AbortController()
+  const url = res.url || ''
+  res.signal = controller.signal
+  abortControllerMap.set(url, controller)
+  return res
+})
+
+axiosInstance.interceptors.response.use(
+  (res: AxiosResponse) => {
+    const url = res.config.url || ''
+
+    abortControllerMap.delete(url)
+    return res
+  },
+  (error: AxiosError) => {
+    const { response } = error
+    // 请求超时 && 网络错误单独判断,没有 response
+    if (error.message.indexOf('timeout') !== -1) ElMessage.error('请求超时!请您稍后重试')
+    if (error.message.indexOf('Network Error') !== -1) ElMessage.error('网络错误!请您稍后重试')
+    // 根据服务器响应的错误状态码,做不同的处理
+    if (response) checkStatus(response.status)
+    // 服务器结果都没有返回(可能服务器错误可能客户端断网),断网处理:可以跳转到断网页面
+    if (!window.navigator.onLine) router.replace('/500')
+    return Promise.reject(error)
+  }
+)
+// 默认请求/响应 处理
+axiosInstance.interceptors.request.use(defaultRequestInterceptors)
+axiosInstance.interceptors.response.use(defaultResponseInterceptors)
+
+const service = {
+  request: (config: RequestConfig) => {
+    return new Promise((resolve, reject) => {
+      if (config.interceptors?.requestInterceptors) {
+        config = config.interceptors.requestInterceptors(config as any)
+      }
+      axiosInstance
+        .request(config)
+        .then(res => {
+          resolve(res)
+        })
+        .catch((err: any) => {
+          reject(err)
+        })
+    })
+  },
+
+  // 取消请求
+  cancelRequest: (url: string | string[]) => {
+    const urlList = Array.isArray(url) ? url : [url]
+    for (const _url of urlList) {
+      abortControllerMap.get(_url)?.abort()
+      abortControllerMap.delete(_url)
+    }
+  },
+
+  // 取消所有请求
+  cancelAllRequest() {
+    for (const [_, controller] of abortControllerMap) {
+      controller.abort()
+    }
+    abortControllerMap.clear()
+  }
+}
+export default service

+ 22 - 0
src/constants/index.ts

@@ -0,0 +1,22 @@
+/**
+ * 不重置路由白名单
+ */
+export const NO_RESET_WHITE_LIST = ['Redirect']
+
+/**
+ * 白名单
+ */
+export const WHITE_LIST = ['/login']
+
+// 登录页地址(默认)
+export const LOGIN_URL: string = '/login'
+
+// 首页地址(默认)
+export const HOME_URL: string = '/home'
+
+// 默认设置
+export const DEFAULT_SETTING = {
+  PRIMARY: '#009688',
+  SHOW_TAPS: true,
+  TAPS_VIEW_ICON: true
+}

+ 43 - 0
src/enums/HttpEnum.ts

@@ -0,0 +1,43 @@
+/**
+ * @description:请求配置
+ */
+export enum ResultEnum {
+  SUCCESS = 200,
+  ERROR = 500,
+  OVERDUE = 401,
+  FORBIDDEN = 403,
+  TIMEOUT = 30000,
+  TYPE = 'success'
+}
+
+/**
+ * @description:请求方法
+ */
+export enum RequestEnum {
+  GET = 'GET',
+  POST = 'POST',
+  PATCH = 'PATCH',
+  PUT = 'PUT',
+  DELETE = 'DELETE'
+}
+
+/**
+ * @description:mock 响应
+ */
+export enum ResponseEnum {
+  TIMEOUT = 10
+}
+
+/**
+ * @description:常用的 contentTyp 类型
+ */
+export enum ContentTypeEnum {
+  // json
+  JSON = 'application/json;charset=UTF-8',
+  // text
+  TEXT = 'text/plain;charset=UTF-8',
+  // form-data 一般配合qs
+  FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
+  // form-data 上传
+  FORM_DATA = 'multipart/form-data;charset=UTF-8'
+}

+ 19 - 0
src/enums/LayoutTypeEnum.ts

@@ -0,0 +1,19 @@
+/**
+ * 菜单布局枚举
+ */
+export const enum LayoutTypeEnum {
+  /**
+   * 经典模式
+   */
+  CLASSIC = 'classic',
+
+  /**
+   * 混合模式
+   */
+  MIX = 'mix',
+
+  /**
+   * 横向模式
+   */
+  TRANSVERSE = 'transverse'
+}

+ 15 - 0
src/enums/MenuTypeEnum.ts

@@ -0,0 +1,15 @@
+export enum MenuTypeEnum {
+  /**
+   * 目录
+   */
+  C = 'C',
+  /**
+   * 菜单
+   */
+  M = 'M',
+
+  /**
+   * 外链
+   */
+  L = 'L'
+}

+ 1 - 0
src/layouts/index.scss

@@ -7,6 +7,7 @@
   height: 55px;
   height: 55px;
   background: linear-gradient(135deg, var(--ev-c-primary), var(--ev-c-dark));
   background: linear-gradient(135deg, var(--ev-c-primary), var(--ev-c-dark));
   display: flex;
   display: flex;
+  justify-content: space-between;
   align-items: center;
   align-items: center;
 }
 }
 .el-main {
 .el-main {

+ 10 - 2
src/layouts/index.vue

@@ -1,8 +1,13 @@
 <template>
 <template>
   <el-container class="layout">
   <el-container class="layout">
     <el-header>
     <el-header>
-      <el-button color="#626aef" @click="handleClickMenu('/')">测试用例</el-button>
-      <el-button color="#626aef" @click="handleClickMenu('/flow')">用例设计</el-button>
+      <div>
+        <el-button color="#626aef" @click="handleClickMenu('/')">测试用例</el-button>
+        <el-button color="#626aef" @click="handleClickMenu('/flow')">用例设计</el-button>
+      </div>
+      <div>
+        <el-button @click="reload">刷新</el-button>
+      </div>
     </el-header>
     </el-header>
     <el-main>
     <el-main>
       <router-view />
       <router-view />
@@ -20,6 +25,9 @@ const version = ref('v1.0.0')
 const handleClickMenu = (path: string) => {
 const handleClickMenu = (path: string) => {
   router.push(path)
   router.push(path)
 }
 }
+const reload = () => {
+  location.reload()
+}
 </script>
 </script>
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 @use './index';
 @use './index';

+ 3 - 0
src/types/auto-components.d.ts

@@ -8,6 +8,7 @@ export {}
 /* prettier-ignore */
 /* prettier-ignore */
 declare module 'vue' {
 declare module 'vue' {
   export interface GlobalComponents {
   export interface GlobalComponents {
+    Components: typeof import('./../views/test/components/index.vue')['default']
     ConfigEdge: typeof import('./../views/components/ConfigPanel/ConfigEdge/index.vue')['default']
     ConfigEdge: typeof import('./../views/components/ConfigPanel/ConfigEdge/index.vue')['default']
     ConfigGrid: typeof import('./../views/components/ConfigPanel/ConfigGrid/index.vue')['default']
     ConfigGrid: typeof import('./../views/components/ConfigPanel/ConfigGrid/index.vue')['default']
     ConfigNode: typeof import('./../views/components/ConfigPanel/ConfigNode/index.vue')['default']
     ConfigNode: typeof import('./../views/components/ConfigPanel/ConfigNode/index.vue')['default']
@@ -17,11 +18,13 @@ declare module 'vue' {
     ElCol: typeof import('element-plus/es')['ElCol']
     ElCol: typeof import('element-plus/es')['ElCol']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElContainer: typeof import('element-plus/es')['ElContainer']
     ElContainer: typeof import('element-plus/es')['ElContainer']
+    ElDialog: typeof import('element-plus/es')['ElDialog']
     ElFooter: typeof import('element-plus/es')['ElFooter']
     ElFooter: typeof import('element-plus/es')['ElFooter']
     ElForm: typeof import('element-plus/es')['ElForm']
     ElForm: typeof import('element-plus/es')['ElForm']
     ElFormItem: typeof import('element-plus/es')['ElFormItem']
     ElFormItem: typeof import('element-plus/es')['ElFormItem']
     ElHeader: typeof import('element-plus/es')['ElHeader']
     ElHeader: typeof import('element-plus/es')['ElHeader']
     ElInput: typeof import('element-plus/es')['ElInput']
     ElInput: typeof import('element-plus/es')['ElInput']
+    ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
     ElMain: typeof import('element-plus/es')['ElMain']
     ElMain: typeof import('element-plus/es')['ElMain']
     ElOption: typeof import('element-plus/es')['ElOption']
     ElOption: typeof import('element-plus/es')['ElOption']
     ElPagination: typeof import('element-plus/es')['ElPagination']
     ElPagination: typeof import('element-plus/es')['ElPagination']

+ 13 - 0
src/types/env.d.ts

@@ -1 +1,14 @@
 /// <reference types="vite/client" />
 /// <reference types="vite/client" />
+
+declare module '*.vue' {
+  import { DefineComponent } from 'vue'
+
+  const component: DefineComponent<object, object, any>
+  export default component
+}
+
+declare global {
+  interface ImportMeta {
+    readonly env: ImportMetaEnv
+  }
+}

+ 104 - 0
src/types/global.d.ts

@@ -0,0 +1,104 @@
+declare interface ImportMetaEnv {
+  VITE_PROXY: ProxyList | undefined
+  readonly VITE_APP_TITLE: string
+  readonly VITE_NODE_ENV: 'development' | 'production'
+  readonly VITE_ROUTER_MODE: 'hash' | 'history'
+  readonly VITE_PORT: number
+  readonly VITE_OPEN: boolean
+  readonly VITE_USE_MOCK: boolean
+  readonly VITE_API_PREFIX_PATH: string
+  readonly VITE_MOCK_API_PREFIX_PATH: string
+}
+
+declare type Recordable<T = any> = Record<string, T>
+declare type LayoutType = 'classic' | 'transverse'
+declare interface AxiosConfig {
+  params?: any
+  data?: any
+  url?: string
+  method?: AxiosMethod
+  headers?: RawAxiosRequestHeaders
+  responseType?: AxiosResponseType
+}
+
+// 请求响应参数(包含data)
+declare interface ResultData<T = any> extends Result {
+  data: T
+}
+
+// 请求响应参数(不包含data)
+declare interface Result {
+  code: string | number
+  msg: string
+}
+
+// BaseEntity
+declare interface BaseEntity {
+  /** 乐观锁 */
+  status?: string
+  delFlag?: string
+  version?: number
+  createName?: string
+  createBy?: string
+  createTime?: string
+  updateName?: string
+  updateBy?: string
+  updateTime?: any
+}
+
+// 分页请求参数
+declare interface PageQuery {
+  pageNum: number
+  pageSize: number
+}
+
+// 分页响应参数
+declare interface ResPage<T> {
+  list: T[]
+  pageNum: number
+  pageSize: number
+  total: number
+}
+
+declare type Nullable<T> = T | null
+
+declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>
+
+declare interface Fn<T = any> {
+  (...arg: T[]): T
+}
+type ObjToKeyValArray<T> = {
+  [K in keyof T]: [K, T[K]]
+}[keyof T]
+
+declare type keyOnPrefix<T> = {
+  [K in keyof T as `on${Capitalize<K>}`]: T[K] extends readonly any[] ? (...t: T[K]) => void : never
+}
+
+declare namespace Menu {
+  interface MenuOptions {
+    id: string
+    menuId: string
+    parentId: string
+    path: string
+    name: string
+    title: string
+    orderNum: number
+    menuType: string
+    component?: string | (() => Promise<unknown>)
+    redirect?: string
+    meta: MetaProps
+    children?: MenuOptions[]
+  }
+
+  interface MetaProps {
+    icon: string
+    title: string
+    isLink?: boolean
+    isHidden: boolean
+    isFull: boolean
+    isAffix: boolean
+    isKeepAlive: boolean
+    useDataScope: string
+  }
+}

+ 92 - 0
src/views/test/components/index.vue

@@ -0,0 +1,92 @@
+<template>
+  <el-dialog
+    v-model="visible"
+    :title="`${paramsProps.title}`"
+    :destroy-on-close="true"
+    width="650px"
+    draggable
+    append-to-body>
+    <el-form
+      ref="ruleFormRef"
+      label-width="100px"
+      label-suffix=" :"
+      :rules="rules"
+      :model="paramsProps.row"
+      @submit.enter.prevent="handleConfirm">
+      <el-form-item label="参数名称" prop="name">
+        <el-input v-model="paramsProps.row.name" placeholder="填写参数名称" clearable />
+      </el-form-item>
+      <el-form-item label="参数Key" prop="configKey">
+        <el-input v-model="paramsProps.row.configKey" placeholder="填写参数Key" clearable />
+      </el-form-item>
+      <el-form-item label="参数Value" prop="configValue">
+        <el-input v-model="paramsProps.row.configValue" placeholder="填写参数Value" clearable />
+      </el-form-item>
+      <el-form-item label="排序" prop="orderNum">
+        <el-input-number v-model="paramsProps.row.orderNum" :precision="0" :min="1" :max="999999" />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="paramsProps.row.remark" placeholder="请填写备注" clearable />
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <el-button @click="visible = false"> 取消 </el-button>
+      <el-button type="primary" @click="handleConfirm"> 确定 </el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts" name="AddTestCase">
+import { ElMessage } from 'element-plus'
+import { FormInstance } from 'element-plus'
+const rules = reactive({
+  name: [{ required: true, message: '请填写参数名称' }]
+})
+interface DialogProps {
+  api?: (params: any) => Promise<any> // 调用接口
+  title: string // 顶部标题
+  row: Partial<any>
+  getTableList?: () => void
+}
+const visible = ref(false)
+const paramsProps = ref<DialogProps>({
+  title: '',
+  row: {},
+  api: undefined,
+  getTableList: undefined
+})
+
+// emit
+const emit = defineEmits(['submit'])
+
+// 接收父组件传过来的参数
+const acceptParams = (params: DialogProps) => {
+  paramsProps.value = params
+  visible.value = true
+}
+// 提交数据(新增/编辑)
+const ruleFormRef = ref<FormInstance>()
+const handleConfirm = async () => {
+  ruleFormRef.value!.validate(async valid => {
+    if (!valid) return
+    try {
+      const { code } = await paramsProps.value.api!(paramsProps.value.row)
+      if (code == 200) {
+        ElMessage.success({ message: `${paramsProps.value.title}成功!` })
+        paramsProps.value.getTableList!()
+        emit('submit')
+        visible.value = false
+      }
+    } catch (error) {
+      console.log(error)
+    }
+  })
+}
+
+defineExpose({
+  acceptParams
+})
+</script>
+
+<style scoped lang="scss"></style>

+ 34 - 72
src/views/test/index.vue

@@ -27,24 +27,26 @@
     <div class="table-card table-main">
     <div class="table-card table-main">
       <div class="table-header">
       <div class="table-header">
         <div class="header-button-lf">
         <div class="header-button-lf">
-          <el-button type="primary" icon="CirclePlus"> 新增组织 </el-button>
-          <el-button type="danger" icon="Delete" plain> 批量删除 </el-button>
+          <el-button type="primary" icon="CirclePlus" @click="openDialog('新增')"> 新增 </el-button>
+          <el-button type="danger" icon="Delete" plain> 删除 </el-button>
         </div>
         </div>
       </div>
       </div>
-      <el-table :data="tableData" border ref="tableRef">
+      <el-table :data="tableData" border ref="tableRef" show-overflow-tooltip>
         <el-table-column type="index" label="序号" width="60" />
         <el-table-column type="index" label="序号" width="60" />
-        <el-table-column prop="date" label="用例名称" width="180" />
-        <el-table-column prop="date" label="用例类型" width="180" />
-        <el-table-column prop="name" label="Name" width="180" />
-        <el-table-column prop="name" label="Name" width="180" />
-        <el-table-column prop="address" label="Address" />
+        <el-table-column prop="id" label="用例编号" width="300" />
+        <el-table-column prop="name" label="用例名称" width="180" />
+        <el-table-column prop="type" label="用例类型" width="180" />
 
 
         <el-table-column fixed="right" label="操作" min-width="120">
         <el-table-column fixed="right" label="操作" min-width="120">
-          <template #default>
-            <el-button link type="primary" size="small" @click="handleClick">详情 </el-button>
+          <template #default="{ row }">
+            <el-button link type="primary" size="small" @click="openDialog('编辑', row)"
+              >详情
+            </el-button>
             <el-button link type="primary" size="small">流程查看</el-button>
             <el-button link type="primary" size="small">流程查看</el-button>
             <el-button link type="primary" size="small">流程设计</el-button>
             <el-button link type="primary" size="small">流程设计</el-button>
-            <el-button link type="primary" size="small">编辑</el-button>
+            <el-button link type="primary" size="small" @click="openDialog('编辑', row)"
+              >编辑</el-button
+            >
           </template>
           </template>
         </el-table-column>
         </el-table-column>
       </el-table>
       </el-table>
@@ -61,9 +63,12 @@
         @current-change="handleCurrentChange" />
         @current-change="handleCurrentChange" />
     </div>
     </div>
     <!-- </div> -->
     <!-- </div> -->
+    <AddDialog ref="dialogRef" />
   </div>
   </div>
 </template>
 </template>
 <script setup lang="ts">
 <script setup lang="ts">
+import { ConfigVO } from '@/api/interface/config'
+import AddDialog from './components/index.vue'
 const tableRef = ref()
 const tableRef = ref()
 const pageable = {
 const pageable = {
   // 当前页数
   // 当前页数
@@ -79,10 +84,6 @@ const formInline = reactive({
   date: ''
   date: ''
 })
 })
 
 
-const handleClick = () => {
-  console.log('click')
-}
-
 /**
 /**
  * @description 每页条数改变
  * @description 每页条数改变
  * @param {Number} val 当前条数
  * @param {Number} val 当前条数
@@ -100,67 +101,28 @@ const handleCurrentChange = (_val: number) => {}
 const onSubmit = () => {
 const onSubmit = () => {
   console.log('submit!')
   console.log('submit!')
 }
 }
-const tableData = [
-  {
-    date: '2016-05-03',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
+const tableData: ConfigVO[] = [
   {
   {
-    date: '2016-05-02',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
+    id: '76575g76t-8g678g-hu9we89-89dsc',
+    name: 'XX用例设计',
+    type: '故障注入'
   },
   },
   {
   {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
+    id: 'teg345g34-435634tg-2346245t-234tf345',
+    name: 'XX用例设计',
+    type: '故障注入'
   }
   }
 ]
 ]
+
+// 打开 dialog(新增、查看、编辑)
+const dialogRef = ref<InstanceType<typeof AddDialog> | null>(null)
+const openDialog = (title: string, row: Partial<ConfigVO> = {}) => {
+  const params = {
+    title,
+    row: { ...row },
+    isView: title === '查看'
+  }
+  dialogRef.value?.acceptParams(params)
+}
 </script>
 </script>
 <style lang="scss" scoped></style>
 <style lang="scss" scoped></style>