diff --git a/server-status-web/.env b/server-status-web/.env
new file mode 100644
index 0000000..e69de29
diff --git a/server-status-web/.env.dev b/server-status-web/.env.dev
new file mode 100644
index 0000000..5a6afce
--- /dev/null
+++ b/server-status-web/.env.dev
@@ -0,0 +1 @@
+VITE_API_ROOT=https://status.liteyuki.icu
\ No newline at end of file
diff --git a/server-status-web/.env.prod b/server-status-web/.env.prod
new file mode 100644
index 0000000..6534684
--- /dev/null
+++ b/server-status-web/.env.prod
@@ -0,0 +1 @@
+VITE_API_ROOT=""
\ No newline at end of file
diff --git a/server-status-web/.gitignore b/server-status-web/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/server-status-web/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/server-status-web/LICENSE b/server-status-web/LICENSE
new file mode 100644
index 0000000..b6d0f30
--- /dev/null
+++ b/server-status-web/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Snowykami
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/server-status-web/README.md b/server-status-web/README.md
new file mode 100644
index 0000000..bf95ff6
--- /dev/null
+++ b/server-status-web/README.md
@@ -0,0 +1,3 @@
+# 服务器监控面板前端源码
+
+![]
\ No newline at end of file
diff --git a/server-status-web/index.html b/server-status-web/index.html
new file mode 100644
index 0000000..efb830f
--- /dev/null
+++ b/server-status-web/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ Server Status
+
+
+
+
+
+
+
+
diff --git a/server-status-web/package-lock.json b/server-status-web/package-lock.json
new file mode 100644
index 0000000..247464b
--- /dev/null
+++ b/server-status-web/package-lock.json
@@ -0,0 +1,727 @@
+{
+ "name": "server-status",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "server-status",
+ "version": "0.0.0",
+ "dependencies": {
+ "echarts": "^5.5.1",
+ "html2canvas": "^1.4.1",
+ "pnpm": "^9.12.0",
+ "vue": "^3.4.37",
+ "vue-router": "^4.4.5"
+ },
+ "devDependencies": {
+ "@types/node": "^22.7.4",
+ "@vitejs/plugin-vue": "^5.1.2",
+ "sax": "^1.4.1",
+ "typescript": "^5.5.3",
+ "vite": "^5.4.1",
+ "vue-tsc": "^2.0.29"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.25.7",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.25.7",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.25.7",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.25.7"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.25.7",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.25.7",
+ "@babel/helper-validator-identifier": "^7.25.7",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.21.5",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.24.0",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.6",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "22.7.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz",
+ "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.19.2"
+ }
+ },
+ "node_modules/@vitejs/plugin-vue": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.4.tgz",
+ "integrity": "sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0",
+ "vue": "^3.2.25"
+ }
+ },
+ "node_modules/@volar/language-core": {
+ "version": "2.4.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/source-map": "2.4.5"
+ }
+ },
+ "node_modules/@volar/source-map": {
+ "version": "2.4.5",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@volar/typescript": {
+ "version": "2.4.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "2.4.5",
+ "path-browserify": "^1.0.1",
+ "vscode-uri": "^3.0.8"
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.5.11",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.3",
+ "@vue/shared": "3.5.11",
+ "entities": "^4.5.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.5.11",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-core": "3.5.11",
+ "@vue/shared": "3.5.11"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.5.11",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.3",
+ "@vue/compiler-core": "3.5.11",
+ "@vue/compiler-dom": "3.5.11",
+ "@vue/compiler-ssr": "3.5.11",
+ "@vue/shared": "3.5.11",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.11",
+ "postcss": "^8.4.47",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-ssr": {
+ "version": "3.5.11",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.11",
+ "@vue/shared": "3.5.11"
+ }
+ },
+ "node_modules/@vue/compiler-vue2": {
+ "version": "2.7.16",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "de-indent": "^1.0.2",
+ "he": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/devtools-api": {
+ "version": "6.6.4",
+ "license": "MIT"
+ },
+ "node_modules/@vue/language-core": {
+ "version": "2.1.6",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "~2.4.1",
+ "@vue/compiler-dom": "^3.4.0",
+ "@vue/compiler-vue2": "^2.7.16",
+ "@vue/shared": "^3.4.0",
+ "computeds": "^0.0.1",
+ "minimatch": "^9.0.3",
+ "muggle-string": "^0.4.1",
+ "path-browserify": "^1.0.1"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.5.11",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/shared": "3.5.11"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.5.11",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.11",
+ "@vue/shared": "3.5.11"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.5.11",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.11",
+ "@vue/runtime-core": "3.5.11",
+ "@vue/shared": "3.5.11",
+ "csstype": "^3.1.3"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.5.11",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-ssr": "3.5.11",
+ "@vue/shared": "3.5.11"
+ },
+ "peerDependencies": {
+ "vue": "3.5.11"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.5.11",
+ "license": "MIT"
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/base64-arraybuffer": {
+ "version": "1.0.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/computeds": {
+ "version": "0.0.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/css-line-break": {
+ "version": "2.1.0",
+ "license": "MIT",
+ "dependencies": {
+ "utrie": "^1.0.2"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "license": "MIT"
+ },
+ "node_modules/de-indent": {
+ "version": "1.0.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/echarts": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.5.1.tgz",
+ "integrity": "sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "2.3.0",
+ "zrender": "5.6.0"
+ }
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.21.5",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "license": "MIT"
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "node_modules/html2canvas": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+ "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+ "license": "MIT",
+ "dependencies": {
+ "css-line-break": "^2.1.0",
+ "text-segmentation": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.11",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "9.0.5",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/muggle-string": {
+ "version": "0.4.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.7",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/path-browserify": {
+ "version": "1.0.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.0",
+ "license": "ISC"
+ },
+ "node_modules/pnpm": {
+ "version": "9.12.0",
+ "resolved": "https://registry.npmjs.org/pnpm/-/pnpm-9.12.0.tgz",
+ "integrity": "sha512-Sr9yUITXvLr71yi/x77mHy95H5d/2HVCs1edyyNQTRcNRjN5ReTGZIXNEtWIoMDlcO2cR358zdhQfPBfP5Lqyg==",
+ "license": "MIT",
+ "bin": {
+ "pnpm": "bin/pnpm.cjs",
+ "pnpx": "bin/pnpx.cjs"
+ },
+ "engines": {
+ "node": ">=18.12"
+ },
+ "funding": {
+ "url": "https://opencollective.com/pnpm"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.47",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.1.0",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.24.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.6"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.24.0",
+ "@rollup/rollup-android-arm64": "4.24.0",
+ "@rollup/rollup-darwin-arm64": "4.24.0",
+ "@rollup/rollup-darwin-x64": "4.24.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.24.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.24.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.24.0",
+ "@rollup/rollup-linux-arm64-musl": "4.24.0",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.24.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.24.0",
+ "@rollup/rollup-linux-x64-gnu": "4.24.0",
+ "@rollup/rollup-linux-x64-musl": "4.24.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.24.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.24.0",
+ "@rollup/rollup-win32-x64-msvc": "4.24.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/sax": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+ "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/semver": {
+ "version": "7.6.3",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/text-segmentation": {
+ "version": "1.0.3",
+ "license": "MIT",
+ "dependencies": {
+ "utrie": "^1.0.2"
+ }
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.3.0",
+ "license": "0BSD"
+ },
+ "node_modules/typescript": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
+ "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.19.8",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/utrie": {
+ "version": "1.0.2",
+ "license": "MIT",
+ "dependencies": {
+ "base64-arraybuffer": "^1.0.2"
+ }
+ },
+ "node_modules/vite": {
+ "version": "5.4.8",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
+ "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vscode-uri": {
+ "version": "3.0.8",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vue": {
+ "version": "3.5.11",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.11.tgz",
+ "integrity": "sha512-/8Wurrd9J3lb72FTQS7gRMNQD4nztTtKPmuDuPuhqXmmpD6+skVjAeahNpVzsuky6Sy9gy7wn8UadqPtt9SQIg==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.11",
+ "@vue/compiler-sfc": "3.5.11",
+ "@vue/runtime-dom": "3.5.11",
+ "@vue/server-renderer": "3.5.11",
+ "@vue/shared": "3.5.11"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue-router": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.5.tgz",
+ "integrity": "sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "vue": "^3.2.0"
+ }
+ },
+ "node_modules/vue-tsc": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.1.6.tgz",
+ "integrity": "sha512-f98dyZp5FOukcYmbFpuSCJ4Z0vHSOSmxGttZJCsFeX0M4w/Rsq0s4uKXjcSRsZqsRgQa6z7SfuO+y0HVICE57Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/typescript": "~2.4.1",
+ "@vue/language-core": "2.1.6",
+ "semver": "^7.5.4"
+ },
+ "bin": {
+ "vue-tsc": "bin/vue-tsc.js"
+ },
+ "peerDependencies": {
+ "typescript": ">=5.0.0"
+ }
+ },
+ "node_modules/zrender": {
+ "version": "5.6.0",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tslib": "2.3.0"
+ }
+ }
+ }
+}
diff --git a/server-status-web/package.json b/server-status-web/package.json
new file mode 100644
index 0000000..e9ec4ca
--- /dev/null
+++ b/server-status-web/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "server-status",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite --mode dev --host",
+ "build": "vue-tsc -b && vite build --mode prod",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "echarts": "^5.5.1",
+ "html2canvas": "^1.4.1",
+ "pnpm": "^9.12.0",
+ "vue": "^3.4.37",
+ "vue-router": "^4.4.5"
+ },
+ "devDependencies": {
+ "@types/node": "^22.7.4",
+ "@vitejs/plugin-vue": "^5.1.2",
+ "sax": "^1.4.1",
+ "typescript": "^5.5.3",
+ "vite": "^5.4.1",
+ "vue-tsc": "^2.0.29"
+ }
+}
diff --git a/server-status-web/pnpm-lock.yaml b/server-status-web/pnpm-lock.yaml
new file mode 100644
index 0000000..a9bcab3
--- /dev/null
+++ b/server-status-web/pnpm-lock.yaml
@@ -0,0 +1,833 @@
+lockfileVersion: '6.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+dependencies:
+ echarts:
+ specifier: ^5.5.1
+ version: 5.5.1
+ html2canvas:
+ specifier: ^1.4.1
+ version: 1.4.1
+ vue:
+ specifier: ^3.4.37
+ version: 3.5.10(typescript@5.6.2)
+ vue-router:
+ specifier: ^4.4.5
+ version: 4.4.5(vue@3.5.10)
+
+devDependencies:
+ '@types/node':
+ specifier: ^22.7.4
+ version: 22.7.4
+ '@vitejs/plugin-vue':
+ specifier: ^5.1.2
+ version: 5.1.4(vite@5.4.8)(vue@3.5.10)
+ sax:
+ specifier: ^1.4.1
+ version: 1.4.1
+ typescript:
+ specifier: ^5.5.3
+ version: 5.6.2
+ vite:
+ specifier: ^5.4.1
+ version: 5.4.8(@types/node@22.7.4)
+ vue-tsc:
+ specifier: ^2.0.29
+ version: 2.1.6(typescript@5.6.2)
+
+packages:
+
+ /@babel/helper-string-parser@7.24.8:
+ resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==}
+ engines: {node: '>=6.9.0'}
+
+ /@babel/helper-validator-identifier@7.24.7:
+ resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==}
+ engines: {node: '>=6.9.0'}
+
+ /@babel/parser@7.25.6:
+ resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+ dependencies:
+ '@babel/types': 7.25.6
+
+ /@babel/types@7.25.6:
+ resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-string-parser': 7.24.8
+ '@babel/helper-validator-identifier': 7.24.7
+ to-fast-properties: 2.0.0
+
+ /@esbuild/aix-ppc64@0.21.5:
+ resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-arm64@0.21.5:
+ resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-arm@0.21.5:
+ resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-x64@0.21.5:
+ resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/darwin-arm64@0.21.5:
+ resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/darwin-x64@0.21.5:
+ resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/freebsd-arm64@0.21.5:
+ resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/freebsd-x64@0.21.5:
+ resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-arm64@0.21.5:
+ resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-arm@0.21.5:
+ resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-ia32@0.21.5:
+ resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-loong64@0.21.5:
+ resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-mips64el@0.21.5:
+ resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-ppc64@0.21.5:
+ resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-riscv64@0.21.5:
+ resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-s390x@0.21.5:
+ resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-x64@0.21.5:
+ resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/netbsd-x64@0.21.5:
+ resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/openbsd-x64@0.21.5:
+ resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/sunos-x64@0.21.5:
+ resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-arm64@0.21.5:
+ resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-ia32@0.21.5:
+ resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-x64@0.21.5:
+ resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@jridgewell/sourcemap-codec@1.5.0:
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+
+ /@rollup/rollup-android-arm-eabi@4.23.0:
+ resolution: {integrity: sha512-8OR+Ok3SGEMsAZispLx8jruuXw0HVF16k+ub2eNXKHDmdxL4cf9NlNpAzhlOhNyXzKDEJuFeq0nZm+XlNb1IFw==}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-android-arm64@4.23.0:
+ resolution: {integrity: sha512-rEFtX1nP8gqmLmPZsXRMoLVNB5JBwOzIAk/XAcEPuKrPa2nPJ+DuGGpfQUR0XjRm8KjHfTZLpWbKXkA5BoFL3w==}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-darwin-arm64@4.23.0:
+ resolution: {integrity: sha512-ZbqlMkJRMMPeapfaU4drYHns7Q5MIxjM/QeOO62qQZGPh9XWziap+NF9fsqPHT0KzEL6HaPspC7sOwpgyA3J9g==}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-darwin-x64@4.23.0:
+ resolution: {integrity: sha512-PfmgQp78xx5rBCgn2oYPQ1rQTtOaQCna0kRaBlc5w7RlA3TDGGo7m3XaptgitUZ54US9915i7KeVPHoy3/W8tA==}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-arm-gnueabihf@4.23.0:
+ resolution: {integrity: sha512-WAeZfAAPus56eQgBioezXRRzArAjWJGjNo/M+BHZygUcs9EePIuGI1Wfc6U/Ki+tMW17FFGvhCfYnfcKPh18SA==}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-arm-musleabihf@4.23.0:
+ resolution: {integrity: sha512-v7PGcp1O5XKZxKX8phTXtmJDVpE20Ub1eF6w9iMmI3qrrPak6yR9/5eeq7ziLMrMTjppkkskXyxnmm00HdtXjA==}
+ cpu: [arm]
+ os: [linux]
+ libc: [musl]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-arm64-gnu@4.23.0:
+ resolution: {integrity: sha512-nAbWsDZ9UkU6xQiXEyXBNHAKbzSAi95H3gTStJq9UGiS1v+YVXwRHcQOQEF/3CHuhX5BVhShKoeOf6Q/1M+Zhg==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-arm64-musl@4.23.0:
+ resolution: {integrity: sha512-5QT/Di5FbGNPaVw8hHO1wETunwkPuZBIu6W+5GNArlKHD9fkMHy7vS8zGHJk38oObXfWdsuLMogD4sBySLJ54g==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-powerpc64le-gnu@4.23.0:
+ resolution: {integrity: sha512-Sefl6vPyn5axzCsO13r1sHLcmPuiSOrKIImnq34CBurntcJ+lkQgAaTt/9JkgGmaZJ+OkaHmAJl4Bfd0DmdtOQ==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-riscv64-gnu@4.23.0:
+ resolution: {integrity: sha512-o4QI2KU/QbP7ZExMse6ULotdV3oJUYMrdx3rBZCgUF3ur3gJPfe8Fuasn6tia16c5kZBBw0aTmaUygad6VB/hQ==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-s390x-gnu@4.23.0:
+ resolution: {integrity: sha512-+bxqx+V/D4FGrpXzPGKp/SEZIZ8cIW3K7wOtcJAoCrmXvzRtmdUhYNbgd+RztLzfDEfA2WtKj5F4tcbNPuqgeg==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-x64-gnu@4.23.0:
+ resolution: {integrity: sha512-I/eXsdVoCKtSgK9OwyQKPAfricWKUMNCwJKtatRYMmDo5N859tbO3UsBw5kT3dU1n6ZcM1JDzPRSGhAUkxfLxw==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-x64-musl@4.23.0:
+ resolution: {integrity: sha512-4ZoDZy5ShLbbe1KPSafbFh1vbl0asTVfkABC7eWqIs01+66ncM82YJxV2VtV3YVJTqq2P8HMx3DCoRSWB/N3rw==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-win32-arm64-msvc@4.23.0:
+ resolution: {integrity: sha512-+5Ky8dhft4STaOEbZu3/NU4QIyYssKO+r1cD3FzuusA0vO5gso15on7qGzKdNXnc1gOrsgCqZjRw1w+zL4y4hQ==}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-win32-ia32-msvc@4.23.0:
+ resolution: {integrity: sha512-0SPJk4cPZQhq9qA1UhIRumSE3+JJIBBjtlGl5PNC///BoaByckNZd53rOYD0glpTkYFBQSt7AkMeLVPfx65+BQ==}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-win32-x64-msvc@4.23.0:
+ resolution: {integrity: sha512-lqCK5GQC8fNo0+JvTSxcG7YB1UKYp8yrNLhsArlvPWN+16ovSZgoehlVHg6X0sSWPUkpjRBR5TuR12ZugowZ4g==}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@types/estree@1.0.6:
+ resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
+ dev: true
+
+ /@types/node@22.7.4:
+ resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==}
+ dependencies:
+ undici-types: 6.19.8
+ dev: true
+
+ /@vitejs/plugin-vue@5.1.4(vite@5.4.8)(vue@3.5.10):
+ resolution: {integrity: sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ peerDependencies:
+ vite: ^5.0.0
+ vue: ^3.2.25
+ dependencies:
+ vite: 5.4.8(@types/node@22.7.4)
+ vue: 3.5.10(typescript@5.6.2)
+ dev: true
+
+ /@volar/language-core@2.4.5:
+ resolution: {integrity: sha512-F4tA0DCO5Q1F5mScHmca0umsi2ufKULAnMOVBfMsZdT4myhVl4WdKRwCaKcfOkIEuyrAVvtq1ESBdZ+rSyLVww==}
+ dependencies:
+ '@volar/source-map': 2.4.5
+ dev: true
+
+ /@volar/source-map@2.4.5:
+ resolution: {integrity: sha512-varwD7RaKE2J/Z+Zu6j3mNNJbNT394qIxXwdvz/4ao/vxOfyClZpSDtLKkwWmecinkOVos5+PWkWraelfMLfpw==}
+ dev: true
+
+ /@volar/typescript@2.4.5:
+ resolution: {integrity: sha512-mcT1mHvLljAEtHviVcBuOyAwwMKz1ibXTi5uYtP/pf4XxoAzpdkQ+Br2IC0NPCvLCbjPZmbf3I0udndkfB1CDg==}
+ dependencies:
+ '@volar/language-core': 2.4.5
+ path-browserify: 1.0.1
+ vscode-uri: 3.0.8
+ dev: true
+
+ /@vue/compiler-core@3.5.10:
+ resolution: {integrity: sha512-iXWlk+Cg/ag7gLvY0SfVucU8Kh2CjysYZjhhP70w9qI4MvSox4frrP+vDGvtQuzIcgD8+sxM6lZvCtdxGunTAA==}
+ dependencies:
+ '@babel/parser': 7.25.6
+ '@vue/shared': 3.5.10
+ entities: 4.5.0
+ estree-walker: 2.0.2
+ source-map-js: 1.2.1
+
+ /@vue/compiler-dom@3.5.10:
+ resolution: {integrity: sha512-DyxHC6qPcktwYGKOIy3XqnHRrrXyWR2u91AjP+nLkADko380srsC2DC3s7Y1Rk6YfOlxOlvEQKa9XXmLI+W4ZA==}
+ dependencies:
+ '@vue/compiler-core': 3.5.10
+ '@vue/shared': 3.5.10
+
+ /@vue/compiler-sfc@3.5.10:
+ resolution: {integrity: sha512-to8E1BgpakV7224ZCm8gz1ZRSyjNCAWEplwFMWKlzCdP9DkMKhRRwt0WkCjY7jkzi/Vz3xgbpeig5Pnbly4Tow==}
+ dependencies:
+ '@babel/parser': 7.25.6
+ '@vue/compiler-core': 3.5.10
+ '@vue/compiler-dom': 3.5.10
+ '@vue/compiler-ssr': 3.5.10
+ '@vue/shared': 3.5.10
+ estree-walker: 2.0.2
+ magic-string: 0.30.11
+ postcss: 8.4.47
+ source-map-js: 1.2.1
+
+ /@vue/compiler-ssr@3.5.10:
+ resolution: {integrity: sha512-hxP4Y3KImqdtyUKXDRSxKSRkSm1H9fCvhojEYrnaoWhE4w/y8vwWhnosJoPPe2AXm5sU7CSbYYAgkt2ZPhDz+A==}
+ dependencies:
+ '@vue/compiler-dom': 3.5.10
+ '@vue/shared': 3.5.10
+
+ /@vue/compiler-vue2@2.7.16:
+ resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==}
+ dependencies:
+ de-indent: 1.0.2
+ he: 1.2.0
+ dev: true
+
+ /@vue/devtools-api@6.6.4:
+ resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
+ dev: false
+
+ /@vue/language-core@2.1.6(typescript@5.6.2):
+ resolution: {integrity: sha512-MW569cSky9R/ooKMh6xa2g1D0AtRKbL56k83dzus/bx//RDJk24RHWkMzbAlXjMdDNyxAaagKPRquBIxkxlCkg==}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@volar/language-core': 2.4.5
+ '@vue/compiler-dom': 3.5.10
+ '@vue/compiler-vue2': 2.7.16
+ '@vue/shared': 3.5.10
+ computeds: 0.0.1
+ minimatch: 9.0.5
+ muggle-string: 0.4.1
+ path-browserify: 1.0.1
+ typescript: 5.6.2
+ dev: true
+
+ /@vue/reactivity@3.5.10:
+ resolution: {integrity: sha512-kW08v06F6xPSHhid9DJ9YjOGmwNDOsJJQk0ax21wKaUYzzuJGEuoKNU2Ujux8FLMrP7CFJJKsHhXN9l2WOVi2g==}
+ dependencies:
+ '@vue/shared': 3.5.10
+
+ /@vue/runtime-core@3.5.10:
+ resolution: {integrity: sha512-9Q86I5Qq3swSkFfzrZ+iqEy7Vla325M7S7xc1NwKnRm/qoi1Dauz0rT6mTMmscqx4qz0EDJ1wjB+A36k7rl8mA==}
+ dependencies:
+ '@vue/reactivity': 3.5.10
+ '@vue/shared': 3.5.10
+
+ /@vue/runtime-dom@3.5.10:
+ resolution: {integrity: sha512-t3x7ht5qF8ZRi1H4fZqFzyY2j+GTMTDxRheT+i8M9Ph0oepUxoadmbwlFwMoW7RYCpNQLpP2Yx3feKs+fyBdpA==}
+ dependencies:
+ '@vue/reactivity': 3.5.10
+ '@vue/runtime-core': 3.5.10
+ '@vue/shared': 3.5.10
+ csstype: 3.1.3
+
+ /@vue/server-renderer@3.5.10(vue@3.5.10):
+ resolution: {integrity: sha512-IVE97tt2kGKwHNq9yVO0xdh1IvYfZCShvDSy46JIh5OQxP1/EXSpoDqetVmyIzL7CYOWnnmMkVqd7YK2QSWkdw==}
+ peerDependencies:
+ vue: 3.5.10
+ dependencies:
+ '@vue/compiler-ssr': 3.5.10
+ '@vue/shared': 3.5.10
+ vue: 3.5.10(typescript@5.6.2)
+
+ /@vue/shared@3.5.10:
+ resolution: {integrity: sha512-VkkBhU97Ki+XJ0xvl4C9YJsIZ2uIlQ7HqPpZOS3m9VCvmROPaChZU6DexdMJqvz9tbgG+4EtFVrSuailUq5KGQ==}
+
+ /balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ dev: true
+
+ /base64-arraybuffer@1.0.2:
+ resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
+ engines: {node: '>= 0.6.0'}
+ dev: false
+
+ /brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ dependencies:
+ balanced-match: 1.0.2
+ dev: true
+
+ /computeds@0.0.1:
+ resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
+ dev: true
+
+ /css-line-break@2.1.0:
+ resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
+ dependencies:
+ utrie: 1.0.2
+ dev: false
+
+ /csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+ /de-indent@1.0.2:
+ resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
+ dev: true
+
+ /echarts@5.5.1:
+ resolution: {integrity: sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==}
+ dependencies:
+ tslib: 2.3.0
+ zrender: 5.6.0
+ dev: false
+
+ /entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
+ /esbuild@0.21.5:
+ resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
+ engines: {node: '>=12'}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.21.5
+ '@esbuild/android-arm': 0.21.5
+ '@esbuild/android-arm64': 0.21.5
+ '@esbuild/android-x64': 0.21.5
+ '@esbuild/darwin-arm64': 0.21.5
+ '@esbuild/darwin-x64': 0.21.5
+ '@esbuild/freebsd-arm64': 0.21.5
+ '@esbuild/freebsd-x64': 0.21.5
+ '@esbuild/linux-arm': 0.21.5
+ '@esbuild/linux-arm64': 0.21.5
+ '@esbuild/linux-ia32': 0.21.5
+ '@esbuild/linux-loong64': 0.21.5
+ '@esbuild/linux-mips64el': 0.21.5
+ '@esbuild/linux-ppc64': 0.21.5
+ '@esbuild/linux-riscv64': 0.21.5
+ '@esbuild/linux-s390x': 0.21.5
+ '@esbuild/linux-x64': 0.21.5
+ '@esbuild/netbsd-x64': 0.21.5
+ '@esbuild/openbsd-x64': 0.21.5
+ '@esbuild/sunos-x64': 0.21.5
+ '@esbuild/win32-arm64': 0.21.5
+ '@esbuild/win32-ia32': 0.21.5
+ '@esbuild/win32-x64': 0.21.5
+ dev: true
+
+ /estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+ /fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /he@1.2.0:
+ resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ hasBin: true
+ dev: true
+
+ /html2canvas@1.4.1:
+ resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
+ engines: {node: '>=8.0.0'}
+ dependencies:
+ css-line-break: 2.1.0
+ text-segmentation: 1.0.3
+ dev: false
+
+ /magic-string@0.30.11:
+ resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==}
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ /minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: true
+
+ /muggle-string@0.4.1:
+ resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
+ dev: true
+
+ /nanoid@3.3.7:
+ resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ /path-browserify@1.0.1:
+ resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+ dev: true
+
+ /picocolors@1.1.0:
+ resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==}
+
+ /postcss@8.4.47:
+ resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==}
+ engines: {node: ^10 || ^12 || >=14}
+ dependencies:
+ nanoid: 3.3.7
+ picocolors: 1.1.0
+ source-map-js: 1.2.1
+
+ /rollup@4.23.0:
+ resolution: {integrity: sha512-vXB4IT9/KLDrS2WRXmY22sVB2wTsTwkpxjB8Q3mnakTENcYw3FRmfdYDy/acNmls+lHmDazgrRjK/yQ6hQAtwA==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+ dependencies:
+ '@types/estree': 1.0.6
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.23.0
+ '@rollup/rollup-android-arm64': 4.23.0
+ '@rollup/rollup-darwin-arm64': 4.23.0
+ '@rollup/rollup-darwin-x64': 4.23.0
+ '@rollup/rollup-linux-arm-gnueabihf': 4.23.0
+ '@rollup/rollup-linux-arm-musleabihf': 4.23.0
+ '@rollup/rollup-linux-arm64-gnu': 4.23.0
+ '@rollup/rollup-linux-arm64-musl': 4.23.0
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.23.0
+ '@rollup/rollup-linux-riscv64-gnu': 4.23.0
+ '@rollup/rollup-linux-s390x-gnu': 4.23.0
+ '@rollup/rollup-linux-x64-gnu': 4.23.0
+ '@rollup/rollup-linux-x64-musl': 4.23.0
+ '@rollup/rollup-win32-arm64-msvc': 4.23.0
+ '@rollup/rollup-win32-ia32-msvc': 4.23.0
+ '@rollup/rollup-win32-x64-msvc': 4.23.0
+ fsevents: 2.3.3
+ dev: true
+
+ /sax@1.4.1:
+ resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
+ dev: true
+
+ /semver@7.6.3:
+ resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dev: true
+
+ /source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ /text-segmentation@1.0.3:
+ resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
+ dependencies:
+ utrie: 1.0.2
+ dev: false
+
+ /to-fast-properties@2.0.0:
+ resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
+ engines: {node: '>=4'}
+
+ /tslib@2.3.0:
+ resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
+ dev: false
+
+ /typescript@5.6.2:
+ resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ /undici-types@6.19.8:
+ resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
+ dev: true
+
+ /utrie@1.0.2:
+ resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
+ dependencies:
+ base64-arraybuffer: 1.0.2
+ dev: false
+
+ /vite@5.4.8(@types/node@22.7.4):
+ resolution: {integrity: sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ dependencies:
+ '@types/node': 22.7.4
+ esbuild: 0.21.5
+ postcss: 8.4.47
+ rollup: 4.23.0
+ optionalDependencies:
+ fsevents: 2.3.3
+ dev: true
+
+ /vscode-uri@3.0.8:
+ resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
+ dev: true
+
+ /vue-router@4.4.5(vue@3.5.10):
+ resolution: {integrity: sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==}
+ peerDependencies:
+ vue: ^3.2.0
+ dependencies:
+ '@vue/devtools-api': 6.6.4
+ vue: 3.5.10(typescript@5.6.2)
+ dev: false
+
+ /vue-tsc@2.1.6(typescript@5.6.2):
+ resolution: {integrity: sha512-f98dyZp5FOukcYmbFpuSCJ4Z0vHSOSmxGttZJCsFeX0M4w/Rsq0s4uKXjcSRsZqsRgQa6z7SfuO+y0HVICE57Q==}
+ hasBin: true
+ peerDependencies:
+ typescript: '>=5.0.0'
+ dependencies:
+ '@volar/typescript': 2.4.5
+ '@vue/language-core': 2.1.6(typescript@5.6.2)
+ semver: 7.6.3
+ typescript: 5.6.2
+ dev: true
+
+ /vue@3.5.10(typescript@5.6.2):
+ resolution: {integrity: sha512-Vy2kmJwHPlouC/tSnIgXVg03SG+9wSqT1xu1Vehc+ChsXsRd7jLkKgMltVEFOzUdBr3uFwBCG+41LJtfAcBRng==}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@vue/compiler-dom': 3.5.10
+ '@vue/compiler-sfc': 3.5.10
+ '@vue/runtime-dom': 3.5.10
+ '@vue/server-renderer': 3.5.10(vue@3.5.10)
+ '@vue/shared': 3.5.10
+ typescript: 5.6.2
+
+ /zrender@5.6.0:
+ resolution: {integrity: sha512-uzgraf4njmmHAbEUxMJ8Oxg+P3fT04O+9p7gY+wJRVxo8Ge+KmYv0WJev945EH4wFuc4OY2NLXz46FZrWS9xJg==}
+ dependencies:
+ tslib: 2.3.0
+ dev: false
diff --git a/server-status-web/public/apiroot b/server-status-web/public/apiroot
new file mode 100644
index 0000000..aa352f1
--- /dev/null
+++ b/server-status-web/public/apiroot
@@ -0,0 +1 @@
+http://127.0.0.1:8088
\ No newline at end of file
diff --git a/server-status-web/public/icon.svg b/server-status-web/public/icon.svg
new file mode 100644
index 0000000..2bce659
--- /dev/null
+++ b/server-status-web/public/icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/label.svg b/server-status-web/public/svg/label.svg
new file mode 100644
index 0000000..8e235b7
--- /dev/null
+++ b/server-status-web/public/svg/label.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/location-new.svg b/server-status-web/public/svg/location-new.svg
new file mode 100644
index 0000000..6a22095
--- /dev/null
+++ b/server-status-web/public/svg/location-new.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/screenshots.svg b/server-status-web/public/svg/screenshots.svg
new file mode 100644
index 0000000..1b2fd3e
--- /dev/null
+++ b/server-status-web/public/svg/screenshots.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-alpine.svg b/server-status-web/public/svg/system-alpine.svg
new file mode 100644
index 0000000..3588585
--- /dev/null
+++ b/server-status-web/public/svg/system-alpine.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-arch.svg b/server-status-web/public/svg/system-arch.svg
new file mode 100644
index 0000000..835466d
--- /dev/null
+++ b/server-status-web/public/svg/system-arch.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-darwin.svg b/server-status-web/public/svg/system-darwin.svg
new file mode 100644
index 0000000..1e9bace
--- /dev/null
+++ b/server-status-web/public/svg/system-darwin.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-debian.svg b/server-status-web/public/svg/system-debian.svg
new file mode 100644
index 0000000..2405bcd
--- /dev/null
+++ b/server-status-web/public/svg/system-debian.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-deepin.svg b/server-status-web/public/svg/system-deepin.svg
new file mode 100644
index 0000000..0ba781e
--- /dev/null
+++ b/server-status-web/public/svg/system-deepin.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-elementary.svg b/server-status-web/public/svg/system-elementary.svg
new file mode 100644
index 0000000..d674e9f
--- /dev/null
+++ b/server-status-web/public/svg/system-elementary.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-fedora.svg b/server-status-web/public/svg/system-fedora.svg
new file mode 100644
index 0000000..e69de29
diff --git a/server-status-web/public/svg/system-kali.svg b/server-status-web/public/svg/system-kali.svg
new file mode 100644
index 0000000..72957e2
--- /dev/null
+++ b/server-status-web/public/svg/system-kali.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-linux.svg b/server-status-web/public/svg/system-linux.svg
new file mode 100644
index 0000000..d6adcc4
--- /dev/null
+++ b/server-status-web/public/svg/system-linux.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-manjaro.svg b/server-status-web/public/svg/system-manjaro.svg
new file mode 100644
index 0000000..0ca209f
--- /dev/null
+++ b/server-status-web/public/svg/system-manjaro.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-mint.svg b/server-status-web/public/svg/system-mint.svg
new file mode 100644
index 0000000..17a12b1
--- /dev/null
+++ b/server-status-web/public/svg/system-mint.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-opensuse.svg b/server-status-web/public/svg/system-opensuse.svg
new file mode 100644
index 0000000..d79d20f
--- /dev/null
+++ b/server-status-web/public/svg/system-opensuse.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-redhat.svg b/server-status-web/public/svg/system-redhat.svg
new file mode 100644
index 0000000..35020c6
--- /dev/null
+++ b/server-status-web/public/svg/system-redhat.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-ubuntu.svg b/server-status-web/public/svg/system-ubuntu.svg
new file mode 100644
index 0000000..9a974a1
--- /dev/null
+++ b/server-status-web/public/svg/system-ubuntu.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-windows.svg b/server-status-web/public/svg/system-windows.svg
new file mode 100644
index 0000000..58263d9
--- /dev/null
+++ b/server-status-web/public/svg/system-windows.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system-zorin.svg b/server-status-web/public/svg/system-zorin.svg
new file mode 100644
index 0000000..7c4fd71
--- /dev/null
+++ b/server-status-web/public/svg/system-zorin.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/system.svg b/server-status-web/public/svg/system.svg
new file mode 100644
index 0000000..372577e
--- /dev/null
+++ b/server-status-web/public/svg/system.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/public/svg/timezone.svg b/server-status-web/public/svg/timezone.svg
new file mode 100644
index 0000000..9a71935
--- /dev/null
+++ b/server-status-web/public/svg/timezone.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/src/App.vue b/server-status-web/src/App.vue
new file mode 100644
index 0000000..9e00d48
--- /dev/null
+++ b/server-status-web/src/App.vue
@@ -0,0 +1,37 @@
+
+
+
+ Server Status
+
+
+
+
+
diff --git a/server-status-web/src/api/index.ts b/server-status-web/src/api/index.ts
new file mode 100644
index 0000000..4940f61
--- /dev/null
+++ b/server-status-web/src/api/index.ts
@@ -0,0 +1,56 @@
+///
+export interface Status {
+ meta: {
+ id: string; // 服务器ID,用于标识服务器
+ name: string;
+ os: {
+ name: string;
+ version: string;
+ release: string;
+ machine: string;
+ };
+ labels: string[]; // 服务器标签
+ location: string; // Chongqing, China
+ uptime: number; // uptime in seconds
+ link: string | null; // 链接或是nil
+ observed_at: number; // unix timestamp
+ start_time: number; // unix timestamp
+ timezone: string; // Asia/Shanghai
+ };
+ hardware: {
+ mem: {
+ total: number;
+ used: number;
+ };
+ swap: {
+ total: number;
+ used: number;
+ };
+ cpu: {
+ cores: number;
+ logics: number;
+ percent: number; // 0-100
+ };
+ disks: {
+ [key: string]: {
+ used: number;
+ total: number;
+ mountpoint: string;
+ fstype: string;
+ device: string;
+ };
+ };
+ net: {
+ up: number;
+ down: number;
+ type: string; // IPv4 or IPv6 or IPv4/6
+ };
+ };
+}
+
+const apiRoot = import.meta.env.VITE_API_ROOT
+
+export async function getStatuses(): Promise> {
+ const response = await fetch(`${apiRoot}/api/status`)
+ return response.json()
+}
\ No newline at end of file
diff --git a/server-status-web/src/api/node.ts b/server-status-web/src/api/node.ts
new file mode 100644
index 0000000..e69de29
diff --git a/server-status-web/src/api/utils.ts b/server-status-web/src/api/utils.ts
new file mode 100644
index 0000000..22c5e8d
--- /dev/null
+++ b/server-status-web/src/api/utils.ts
@@ -0,0 +1,123 @@
+export const onlineTimeout = 30
+
+export function getReleaseInfo(name: string, release: string): { name: string, icon: string } {
+ if (name.toLowerCase() == 'windows') {
+ return {name: 'Windows', icon: '/svg/system-windows.svg'}
+ } else if (name.toLowerCase() == 'darwin') {
+ return {name: 'macOS', icon: '/svg/system-darwin.svg'}
+ } else {
+ const map: Record = {
+ 'alpine': {name: 'Alpine Linux', icon: '/svg/system-alpine.svg'},
+ 'arch': {name: 'Arch Linux', icon: '/svg/system-archlinux.svg'},
+ 'centos': {name: 'CentOS', icon: '/svg/system-centos.svg'},
+ 'debian': {name: 'Debian', icon: '/svg/system-debian.svg'},
+ 'deepin': {name: 'Deepin', icon: '/svg/system-deepin.svg'},
+ 'elementary': {name: 'elementary OS', icon: '/svg/system-elementary.svg'},
+ 'fedora': {name: 'Fedora', icon: '/svg/system-fedora.svg'},
+ 'kali': {name: 'Kali Linux', icon: '/svg/system-kali.svg'},
+ 'manjaro': {name: 'Manjaro', icon: '/svg/system-manjaro.svg'},
+ 'opensuse': {name: 'openSUSE', icon: '/svg/system-opensuse.svg'},
+ 'redhat': {name: 'Red Hat', icon: '/svg/system-redhat.svg'},
+ 'suse': {name: 'SUSE', icon: '/svg/system-opensuse.svg'}, // SUSE Linux Enterprise Server
+ 'ubuntu': {name: 'Ubuntu', icon: '/svg/system-ubuntu.svg'},
+ 'zorin': {name: 'Zorin OS', icon: '/svg/system-zorin.svg'},
+ }
+ release = release.toLowerCase()
+ for (const key in map) {
+ if (release.includes(key)) {
+ return map[key]
+ }
+ }
+ return {name: name, icon: '/svg/system-linux.svg'}
+ }
+}
+
+export function formatSizeByUnit(bytes: number, unit: string | null = null, suffix: string | null = null): string {
+ // 若指定单位,则格式化为指定单位对应的大小字符串加上单位
+ // 若未指定单位,则选择1-1024之间的最大单位,格式化为该单位对应的大小字符串加上单位
+ if (bytes == 0) {
+ return '0'
+ }
+ if (bytes < 1024) {
+ return bytes.toFixed(0) + (suffix ? suffix : '')
+ }
+ const units = ['', 'K', 'M', 'G', 'T', 'P', 'E']
+ let i = unit ? units.indexOf(unit) : Math.floor(Math.log2(bytes) / 10)
+ return (bytes / Math.pow(1024, i)).toFixed(1) + (suffix ? (units[i] + suffix) : '')
+}
+
+export function formatSizeToNumAndUnit(bytes: number): { num: number, unit: string } {
+ const units = ['', 'K', 'M', 'G', 'T', 'P', 'E']
+ let i = Math.floor(Math.log2(bytes) / 10)
+ return {num: (bytes / Math.pow(1024, i)), unit: units[i]}
+}
+
+export function format2Size(num1: number, num2: number, suffix: string | null = 'iB'): string {
+ // const n1, unit = formatSizeToNumAndUnit(num1)
+ // const n2 = formatSizeWithUnit(num2, unit)
+ // return `${n1}/${n2}`
+ // const r1 = formatSizeToNumAndUnit(num1)
+ // let n2 = formatSizeWithUnit(num2, r1.unit)
+ // return `${r1.num.toFixed(2)}/${n2}`
+ const r2 = formatSizeToNumAndUnit(num2)
+ const n1 = formatSizeByUnit(num1, r2.unit)
+ return `${n1}/${r2.num.toFixed(1)}${r2.unit}${suffix}`
+}
+
+export function formatDate(timestamp: number, timeOnly: boolean = false) {
+ const d = new Date(timestamp * 1000)
+ const date = d.toLocaleDateString()
+ const time = d.toLocaleTimeString()
+ return timeOnly ? time : `${date} ${time}`
+}
+
+export function getBaseColor(percent: number, disable: boolean = false) {
+ // 0~60: green, 60~80: yellow, 80~90: orange, 90~100: red
+ if (disable) {
+ return '#9ca3af'
+ }
+ if (percent < 60) {
+ return '#22c55e'
+ } else if (percent < 80) {
+ return '#eab308'
+ } else if (percent < 90) {
+ return '#f97316'
+ } else {
+ return '#ef4444'
+ }
+}
+
+
+export function getBlankColor(percent: number, disable: boolean = false) {
+ if (disable) {
+ return '#e5e7eb'
+ }
+ if (percent < 60) {
+ return '#bbf7d0'
+ } else if (percent < 80) {
+ return '#fef08a'
+ } else if (percent < 90) {
+ return '#fed7aa'
+ } else {
+ return '#fecaca'
+ }
+}
+
+// 1727998501
+
+export function formatUptime(uptime: number): string {
+ const seconds = uptime;
+ const d = Math.floor(seconds / 86400);
+ const h = Math.floor((seconds % 86400) / 3600).toString().padStart(2, '0');
+ const m = Math.floor((seconds % 3600) / 60).toString().padStart(2, '0');
+ const s = Math.floor(seconds % 60).toString().padStart(2, '0');
+ return `${d}:${h}:${m}:${s}`;
+}
+
+export function formatDuration(duration: number): string {
+ const d = Math.floor(duration / 86400);
+ const h = Math.floor((duration % 86400) / 3600);
+ const m = Math.floor((duration % 3600) / 60);
+ const s = Math.floor(duration % 60);
+ return d > 0 ? `${d}d` : h > 0 ? `${h}h` : m > 0 ? `${m}m` : `${s}s`;
+}
\ No newline at end of file
diff --git a/server-status-web/src/assets/vue.svg b/server-status-web/src/assets/vue.svg
new file mode 100644
index 0000000..770e9d3
--- /dev/null
+++ b/server-status-web/src/assets/vue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/server-status-web/src/components/Disk.vue b/server-status-web/src/components/Disk.vue
new file mode 100644
index 0000000..48016bd
--- /dev/null
+++ b/server-status-web/src/components/Disk.vue
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+ {{ props.mountpoint }}
+
+
+ {{ format2Size(props.used, props.total) }} [{{ props.fstype }}]
+
+
+
+
+
+
{{ (props.used / props.total * 100).toFixed(1) }}%
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server-status-web/src/components/HelloWorld.vue b/server-status-web/src/components/HelloWorld.vue
new file mode 100644
index 0000000..b58e52b
--- /dev/null
+++ b/server-status-web/src/components/HelloWorld.vue
@@ -0,0 +1,41 @@
+
+
+
+ {{ msg }}
+
+
+
count is {{ count }}
+
+ Edit
+ components/HelloWorld.vue
to test HMR
+
+
+
+
+ Check out
+ create-vue , the official Vue + Vite starter
+
+
+ Learn more about IDE Support for Vue in the
+ Vue Docs Scaling up Guide .
+
+ Click on the Vite and Vue logos to learn more
+
+
+
diff --git a/server-status-web/src/components/Host.vue b/server-status-web/src/components/Host.vue
new file mode 100644
index 0000000..7d031ef
--- /dev/null
+++ b/server-status-web/src/components/Host.vue
@@ -0,0 +1,548 @@
+
+
+
+
+
+
{{ status.meta.name }}
+
+
+
+
+
+ Hardware
+
+
+
+
+
CPU
+
{{ status.hardware.cpu.cores }}C {{ status.hardware.cpu.logics }}T
+
+
+
+
Mem
+
{{ memDetail }}
+
+
+
+
Swap
+
{{ swapDetail }}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server-status-web/src/components/Nav.vue b/server-status-web/src/components/Nav.vue
new file mode 100644
index 0000000..676d926
--- /dev/null
+++ b/server-status-web/src/components/Nav.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ route.name }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server-status-web/src/components/OutlineAnime.vue b/server-status-web/src/components/OutlineAnime.vue
new file mode 100644
index 0000000..795cc1f
--- /dev/null
+++ b/server-status-web/src/components/OutlineAnime.vue
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server-status-web/src/main.ts b/server-status-web/src/main.ts
new file mode 100644
index 0000000..e210599
--- /dev/null
+++ b/server-status-web/src/main.ts
@@ -0,0 +1,10 @@
+import { createApp } from 'vue'
+import './style.css'
+import App from './App.vue'
+import router from "./router";
+
+// createApp(App).use(router).mount('#app')
+
+const app = createApp(App)
+app.use(router)
+app.mount('#app')
\ No newline at end of file
diff --git a/server-status-web/src/router/index.ts b/server-status-web/src/router/index.ts
new file mode 100644
index 0000000..85e2110
--- /dev/null
+++ b/server-status-web/src/router/index.ts
@@ -0,0 +1,23 @@
+import {createRouter, createWebHistory} from "vue-router"
+import Home from "../views/Home.vue"
+import Test from "../views/Test.vue"
+
+const routes = [
+ {
+ path: '/',
+ name: '主页',
+ component: Home
+ },
+ {
+ path: '/test',
+ name: '测试',
+ component: Test
+ }
+]
+
+const router = createRouter({
+ history: createWebHistory("/"),
+ routes
+})
+
+export default router
\ No newline at end of file
diff --git a/server-status-web/src/style.css b/server-status-web/src/style.css
new file mode 100644
index 0000000..97ab8fd
--- /dev/null
+++ b/server-status-web/src/style.css
@@ -0,0 +1,89 @@
+:root {
+ font-family: 'Josefin Sans', sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: #000;
+ background-color: #fff;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ --text-color-1: #000;
+ --text-color-2: #5f5f5f;
+
+}
+
+
+.dark {
+ color: #fff;
+ background-color: #000;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+
+a:hover {
+ color: #535bf2;
+}
+
+/*body {*/
+/* margin: 0;*/
+/* display: flex;*/
+/* place-items: center;*/
+/* min-width: 320px;*/
+/* min-height: 100vh;*/
+/*}*/
+
+/*h1 {*/
+/* font-size: 3.2em;*/
+/* line-height: 1.1;*/
+/*}*/
+
+/*button {*/
+/* border-radius: 8px;*/
+/* border: 1px solid transparent;*/
+/* padding: 0.6em 1.2em;*/
+/* font-size: 1em;*/
+/* font-weight: 500;*/
+/* font-family: inherit;*/
+/* background-color: #1a1a1a;*/
+/* cursor: pointer;*/
+/* transition: border-color 0.25s;*/
+/*}*/
+/*button:hover {*/
+/* border-color: #646cff;*/
+/*}*/
+/*button:focus,*/
+/*button:focus-visible {*/
+/* outline: 4px auto -webkit-focus-ring-color;*/
+/*}*/
+
+/*.card {*/
+/* padding: 2em;*/
+/*}*/
+
+/*#app {*/
+/* max-width: 1280px;*/
+/* margin: 0 auto;*/
+/* padding: 2rem;*/
+/* text-align: center;*/
+/*}*/
+
+/*@media (prefers-color-scheme: light) {*/
+/* :root {*/
+/* color: #213547;*/
+/* background-color: #ffffff;*/
+/* }*/
+/* a:hover {*/
+/* color: #747bff;*/
+/* }*/
+/* button {*/
+/* background-color: #f9f9f9;*/
+/* }*/
+/*}*/
diff --git a/server-status-web/src/views/Home.vue b/server-status-web/src/views/Home.vue
new file mode 100644
index 0000000..4333e24
--- /dev/null
+++ b/server-status-web/src/views/Home.vue
@@ -0,0 +1,160 @@
+
+
+
+
+
Overview: {{ onlineNum }} Online {{ offline }} Offline
+
+
+
Sort by
+
+
+ selectOption('name')">Name
+ selectOption('uptime')">Uptime
+ selectOption('memory')">Memory
+ selectOption('network')">Network
+
+ reverse= !reverse" id="reverse-button">Reverse
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server-status-web/src/views/Test.vue b/server-status-web/src/views/Test.vue
new file mode 100644
index 0000000..e2dace2
--- /dev/null
+++ b/server-status-web/src/views/Test.vue
@@ -0,0 +1,11 @@
+
+
+
+Test
+
+
+
\ No newline at end of file
diff --git a/server-status-web/src/vite-env.d.ts b/server-status-web/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/server-status-web/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/server-status-web/tsconfig.app.json b/server-status-web/tsconfig.app.json
new file mode 100644
index 0000000..c54e602
--- /dev/null
+++ b/server-status-web/tsconfig.app.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "preserve",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
+}
diff --git a/server-status-web/tsconfig.app.tsbuildinfo b/server-status-web/tsconfig.app.tsbuildinfo
new file mode 100644
index 0000000..86a02f8
--- /dev/null
+++ b/server-status-web/tsconfig.app.tsbuildinfo
@@ -0,0 +1 @@
+{"root":["./src/main.ts","./src/vite-env.d.ts","./src/api/index.ts","./src/api/node.ts","./src/api/utils.ts","./src/router/index.ts","./src/App.vue","./src/components/Disk.vue","./src/components/HelloWorld.vue","./src/components/Host.vue","./src/components/Nav.vue","./src/components/OutlineAnime.vue","./src/views/Home.vue","./src/views/Test.vue"],"version":"5.6.2"}
\ No newline at end of file
diff --git a/server-status-web/tsconfig.json b/server-status-web/tsconfig.json
new file mode 100644
index 0000000..ea9d0cd
--- /dev/null
+++ b/server-status-web/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "files": [],
+ "references": [
+ {
+ "path": "./tsconfig.app.json"
+ },
+ {
+ "path": "./tsconfig.node.json"
+ }
+ ]
+}
diff --git a/server-status-web/tsconfig.node.json b/server-status-web/tsconfig.node.json
new file mode 100644
index 0000000..0d3d714
--- /dev/null
+++ b/server-status-web/tsconfig.node.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/server-status-web/tsconfig.node.tsbuildinfo b/server-status-web/tsconfig.node.tsbuildinfo
new file mode 100644
index 0000000..98ef2f9
--- /dev/null
+++ b/server-status-web/tsconfig.node.tsbuildinfo
@@ -0,0 +1 @@
+{"root":["./vite.config.ts"],"version":"5.6.2"}
\ No newline at end of file
diff --git a/server-status-web/vite.config.ts b/server-status-web/vite.config.ts
new file mode 100644
index 0000000..104fb60
--- /dev/null
+++ b/server-status-web/vite.config.ts
@@ -0,0 +1,7 @@
+import {defineConfig} from 'vite'
+import vue from '@vitejs/plugin-vue'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [vue()],
+})