A:引入axios;增加初始化访问示例

This commit is contained in:
jimmy committed 2025-06-25 13:24:16 +08:00
1 parent e5e043246e
commit 1b35e2dfd7
14 files changed
+1352 -278

No files matched your search

+1 -2
View File
@@ -1,3 +1,2 @@
VITE_MODE='development'
VITE_APP_API_URL='http://192.****:8008/api/'
VITE_API_URL=http://localhost:3000/api
VITE_APP_API_URL='http://localhost:8268/api'
+1 -1
View File
@@ -1,2 +1,2 @@
VITE_MODE='production'
VITE_APP_API_URL='http://xxx.xxx.xxx.xx:8008/api/'
VITE_APP_API_URL='http://localhost:8268/api'
+1
View File
@@ -15,6 +15,7 @@
},
"dependencies": {
"@vicons/ionicons5": "^0.13.0",
"axios": "^1.10.0",
"gsap": "^3.13.0",
"pinia": "^3.0.1",
"unplugin-auto-import": "^19.3.0",
+284
View File
@@ -11,6 +11,9 @@ importers:
'@vicons/ionicons5':
specifier: ^0.13.0
version: 0.13.0
axios:
specifier: ^1.10.0
version: 1.10.0
gsap:
specifier: ^3.13.0
version: 3.13.0
@@ -20,6 +23,9 @@ importers:
unplugin-auto-import:
specifier: ^19.3.0
version: 19.3.0
unplugin-vue-components:
specifier: ^28.7.0
version: 28.7.0(@babel/parser@7.27.2)(vue@3.5.14(typescript@5.8.3))
vue:
specifier: ^3.5.13
version: 3.5.14(typescript@5.8.3)
@@ -971,6 +977,10 @@ packages:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==, tarball: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.1.tgz}
engines: {node: '>=12'}
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, tarball: https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz}
@@ -981,9 +991,19 @@ packages:
async-validator@4.2.5:
resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
axios@1.10.0:
resolution: {integrity: sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, tarball: https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz}
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
birpc@2.3.0:
resolution: {integrity: sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g==, tarball: https://registry.npmmirror.com/birpc/-/birpc-2.3.0.tgz}
@@ -1013,6 +1033,10 @@ packages:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==, tarball: https://registry.npmmirror.com/cac/-/cac-6.7.14.tgz}
engines: {node: '>=8'}
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, tarball: https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz}
engines: {node: '>=6'}
@@ -1032,6 +1056,10 @@ packages:
resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==, tarball: https://registry.npmmirror.com/check-error/-/check-error-2.1.1.tgz}
engines: {node: '>= 16'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, tarball: https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz}
engines: {node: '>=7.0.0'}
@@ -1039,6 +1067,10 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
commander@10.0.1:
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==, tarball: https://registry.npmmirror.com/commander/-/commander-10.0.1.tgz}
engines: {node: '>=14'}
@@ -1130,6 +1162,14 @@ packages:
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==, tarball: https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz}
engines: {node: '>=12'}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, tarball: https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz}
@@ -1158,9 +1198,25 @@ packages:
error-stack-parser-es@0.1.5:
resolution: {integrity: sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==, tarball: https://registry.npmmirror.com/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz}
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-module-lexer@1.7.0:
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==, tarball: https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz}
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-set-tostringtag@2.1.0:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
esbuild@0.25.4:
resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==, tarball: https://registry.npmmirror.com/esbuild/-/esbuild-0.25.4.tgz}
engines: {node: '>=18'}
@@ -1317,10 +1373,23 @@ packages:
flatted@3.3.3:
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==, tarball: https://registry.npmmirror.com/flatted/-/flatted-3.3.3.tgz}
follow-redirects@1.15.9:
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==, tarball: https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz}
engines: {node: '>=14'}
form-data@4.0.3:
resolution: {integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==}
engines: {node: '>= 6'}
fs-extra@11.3.0:
resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==, tarball: https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.0.tgz}
engines: {node: '>=14.14'}
@@ -1330,10 +1399,21 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, tarball: https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz}
engines: {node: '>=6.9.0'}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
get-stream@9.0.1:
resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==, tarball: https://registry.npmmirror.com/get-stream/-/get-stream-9.0.1.tgz}
engines: {node: '>=18'}
@@ -1358,6 +1438,10 @@ packages:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==, tarball: https://registry.npmmirror.com/globals/-/globals-14.0.0.tgz}
engines: {node: '>=18'}
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, tarball: https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz}
@@ -1371,6 +1455,18 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, tarball: https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz}
engines: {node: '>=8'}
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==, tarball: https://registry.npmmirror.com/he/-/he-1.2.0.tgz}
hasBin: true
@@ -1421,6 +1517,10 @@ packages:
ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, tarball: https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz}
is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
is-docker@3.0.0:
resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==, tarball: https://registry.npmmirror.com/is-docker/-/is-docker-3.0.0.tgz}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -1577,6 +1677,10 @@ packages:
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==, tarball: https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
memorystream@0.3.1:
resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==, tarball: https://registry.npmmirror.com/memorystream/-/memorystream-0.3.1.tgz}
engines: {node: '>= 0.10.0'}
@@ -1589,6 +1693,14 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, tarball: https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz}
engines: {node: '>=8.6'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, tarball: https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz}
@@ -1646,6 +1758,10 @@ packages:
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
hasBin: true
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
npm-normalize-package-bin@4.0.0:
resolution: {integrity: sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==, tarball: https://registry.npmmirror.com/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz}
engines: {node: ^18.17.0 || >=20.5.0}
@@ -1783,6 +1899,9 @@ packages:
proto-list@1.2.4:
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==, tarball: https://registry.npmmirror.com/proto-list/-/proto-list-1.2.4.tgz}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, tarball: https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz}
engines: {node: '>=6'}
@@ -1797,6 +1916,10 @@ packages:
resolution: {integrity: sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==, tarball: https://registry.npmmirror.com/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz}
engines: {node: ^18.17.0 || >=20.5.0}
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, tarball: https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz}
engines: {node: '>=4'}
@@ -1934,6 +2057,10 @@ packages:
resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==, tarball: https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.13.tgz}
engines: {node: '>=12.0.0'}
tinyglobby@0.2.14:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'}
tinypool@1.0.2:
resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==, tarball: https://registry.npmmirror.com/tinypool/-/tinypool-1.0.2.tgz}
engines: {node: ^18.0.0 || >=20.0.0}
@@ -2028,6 +2155,19 @@ packages:
resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==}
engines: {node: '>=18.12.0'}
unplugin-vue-components@28.7.0:
resolution: {integrity: sha512-3SuWAHlTjOiZckqRBGXRdN/k6IMmKyt2Ch5/+DKwYaT321H0ItdZDvW4r8/YkEKQpN9TN3F/SZ0W342gQROC3Q==}
engines: {node: '>=14'}
peerDependencies:
'@babel/parser': ^7.15.8
'@nuxt/kit': ^3.2.2
vue: 2 || 3
peerDependenciesMeta:
'@babel/parser':
optional: true
'@nuxt/kit':
optional: true
unplugin@2.3.5:
resolution: {integrity: sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==}
engines: {node: '>=18.12.0'}
@@ -3155,14 +3295,31 @@ snapshots:
ansi-styles@6.2.1: {}
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
argparse@2.0.1: {}
assertion-error@2.0.1: {}
async-validator@4.2.5: {}
asynckit@0.4.0: {}
axios@1.10.0:
dependencies:
follow-redirects: 1.15.9
form-data: 4.0.3
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
balanced-match@1.0.2: {}
binary-extensions@2.3.0: {}
birpc@2.3.0: {}
boolbase@1.0.0: {}
@@ -3193,6 +3350,11 @@ snapshots:
cac@6.7.14: {}
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
callsites@3.1.0: {}
caniuse-lite@1.0.30001718: {}
@@ -3212,12 +3374,28 @@ snapshots:
check-error@2.1.1: {}
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
braces: 3.0.3
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.3
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
color-name@1.1.4: {}
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
commander@10.0.1: {}
concat-map@0.0.1: {}
@@ -3291,6 +3469,14 @@ snapshots:
define-lazy-prop@3.0.0: {}
delayed-stream@1.0.0: {}
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
eastasianwidth@0.2.0: {}
editorconfig@1.0.4:
@@ -3312,8 +3498,23 @@ snapshots:
error-stack-parser-es@0.1.5: {}
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
es-module-lexer@1.7.0: {}
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
get-intrinsic: 1.3.0
has-tostringtag: 1.0.2
hasown: 2.0.2
esbuild@0.25.4:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.4
@@ -3516,11 +3717,21 @@ snapshots:
flatted@3.3.3: {}
follow-redirects@1.15.9: {}
foreground-child@3.3.1:
dependencies:
cross-spawn: 7.0.6
signal-exit: 4.1.0
form-data@4.0.3:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
hasown: 2.0.2
mime-types: 2.1.35
fs-extra@11.3.0:
dependencies:
graceful-fs: 4.2.11
@@ -3530,8 +3741,28 @@ snapshots:
fsevents@2.3.3:
optional: true
function-bind@1.1.2: {}
gensync@1.0.0-beta.2: {}
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
function-bind: 1.1.2
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
hasown: 2.0.2
math-intrinsics: 1.1.0
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
es-object-atoms: 1.1.1
get-stream@9.0.1:
dependencies:
'@sec-ant/readable-stream': 0.4.1
@@ -3558,6 +3789,8 @@ snapshots:
globals@14.0.0: {}
gopd@1.2.0: {}
graceful-fs@4.2.11: {}
graphemer@1.4.0: {}
@@ -3566,6 +3799,16 @@ snapshots:
has-flag@4.0.0: {}
has-symbols@1.1.0: {}
has-tostringtag@1.0.2:
dependencies:
has-symbols: 1.1.0
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
he@1.2.0: {}
highlight.js@11.11.1: {}
@@ -3609,6 +3852,10 @@ snapshots:
ini@1.3.8: {}
is-binary-path@2.1.0:
dependencies:
binary-extensions: 2.3.0
is-docker@3.0.0: {}
is-extglob@2.1.1: {}
@@ -3753,6 +4000,8 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
math-intrinsics@1.1.0: {}
memorystream@0.3.1: {}
merge2@1.4.1: {}
@@ -3762,6 +4011,12 @@ snapshots:
braces: 3.0.3
picomatch: 2.3.1
mime-db@1.52.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.11
@@ -3826,6 +4081,8 @@ snapshots:
dependencies:
abbrev: 2.0.0
normalize-path@3.0.0: {}
npm-normalize-package-bin@4.0.0: {}
npm-run-all2@7.0.2:
@@ -3957,6 +4214,8 @@ snapshots:
proto-list@1.2.4: {}
proxy-from-env@1.1.0: {}
punycode@2.3.1: {}
quansync@0.2.10: {}
@@ -3968,6 +4227,10 @@ snapshots:
json-parse-even-better-errors: 4.0.0
npm-normalize-package-bin: 4.0.0
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
resolve-from@4.0.0: {}
reusify@1.1.0: {}
@@ -4099,6 +4362,11 @@ snapshots:
fdir: 6.4.4(picomatch@4.0.2)
picomatch: 4.0.2
tinyglobby@0.2.14:
dependencies:
fdir: 6.4.4(picomatch@4.0.2)
picomatch: 4.0.2
tinypool@1.0.2: {}
tinyrainbow@2.0.0: {}
@@ -4186,6 +4454,22 @@ snapshots:
pathe: 2.0.3
picomatch: 4.0.2
unplugin-vue-components@28.7.0(@babel/parser@7.27.2)(vue@3.5.14(typescript@5.8.3)):
dependencies:
chokidar: 3.6.0
debug: 4.4.1
local-pkg: 1.1.1
magic-string: 0.30.17
mlly: 1.7.4
tinyglobby: 0.2.14
unplugin: 2.3.5
unplugin-utils: 0.2.4
vue: 3.5.14(typescript@5.8.3)
optionalDependencies:
'@babel/parser': 7.27.2
transitivePeerDependencies:
- supports-color
unplugin@2.3.5:
dependencies:
acorn: 8.14.1
@@ -28,23 +28,23 @@
/* ========== 颜色定义 - 亮色主题(默认) ========== */
/* 背景色层级 */
--bg-primary: #ffffff; /* 主背景色 */
--bg-secondary: #f8fafc; /* 次级背景 */
--bg-tertiary: #f1f5f9; /* 三级背景 */
--bg-quaternary: #e2e8f0; /* 四级背景 */
--bg-overlay: rgba(255, 255, 255, 0.95); /* 遮罩层 */
--bg-glass: rgba(248, 250, 252, 0.8); /* 玻璃效果 */
--bg-card: rgba(241, 245, 249, 0.8); /* 卡片背景 */
--bg-hover: rgba(59, 130, 246, 0.08); /* 悬停背景 */
--bg-selected: rgba(59, 130, 246, 0.15); /* 选中背景 */
--bg-primary: #ffffff;
--bg-secondary: #f8fafc;
--bg-tertiary: #f1f5f9;
--bg-quaternary: #e2e8f0;
--bg-overlay: rgba(255, 255, 255, 0.95);
--bg-glass: rgba(248, 250, 252, 0.8);
--bg-card: rgba(241, 245, 249, 0.8);
--bg-hover: rgba(59, 130, 246, 0.08);
--bg-selected: rgba(59, 130, 246, 0.15);
/* 文字色层级 */
--text-primary: #0f172a; /* 主文字色 */
--text-secondary: #1e293b; /* 次级文字 */
--text-tertiary: #334155; /* 三级文字 */
--text-quaternary: #475569; /* 四级文字 */
--text-muted: #64748b; /* 柔和文字 */
--text-disabled: #94a3b8; /* 禁用文字 */
--text-primary: #0f172a;
--text-secondary: #1e293b;
--text-tertiary: #334155;
--text-quaternary: #475569;
--text-muted: #64748b;
--text-disabled: #94a3b8;
/* 边框色层级 */
--border-primary: #e2e8f0;
@@ -54,12 +54,12 @@
--border-focus: #3b82f6;
/* 主题色 - 这些在明暗主题中保持一致 */
--accent-primary: #3b82f6; /* 主要强调色 - 蓝色 */
--accent-secondary: #06b6d4; /* 次要强调色 - 青色 */
--accent-success: #22c55e; /* 成功 - 绿色 */
--accent-warning: #f59e0b; /* 警告 - 橙色 */
--accent-error: #ef4444; /* 错误 - 红色 */
--accent-purple: #8b5cf6; /* 紫色 */
--accent-primary: #3b82f6;
--accent-secondary: #06b6d4;
--accent-success: #22c55e;
--accent-warning: #f59e0b;
--accent-error: #ef4444;
--accent-purple: #8b5cf6;
/* 阴影 */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
@@ -94,63 +94,16 @@
/* 布局 */
--section-gap: 160px;
/* 监控页面软件列表选中样式颜色 */
--monitor-bg-card-selected: rgba(var(--accent-primary), 0.05);
--monitor-accent-primary-alpha: rgba(var(--accent-primary), 0.2);
}
/* ==================== 暗色主题 - .dark 类名方式 ==================== */
.dark {
/* 背景色层级 - 暗色 */
--bg-primary: #0f172a;
--bg-secondary: #1e293b;
--bg-tertiary: #334155;
--bg-quaternary: #475569;
--bg-overlay: rgba(15, 23, 42, 0.95);
--bg-glass: rgba(30, 41, 59, 0.8);
--bg-card: rgba(51, 65, 85, 0.5);
--bg-hover: rgba(59, 130, 246, 0.1);
--bg-selected: rgba(59, 130, 246, 0.2);
/* 文字色层级 - 暗色 */
--text-primary: #f8fafc;
--text-secondary: #f1f5f9;
--text-tertiary: #e2e8f0;
--text-quaternary: #cbd5e1;
--text-muted: #94a3b8;
--text-disabled: #64748b;
/* 边框色层级 - 暗色 */
--border-primary: #334155;
--border-secondary: rgba(51, 65, 85, 0.3);
--border-tertiary: rgba(71, 85, 105, 0.3);
--border-hover: rgba(59, 130, 246, 0.5);
--border-focus: #3b82f6;
/* 阴影 - 暗色模式 */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.6);
/* 滚动条颜色 - 暗色主题 */
--scrollbar-track-bg: rgba(255, 255, 255, 0.03);
--scrollbar-thumb-bg: rgba(255, 255, 255, 0.2);
--scrollbar-thumb-bg-hover: rgba(255, 255, 255, 0.35);
--scrollbar-thumb-bg-active: rgba(255, 255, 255, 0.45);
--scrollbar-thumb-border: rgba(255, 255, 255, 0.1);
--scrollbar-thumb-border-hover: rgba(255, 255, 255, 0.2);
--scrollbar-thumb-border-active: rgba(255, 255, 255, 0.3);
--scrollbar-corner-bg: rgba(255, 255, 255, 0.03);
/* 语义化颜色变量(向后兼容)*/
--color-background: var(--bg-primary);
--color-background-soft: var(--bg-secondary);
--color-background-mute: var(--bg-tertiary);
--color-border: var(--border-primary);
--color-border-hover: var(--border-hover);
--color-heading: var(--text-primary);
--color-text: var(--text-secondary);
}
/* ==================== 暗色主题 - data-theme 属性方式(向后兼容) ==================== */
/* ==================== 暗色主题变量定义 ==================== */
/* 暗色主题 - .dark 类名方式 */
.dark,
/* 暗色主题 - data-theme 属性方式(向后兼容) */
[data-theme="dark"] {
/* 背景色层级 - 暗色 */
--bg-primary: #0f172a;
@@ -202,6 +155,10 @@
--color-border-hover: var(--border-hover);
--color-heading: var(--text-primary);
--color-text: var(--text-secondary);
/* 监控页面软件列表选中样式颜色 */
--monitor-bg-card-selected: rgba(var(--accent-primary), 0.1);
}
/* ==================== 媒体查询 - 系统主题偏好 ==================== */
@@ -257,15 +214,16 @@
--color-border-hover: var(--border-hover);
--color-heading: var(--text-primary);
--color-text: var(--text-secondary);
/* 监控页面软件列表选中样式颜色 */
--monitor-bg-card-selected: rgba(var(--accent-primary), 0.1);
}
}
/* ==================== 主题切换过渡效果 ==================== */
* {
/* 确保所有元素都使用主题过渡 */
transition: background-color 0.2s ease,
border-color 0.2s ease,
color 0.2s ease;
transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
/* 防止页面初始加载时的闪烁 */
@@ -0,0 +1,67 @@
/**
* Time:2025/6/15 20:13 49
* Name:httpConfig.ts
* Path:src/config
* ProjectName:argus-front
* Author:charlatans
*
* Il n'ya qu'un héroïsme au monde :
* c'est de voir le monde tel qu'il est et de l'aimer.
*/
import type { HttpConfig } from '@/types/http.ts'
// 2. 配置管理器 (config/httpConfig.ts)
class HttpConfigManager {
private config: HttpConfig = {
baseURL: import.meta.env.VITE_APP_API_URL || 'http://localhost:8726',
timeout: 10000,
headers: {
'Content-Type': 'application/json'
}
};
/**
* 设置配置
*/
setConfig(config: Partial<HttpConfig>): void {
this.config = { ...this.config, ...config };
}
/**
* 获取配置
*/
getConfig(): HttpConfig {
return { ...this.config };
}
/**
* 设置基础URL
*/
setBaseURL(baseURL: string): void {
this.config.baseURL = baseURL;
}
/**
* 设置端口
*/
setPort(host: string, port: number): void {
const protocol = this.config.baseURL.startsWith('https') ? 'https' : 'http';
this.config.baseURL = `${protocol}://${host}:${port}`;
}
/**
* 设置超时时间
*/
setTimeout(timeout: number): void {
this.config.timeout = timeout;
}
/**
* 设置默认请求头
*/
setHeaders(headers: Record<string, string>): void {
this.config.headers = { ...this.config.headers, ...headers };
}
}
export const httpConfig = new HttpConfigManager();
+27 -13
View File
@@ -10,6 +10,8 @@ import websocketPlugin from '@/plugins/websocketPlugin'
import { useWebSocketStore } from '@/stores/websocketStore'
import { createNaiveUI } from './naive'
import { useThemeStore } from '@/stores/theme'
import { useUuidStore } from '@/stores/uuidStore'
import { logB } from '@/utils/logHelper/logUtils'
const app = createApp(App)
app.use(createPinia())
@@ -21,6 +23,14 @@ app.use(createNaiveUI())
// 这行代码会触发 store 的初始化,从而立即应用主题
useThemeStore()
// 获取全局 UUID
const useUuidStore1 = useUuidStore()
logB.success('全局 ID :', useUuidStore1.uuid)
// http 注册
import httpPlugin from './plugins/http';
app.use(httpPlugin);
app.mount('#app')
// 注册 C# 函数
@@ -31,16 +41,20 @@ const webSocketStore = useWebSocketStore()
// 监听WebSocket地址
const bridge = CSharpBridgeV2?.getBridge()
const intervalId = setInterval(() => {
if (webSocketStore.isInitialized) {
clearInterval(intervalId)
return
}
if (bridge){
bridge.send('GetWebSocketPath', {}, (data) => {
webSocketStore.initialize(data)
console.log(data, '======')
})
}
}, 500)
if (bridge) {
const intervalId = setInterval(() => {
if (webSocketStore.isInitialized) {
clearInterval(intervalId)
return
}
if (bridge) {
bridge.send('GetWebSocketPath', {}, (data) => {
webSocketStore.initialize(data)
console.log(data, '======')
})
}
}, 500)
} else {
// todo: 2025/6/25 08:32 开发阶段直接使用固定节点
webSocketStore.initialize('ws://127.0.0.1:8267')
}
+29
View File
@@ -0,0 +1,29 @@
/**
* Time:2025/6/15 20:23 36
* Name:http.ts
* Path:src/plugins
* ProjectName:argus-front
* Author:charlatans
*
* Il n'ya qu'un héroïsme au monde :
* c'est de voir le monde tel qu'il est et de l'aimer.
*/
import { type App } from 'vue';
import { httpConfig } from '@/config/httpConfig.ts'
import { httpClient } from '@/utils/http.ts'
export default {
install(app: App) {
// 更新HTTP配置
const config = httpConfig.getConfig();
httpClient.updateConfig(config);
// 注册全局属性
app.config.globalProperties.$http = httpClient;
app.config.globalProperties.$httpConfig = httpConfig;
// 提供注入
app.provide('$http', httpClient);
app.provide('$httpConfig', httpConfig);
}
};
@@ -0,0 +1,16 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import lodash from 'lodash'
export const useUuidStore = defineStore('uuid', () => {
const _uuid: ref = ref('')
const uuid = computed(() => {
if (lodash.isEmpty(_uuid.value)) {
_uuid.value = crypto.randomUUID()
}
return _uuid.value
})
return { uuid }
})
+12
View File
@@ -0,0 +1,12 @@
/**
* 响应模型
*/
interface ResponseModel {
success: boolean,
data: unknown,
message: string
}
export { ResponseModel }
+292
View File
@@ -0,0 +1,292 @@
import axios, {
type AxiosInstance,
type AxiosRequestConfig,
type AxiosResponse,
AxiosError,
type InternalAxiosRequestConfig,
} from 'axios'
// 或者混合导入(如果同时需要导入值和类型)
import type { ApiResponse, HttpConfig, RequestConfig } from '@/types/http.ts'
import { disLog, logB, logN, logS } from '@/utils/logHelper/logUtils'
class HttpClient {
private axiosInstance: AxiosInstance
private pending: Map<string, AbortController> = new Map()
constructor() {
this.axiosInstance = axios.create()
this.setupInterceptors()
}
/**
* 更新配置
*/
updateConfig(config: HttpConfig): void {
this.axiosInstance.defaults.baseURL = config.baseURL
this.axiosInstance.defaults.timeout = config.timeout || 10000
this.axiosInstance.defaults.headers.common = {
...this.axiosInstance.defaults.headers.common,
...config.headers,
}
}
/**
* 生成请求标识符
*/
private getRequestKey(config: AxiosRequestConfig): string {
return `${config.method?.toUpperCase()}_${config.url}_${JSON.stringify(
config.params,
)}_${JSON.stringify(config.data)}`
}
/**
* 添加请求到待处理列表
*/
private addPending(config: InternalAxiosRequestConfig): void {
const requestKey = this.getRequestKey(config)
config.signal = new AbortController().signal
if (this.pending.has(requestKey)) {
this.pending.get(requestKey)?.abort()
}
const controller = new AbortController()
config.signal = controller.signal
this.pending.set(requestKey, controller)
}
/**
* 移除请求从待处理列表
*/
private removePending(config: AxiosRequestConfig): void {
const requestKey = this.getRequestKey(config)
if (this.pending.has(requestKey)) {
this.pending.delete(requestKey)
}
}
/**
* 设置拦截器
*/
private setupInterceptors(): void {
// 请求拦截器
this.axiosInstance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
console.group(
'请求链接: ' +
config.url +
' ' +
config.method?.toUpperCase() +
' params: ' +
JSON.stringify(config.params) +
', data: ' +
JSON.stringify(config.data),
)
// 防止重复请求
this.addPending(config)
// 添加时间戳防止缓存
if (config.method?.toLowerCase() === 'get') {
config.params = {
...config.params,
_t: Date.now(),
}
}
// 添加token
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
logB.success('请求发送:', config)
return config
},
(error: AxiosError) => {
logB.error('请求错误:', error)
return Promise.reject(error)
},
)
// 响应拦截器
this.axiosInstance.interceptors.response.use(
(response: AxiosResponse<ApiResponse>) => {
this.removePending(response.config)
logB.success('响应接收:', response)
// 统一处理响应数据
const { data } = response
console.groupEnd()
if (data.success || data.code === 200) {
return response
} else {
// 业务错误处理
const errorMessage = data.message || '请求失败'
return Promise.reject(new Error(errorMessage))
}
},
(error: AxiosError<ApiResponse>) => {
this.removePending(error.config || {})
logB.error('响应错误:', error)
// 统一错误处理
this.handleError(error)
console.groupEnd()
return Promise.reject(error)
},
)
}
/**
* 统一错误处理
*/
private handleError(error: AxiosError<ApiResponse>): void {
let message = '网络错误'
if (error.response) {
const { status, data } = error.response
switch (status) {
case 400:
message = data?.message || '请求参数错误'
break
case 401:
message = '未授权,请重新登录'
// 清除token并跳转到登录页
localStorage.removeItem('token')
// router.push('/login');
break
case 403:
message = '拒绝访问'
break
case 404:
message = '请求的资源不存在'
break
case 500:
message = '服务器内部错误'
break
default:
message = data?.message || `错误码: ${status}`
}
} else if (error.code === 'ECONNABORTED') {
message = '请求超时'
} else if (error.message.includes('Network Error')) {
message = '网络连接异常'
}
logB.error(message)
}
/**
* 通用请求方法
*/
async request<T = unknown>(config: RequestConfig): Promise<ApiResponse<T>> {
try {
const response = await this.axiosInstance.request<ApiResponse<T>>(config)
return response.data
} catch (error) {
throw error
}
}
/**
* GET请求
*/
async get<T = unknown>(
url: string,
params?: unknown,
config?: AxiosRequestConfig,
): Promise<ApiResponse<T>> {
return this.request<T>({
url,
method: 'GET',
params,
...config,
})
}
/**
* POST请求
*/
async post<T = unknown>(
url: string,
data?: unknown,
config?: AxiosRequestConfig,
): Promise<ApiResponse<T>> {
return this.request<T>({
url,
method: 'POST',
data,
...config,
})
}
/**
* PUT请求
*/
async put<T = unknown>(
url: string,
data?: unknown,
config?: AxiosRequestConfig,
): Promise<ApiResponse<T>> {
return this.request<T>({
url,
method: 'PUT',
data,
...config,
})
}
/**
* DELETE请求
*/
async delete<T = unknown>(
url: string,
params?: unknown,
config?: AxiosRequestConfig,
): Promise<ApiResponse<T>> {
return this.request<T>({
url,
method: 'DELETE',
params,
...config,
})
}
/**
* PATCH请求
*/
async patch<T = unknown>(
url: string,
data?: unknown,
config?: AxiosRequestConfig,
): Promise<ApiResponse<T>> {
return this.request<T>({
url,
method: 'PATCH',
data,
...config,
})
}
/**
* 取消所有请求
*/
cancelAllRequests(): void {
this.pending.forEach((controller) => {
controller.abort()
})
this.pending.clear()
}
/**
* 获取Axios实例
*/
getAxiosInstance(): AxiosInstance {
return this.axiosInstance
}
}
export const httpClient = new HttpClient()
+12 -4
View File
@@ -2,6 +2,8 @@ import { CommandHandler, SubscriptionRequest, WebSocketMessage, WebSocketRespons
import CSharpBridgeV2 from '@/correspond/CSharpBridgeV2'
import { ref } from 'vue'
import { WebSocketState } from '@/types/websocket'
import { logB } from '@/utils/logHelper/logUtils'
import { useUuidStore } from '@/stores/uuidStore'
export class WebSocketManager {
private socket: WebSocket | null = null
@@ -33,15 +35,21 @@ export class WebSocketManager {
// 初始化WebSocket连接
public initialize(url: string) {
console.log('initialize', url)
logB.info('进入 web Socket 初始化, url:', url)
if (url.trim() === '') return
if (this.socket) return
this.state = WebSocketState.CONNECTING
this.socket = new WebSocket(url)
const useUuidStore1 = useUuidStore()
logB.info('准备建立连接, uuid:', useUuidStore1.uuid)
const url1 = url + '?uuid=' + useUuidStore1.uuid
logB.info('拼接链接:', url1)
this.socket = new WebSocket(url1)
this.isInitialized = true
this.registerHandler('welcome', (data: WebSocketResponse) => {
if (data.success) console.log('WebSocket 连接建立成功 !! ')
if (data.success) logB.success('WebSocket 连接建立成功 !! ')
else console.error('收到WbeSocket 欢迎信息,但是解析失败!!1')
})
@@ -49,7 +57,7 @@ export class WebSocketManager {
this.state = WebSocketState.CONNECTED
this.isReconnecting = true
this.reconnectAttempts = 0
console.log('WebSocket connected')
logB.success('WebSocket connected')
// 发送队列中的消息
this.flushMessageQueue()
// 重新激活订阅
@@ -1,85 +1,206 @@
<template>
<div class="sidebar scrollbar-primary scrollbar-thin" :style="{ width: width + 'px' }">
<div class="sidebar-content">
<template v-if="false">
<div class="sidebar-header">
<h3 class="sidebar-title">系统概览</h3>
<div class="sidebar-badge">{{ data.processCount }}</div>
</div>
<div class="sidebar-stats">
<span>使用 echarts 绘制当前网速</span>
</div>
</template>
<div class="sidebar-header">
<h3 class="sidebar-title">系统概览</h3>
<div class="sidebar-badge">{{ data.processCount }}</div>
<h3 class="sidebar-title">所有连接</h3>
</div>
<div class="sidebar-stats">
<div class="stat-card">
<div class="stat-icon">🔗</div>
<div class="stat-info">
<div class="stat-value">{{ data.activeConnections }}</div>
<div class="stat-label">活跃连接</div>
</div>
</div>
<!-- 应用列表 -->
<div class="app-list">
<div
v-for="app in applications"
:key="app.id"
class="app-item"
:class="{ 'app-item--selected': selectedApp?.id === app.id }"
@click="selectApp(app)"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
>
<!-- 书角折叠效果 -->
<div v-if="selectedApp?.id === app.id" class="folded-corner"></div>
<div class="stat-card">
<div class="stat-icon">⚡</div>
<div class="stat-info">
<div class="stat-value">{{ data.networkSpeed }}</div>
<div class="stat-label">网络速度</div>
<!-- 应用图标 -->
<div class="app-icon">
<img :src="app.icon" :alt="app.name" />
</div>
</div>
<div class="stat-card">
<div class="stat-icon">🛡️</div>
<div class="stat-info">
<div class="stat-value">{{ data.ruleCount }}</div>
<div class="stat-label">防护规则</div>
<!-- 应用信息 -->
<div class="app-info">
<div class="app-name">{{ app.name }}</div>
<div class="app-details">
<span class="app-detail">PID: {{ app.pid }}</span>
<span class="app-detail">内存: {{ app.memory }}</span>
<span class="app-detail">{{ app.status }}</span>
</div>
</div>
<!-- 应用状态指示器 -->
<div class="app-status">
<div class="status-indicator" :class="`status-${app.statusType}`"></div>
</div>
</div>
</div>
<div class="sidebar-section">
<h4 class="section-title">快速操作</h4>
<div class="quick-actions">
<div class="action-item" @click="handleAction('scan')">扫描威胁</div>
<div class="action-item" @click="handleAction('update')">更新规则</div>
<div class="action-item" @click="handleAction('export')">导出日志</div>
</div>
</div>
<div class="sidebar-section">
<h4 class="section-title">系统状态</h4>
<div class="system-status">
<div class="status-item">
<span class="status-dot active"></span>
<span class="status-label">防护已启用</span>
</div>
<div class="status-item">
<span class="status-dot active"></span>
<span class="status-label">实时监控中</span>
</div>
<div class="status-item">
<span class="status-dot warning"></span>
<span class="status-label">待处理警告: 3</span>
</div>
</div>
<!-- 空状态 -->
<div v-if="applications.length === 0" class="empty-state">
<n-icon :component="DesktopOutline" size="48" class="empty-icon" />
<div class="empty-title">暂无运行的应用</div>
<div class="empty-subtitle">系统中没有检测到正在运行的应用程序</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue'
import { ref, defineEmits, defineProps } from 'vue'
import { NIcon } from 'naive-ui'
import { CheckmarkOutline, DesktopOutline } from '@vicons/ionicons5'
import { httpClient } from '@/utils/http.ts'
import { ResponseModel } from '@/types/response'
// 定义应用数据类型
interface Application {
id: string
name: string
icon: string
pid: number
memory: string
status: string
statusType: 'active' | 'idle' | 'background'
path?: string
windowTitle?: string
cpuUsage?: number
}
// 事件定义
const emit = defineEmits<{
'app-selected': [app: Application | null]
}>()
// 发送请求
httpClient.post(`/subscribe`, '发送的测试例子').then((res:ResponseModel) => {
console.log(res)
})
// 选中的应用
const selectedApp = ref<Application | null>(null)
// 模拟应用数据
const applications = ref<Application[]>([
{
id: '1',
name: 'Visual Studio Code',
icon: 'https://code.visualstudio.com/assets/images/code-stable.png',
pid: 12456,
memory: '245.6 MB',
status: '活跃',
statusType: 'active',
path: '/Applications/Visual Studio Code.app',
windowTitle: 'main.js - myproject',
cpuUsage: 5.2,
},
{
id: '2',
name: 'Google Chrome',
icon: 'https://upload.wikimedia.org/wikipedia/commons/e/e1/Google_Chrome_icon_%28February_2022%29.svg',
pid: 8923,
memory: '512.3 MB',
status: '活跃',
statusType: 'active',
path: '/Applications/Google Chrome.app',
windowTitle: 'GitHub - Dashboard',
cpuUsage: 12.8,
},
{
id: '3',
name: 'Spotify',
icon: 'https://upload.wikimedia.org/wikipedia/commons/1/19/Spotify_logo_without_text.svg',
pid: 5647,
memory: '156.7 MB',
status: '后台运行',
statusType: 'background',
path: '/Applications/Spotify.app',
windowTitle: 'Spotify Premium',
cpuUsage: 2.1,
},
{
id: '4',
name: 'Finder',
icon: 'https://upload.wikimedia.org/wikipedia/en/f/f4/MacOS_Finder_Icon.png',
pid: 1234,
memory: '89.2 MB',
status: '空闲',
statusType: 'idle',
path: '/System/Library/CoreServices/Finder.app',
windowTitle: 'Documents',
cpuUsage: 0.8,
},
{
id: '5',
name: 'Slack',
icon: 'https://a.slack-edge.com/80588/marketing/img/icons/icon_slack_hash_colored.svg',
pid: 9876,
memory: '198.4 MB',
status: '活跃',
statusType: 'active',
path: '/Applications/Slack.app',
windowTitle: 'Slack - workspace',
cpuUsage: 3.7,
},
])
// 选择应用
const selectApp = (app: Application) => {
selectedApp.value = app
emit('app-selected', app)
}
// 鼠标悬停事件
const handleMouseEnter = () => {
// 可以在这里添加额外的悬停逻辑
}
const handleMouseLeave = () => {
// 可以在这里添加额外的离开逻辑
}
// 暴露方法给父组件
defineExpose({
clearSelection: () => {
selectedApp.value = null
emit('app-selected', null)
},
selectById: (id: string) => {
const app = applications.value.find((a) => a.id === id)
if (app) {
selectApp(app)
}
},
})
// Props
const props = defineProps<{
width: number
data: {
activeConnections: number
processCount: number
networkSpeed: string
ruleCount: number
}
}>()
// Emits
const emit = defineEmits<{
action: [type: string]
}>()
// 模拟数据
const data = {
activeConnections: 247,
processCount: 43,
networkSpeed: '5.2 MB/s',
ruleCount: 156,
}
// 处理快速操作
const handleAction = (type: string) => {
@@ -89,10 +210,401 @@ const handleAction = (type: string) => {
</script>
<style scoped>
/* 书角折叠效果 - 平衡版 */
.folded-corner {
position: absolute;
top: 0;
right: 0;
width: 0;
height: 0;
border-left: 30px solid transparent;
border-top: 30px solid var(--accent-primary);
z-index: 10;
animation: foldIn 0.3s ease-out;
filter: drop-shadow(1px 1px 3px rgba(0, 0, 0, 0.15));
}
.folded-corner::before {
content: '';
position: absolute;
top: -30px;
right: -30px;
width: 0;
height: 0;
border-left: 30px solid var(--accent-primary);
border-top: 30px solid transparent;
transform: rotate(90deg);
transform-origin: 0 0;
filter: brightness(0.85);
}
.folded-corner::after {
content: '';
position: absolute;
top: -22px;
right: -22px;
width: 0;
height: 0;
border-left: 22px solid rgba(0, 0, 0, 0.12);
border-top: 22px solid transparent;
transform: rotate(45deg);
transform-origin: 0 0;
}
/* 书角的轻微发光效果 */
.app-item--selected .folded-corner {
animation:
foldIn 0.3s ease-out,
cornerGlow 4s ease-in-out infinite alternate;
}
@keyframes foldIn {
0% {
transform: scale(0.7) rotate(-15deg);
opacity: 0;
}
60% {
transform: scale(1.05) rotate(-3deg);
opacity: 0.9;
}
100% {
transform: scale(1) rotate(0deg);
opacity: 1;
}
}
@keyframes cornerGlow {
0% {
filter: drop-shadow(1px 1px 3px rgba(0, 0, 0, 0.15));
}
100% {
filter: drop-shadow(1px 1px 3px rgba(0, 0, 0, 0.15))
drop-shadow(0 0 8px rgba(59, 130, 246, 0.4));
}
}
.app-list-view {
height: 100%;
background: var(--bg-secondary);
}
.app-list-container {
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
/* 头部 */
.list-header {
margin-bottom: 20px;
}
.list-title {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
margin: 0 0 4px 0;
}
.list-subtitle {
font-size: 14px;
color: var(--text-muted);
}
/* 应用列表 */
.app-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.app-item {
background: var(--bg-card);
backdrop-filter: var(--backdrop-blur);
border: 1px solid var(--border-primary);
border-radius: 12px;
padding: 16px;
display: flex;
align-items: center;
gap: 16px;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
overflow: hidden;
}
.app-item:hover {
transform: translateY(-1px);
border-color: var(--border-hover);
background: var(--bg-hover, var(--bg-card));
box-shadow: var(--shadow-md);
}
.app-item--selected {
border: 1px solid var(--accent-primary);
background: var(--monitor-bg-card-selected);
box-shadow:
0 0 0 4px var(--monitor-accent-primary-alpha),
0 8px 25px -5px rgba(59, 130, 246, 0.3);
transform: translateY(-1px) scale(1.02);
position: relative;
z-index: 5;
}
/* 选中元素的左侧强调边框 */
.app-item--selected::before {
content: '';
position: absolute;
left: -2px;
top: -2px;
bottom: -2px;
width: 6px;
background: linear-gradient(
to bottom,
var(--accent-primary) 0%,
#1d4ed8 50%,
var(--accent-primary) 100%
);
border-radius: 6px 0 0 6px;
z-index: 1;
}
/* 应用图标 */
.app-icon {
width: 48px;
height: 48px;
border-radius: 10px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: var(--bg-tertiary);
flex-shrink: 0;
}
.app-icon img {
width: 32px;
height: 32px;
object-fit: contain;
}
/* 应用信息 */
.app-info {
flex: 1;
min-width: 0;
}
.app-name {
font-size: 15px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.app-details {
display: flex;
align-items: center;
gap: 12px;
font-size: 12px;
color: var(--text-muted);
}
.app-detail {
display: flex;
align-items: center;
gap: 4px;
white-space: nowrap;
}
/* 状态指示器 */
.app-status {
display: flex;
align-items: center;
}
.status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
position: relative;
}
.status-indicator::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
border-radius: 50%;
opacity: 0.3;
animation: pulse 2s infinite;
}
.status-active {
background: var(--accent-success);
}
.status-active::before {
background: var(--accent-success);
}
.status-background {
background: var(--accent-warning);
}
.status-background::before {
background: var(--accent-warning);
}
.status-idle {
background: var(--text-quaternary);
}
.status-idle::before {
background: var(--text-quaternary);
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 60px 20px;
}
.empty-icon {
color: var(--text-quaternary);
margin-bottom: 16px;
}
.empty-title {
font-size: 16px;
font-weight: 600;
color: var(--text-secondary);
margin-bottom: 8px;
}
.empty-subtitle {
font-size: 14px;
color: var(--text-muted);
}
/* 动画 */
@keyframes pulse {
0%,
100% {
opacity: 0.3;
transform: scale(1);
}
50% {
opacity: 0.8;
transform: scale(1.2);
}
}
@keyframes bounceIn {
0% {
opacity: 0;
transform: scale(0.3);
}
50% {
transform: scale(1.1);
}
100% {
opacity: 1;
transform: scale(1);
}
}
/* 响应式 */
@media (max-width: 768px) {
.app-item {
padding: 12px;
}
.app-icon {
width: 40px;
height: 40px;
}
.app-icon img {
width: 28px;
height: 28px;
}
.app-details {
flex-direction: column;
align-items: flex-start;
gap: 4px;
}
.folded-corner {
border-left-width: 24px;
border-top-width: 24px;
}
.folded-corner::before {
border-left-width: 24px;
border-top-width: 24px;
top: -24px;
right: -24px;
}
.folded-corner::after {
border-left-width: 18px;
border-top-width: 18px;
top: -18px;
right: -18px;
}
}
/* CSS变量定义 */
:root {
--monitor-bg-card-selected: rgba(59, 130, 246, 0.08);
--monitor-accent-primary-alpha: rgba(59, 130, 246, 0.2);
--accent-primary: #3b82f6;
--accent-success: #10b981;
--accent-warning: #f59e0b;
--bg-card: #ffffff;
--bg-hover: #f8fafc;
--bg-tertiary: #f8fafc;
--border-primary: #e2e8f0;
--border-hover: #cbd5e1;
--text-primary: #1e293b;
--text-secondary: #475569;
--text-muted: #64748b;
--text-quaternary: #94a3b8;
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
/* 深色模式适配 */
@media (prefers-color-scheme: dark) {
:root {
--monitor-bg-card-selected: rgba(59, 130, 246, 0.12);
--monitor-accent-primary-alpha: rgba(59, 130, 246, 0.25);
--bg-card: #1e293b;
--bg-hover: #334155;
--bg-tertiary: #334155;
--border-primary: #475569;
--border-hover: #64748b;
--text-primary: #f1f5f9;
--text-secondary: #e2e8f0;
--text-muted: #cbd5e1;
--text-quaternary: #94a3b8;
}
.folded-corner::after {
border-left-color: rgba(255, 255, 255, 0.08);
}
}
/* 侧边栏容器 */
.sidebar {
background: var(--bg-glass);
backdrop-filter: var(--backdrop-blur);
background: var(--bg-glass, var(--bg-card));
backdrop-filter: var(--backdrop-blur, blur(10px));
border-right: 1px solid var(--border-primary);
overflow: hidden;
display: flex;
@@ -138,114 +650,4 @@ const handleAction = (type: string) => {
gap: 12px;
margin-bottom: 24px;
}
.stat-card {
background: var(--bg-card);
border: 1px solid var(--border-tertiary);
border-radius: 12px;
padding: 16px;
display: flex;
align-items: center;
gap: 12px;
transition: var(--transition);
}
.stat-card:hover {
background: var(--bg-hover);
border-color: var(--border-hover);
transform: translateY(-1px);
}
.stat-icon {
font-size: 20px;
width: 32px;
text-align: center;
}
.stat-info {
flex: 1;
}
.stat-value {
font-size: 18px;
font-weight: 700;
color: var(--text-secondary);
line-height: 1;
}
.stat-label {
font-size: 12px;
color: var(--text-muted);
margin-top: 2px;
}
/* 侧边栏区块 */
.sidebar-section {
margin-top: 24px;
}
.section-title {
font-size: 14px;
font-weight: 600;
color: var(--text-quaternary);
margin-bottom: 12px;
}
/* 快速操作 */
.quick-actions {
display: flex;
flex-direction: column;
gap: 8px;
}
.action-item {
padding: 8px 12px;
background: var(--bg-tertiary);
border-radius: 8px;
font-size: 13px;
color: var(--text-quaternary);
cursor: pointer;
transition: var(--transition);
}
.action-item:hover {
background: var(--bg-hover);
color: var(--text-secondary);
}
/* 系统状态 */
.system-status {
display: flex;
flex-direction: column;
gap: 10px;
}
.status-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--text-tertiary);
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--text-disabled);
}
.status-dot.active {
background: var(--accent-success);
box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2);
}
.status-dot.warning {
background: var(--accent-warning);
box-shadow: 0 0 0 2px rgba(251, 146, 60, 0.2);
}
.status-label {
flex: 1;
}
</style>
@@ -3,7 +3,7 @@
<!-- 主内容区域 - 可拖拽布局 -->
<div class="main-content">
<!-- 左侧边栏 -->
<MonitorSidebar :width="sidebarWidth" :data="mockData" />
<MonitorSidebar :width="sidebarWidth" />
<!-- 左侧分割线 -->
<div class="resize-handle-vertical" @mousedown="startResize('sidebar', $event)">
@@ -49,7 +49,7 @@ import MonitorMainPanel from './MonitorMainPanel.vue'
import MonitorInspector from './MonitorInspector.vue'
// 布局尺寸控制
const sidebarWidth = ref(300)
const sidebarWidth = ref(400)
const inspectorWidth = ref(350)
const timelineHeight = ref(500)
const mainHeaderHeight = ref(80)
@@ -66,14 +66,6 @@ const MAX_TIMELINE_HEIGHT = 800
const searchQuery = ref('')
const selectedConnection = ref<any>(null)
// 模拟数据
const mockData = ref({
activeConnections: 247,
processCount: 43,
networkSpeed: '5.2 MB/s',
ruleCount: 156,
})
const mockConnections = ref([
{
id: 1,