更新依赖版本,添加音效功能,优化WebSocket连接及图表显示逻辑
This commit is contained in:
parent
a8b6fb4b8b
commit
686b5facf8
858
package-lock.json
generated
858
package-lock.json
generated
@ -63,8 +63,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.26.9",
|
||||
"integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==",
|
||||
"version": "7.26.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz",
|
||||
"integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
@ -116,9 +117,394 @@
|
||||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz",
|
||||
"integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz",
|
||||
"integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz",
|
||||
"integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz",
|
||||
"integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz",
|
||||
"integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz",
|
||||
"integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz",
|
||||
"integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz",
|
||||
"integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz",
|
||||
"integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz",
|
||||
"integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.24.2",
|
||||
"integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -1176,8 +1562,9 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.9",
|
||||
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz",
|
||||
"integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
@ -1474,8 +1861,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.24.2",
|
||||
"integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
|
||||
"integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
@ -1485,415 +1873,31 @@
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.24.2",
|
||||
"@esbuild/android-arm": "0.24.2",
|
||||
"@esbuild/android-arm64": "0.24.2",
|
||||
"@esbuild/android-x64": "0.24.2",
|
||||
"@esbuild/darwin-arm64": "0.24.2",
|
||||
"@esbuild/darwin-x64": "0.24.2",
|
||||
"@esbuild/freebsd-arm64": "0.24.2",
|
||||
"@esbuild/freebsd-x64": "0.24.2",
|
||||
"@esbuild/linux-arm": "0.24.2",
|
||||
"@esbuild/linux-arm64": "0.24.2",
|
||||
"@esbuild/linux-ia32": "0.24.2",
|
||||
"@esbuild/linux-loong64": "0.24.2",
|
||||
"@esbuild/linux-mips64el": "0.24.2",
|
||||
"@esbuild/linux-ppc64": "0.24.2",
|
||||
"@esbuild/linux-riscv64": "0.24.2",
|
||||
"@esbuild/linux-s390x": "0.24.2",
|
||||
"@esbuild/linux-x64": "0.24.2",
|
||||
"@esbuild/netbsd-arm64": "0.24.2",
|
||||
"@esbuild/netbsd-x64": "0.24.2",
|
||||
"@esbuild/openbsd-arm64": "0.24.2",
|
||||
"@esbuild/openbsd-x64": "0.24.2",
|
||||
"@esbuild/sunos-x64": "0.24.2",
|
||||
"@esbuild/win32-arm64": "0.24.2",
|
||||
"@esbuild/win32-ia32": "0.24.2",
|
||||
"@esbuild/win32-x64": "0.24.2"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
|
||||
"integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/android-arm": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
|
||||
"integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
|
||||
"integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/android-x64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
|
||||
"integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
|
||||
"integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
|
||||
"integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
|
||||
"integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
|
||||
"integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
|
||||
"integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
|
||||
"integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
|
||||
"integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
|
||||
"integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
|
||||
"integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
|
||||
"integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
|
||||
"integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
|
||||
"integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
|
||||
"integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
|
||||
"integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
|
||||
"integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
|
||||
"integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
|
||||
"integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
|
||||
"integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
|
||||
"integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.24.2",
|
||||
"resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
|
||||
"integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"@esbuild/aix-ppc64": "0.25.1",
|
||||
"@esbuild/android-arm": "0.25.1",
|
||||
"@esbuild/android-arm64": "0.25.1",
|
||||
"@esbuild/android-x64": "0.25.1",
|
||||
"@esbuild/darwin-arm64": "0.25.1",
|
||||
"@esbuild/darwin-x64": "0.25.1",
|
||||
"@esbuild/freebsd-arm64": "0.25.1",
|
||||
"@esbuild/freebsd-x64": "0.25.1",
|
||||
"@esbuild/linux-arm": "0.25.1",
|
||||
"@esbuild/linux-arm64": "0.25.1",
|
||||
"@esbuild/linux-ia32": "0.25.1",
|
||||
"@esbuild/linux-loong64": "0.25.1",
|
||||
"@esbuild/linux-mips64el": "0.25.1",
|
||||
"@esbuild/linux-ppc64": "0.25.1",
|
||||
"@esbuild/linux-riscv64": "0.25.1",
|
||||
"@esbuild/linux-s390x": "0.25.1",
|
||||
"@esbuild/linux-x64": "0.25.1",
|
||||
"@esbuild/netbsd-arm64": "0.25.1",
|
||||
"@esbuild/netbsd-x64": "0.25.1",
|
||||
"@esbuild/openbsd-arm64": "0.25.1",
|
||||
"@esbuild/openbsd-x64": "0.25.1",
|
||||
"@esbuild/sunos-x64": "0.25.1",
|
||||
"@esbuild/win32-arm64": "0.25.1",
|
||||
"@esbuild/win32-ia32": "0.25.1",
|
||||
"@esbuild/win32-x64": "0.25.1"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-html": {
|
||||
@ -2402,8 +2406,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.1",
|
||||
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
|
||||
"version": "8.5.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@ -2437,9 +2442,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prismjs": {
|
||||
"version": "1.29.0",
|
||||
"resolved": "https://registry.npmmirror.com/prismjs/-/prismjs-1.29.0.tgz",
|
||||
"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
|
||||
"version": "1.30.0",
|
||||
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
|
||||
"integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@ -2905,12 +2910,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.1.0",
|
||||
"integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.1.tgz",
|
||||
"integrity": "sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.24.2",
|
||||
"postcss": "^8.5.1",
|
||||
"esbuild": "^0.25.0",
|
||||
"postcss": "^8.5.3",
|
||||
"rollup": "^4.30.1"
|
||||
},
|
||||
"bin": {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
import AdminLayout from '../layout/AdminLayout.vue'
|
||||
import { useUserStore } from '../stores/user'
|
||||
|
||||
@ -24,7 +24,7 @@ Promise.all([
|
||||
])
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
history: createWebHashHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
|
35
src/utils/SoundEffect.js
Normal file
35
src/utils/SoundEffect.js
Normal file
@ -0,0 +1,35 @@
|
||||
class SoundEffect {
|
||||
constructor() {
|
||||
this.SOUND_CONNECT = new Audio('/src/assets/harmonyos-sound/notification_accomplished_08.wav');
|
||||
this.SOUND_DISCONNECT = new Audio('/src/assets/harmonyos-sound/notification_wrong_04.wav');
|
||||
}
|
||||
|
||||
// 播放连接成功音效
|
||||
playConnectSound() {
|
||||
this.SOUND_CONNECT.currentTime = 0;
|
||||
this.SOUND_CONNECT.play().catch(error => {
|
||||
console.error('音效播放失败:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// 播放断开连接音效
|
||||
playDisconnectSound() {
|
||||
this.SOUND_DISCONNECT.currentTime = 0;
|
||||
this.SOUND_DISCONNECT.play().catch(error => {
|
||||
console.error('音效播放失败:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// 根据状态播放对应音效
|
||||
playStatusSound(isOnline) {
|
||||
if (isOnline) {
|
||||
this.playConnectSound();
|
||||
} else {
|
||||
this.playDisconnectSound();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建单例实例
|
||||
const soundEffect = new SoundEffect();
|
||||
export default soundEffect;
|
@ -1,10 +1,36 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, watch, nextTick, onActivated, onDeactivated } from 'vue'
|
||||
import { Plus, VideoCamera, Loading } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ElMessage, ElNotification } from 'element-plus'
|
||||
import { getDeviceList } from '@/api/device'
|
||||
import { createFlvPlayer, destroyFlvPlayer } from '@/utils/videoPlayer'
|
||||
|
||||
// 音效资源
|
||||
const SOUND_CONNECT = new Audio('/src/assets/harmonyos-sound/notification_accomplished_08.wav')
|
||||
const SOUND_DISCONNECT = new Audio('/src/assets/harmonyos-sound/notification_wrong_04.wav')
|
||||
|
||||
// 预加载音频
|
||||
const preloadSounds = () => {
|
||||
SOUND_CONNECT.load()
|
||||
SOUND_DISCONNECT.load()
|
||||
|
||||
// 添加音频加载事件监听
|
||||
SOUND_CONNECT.addEventListener('canplaythrough', () => {
|
||||
console.log('连接音效加载完成')
|
||||
})
|
||||
SOUND_DISCONNECT.addEventListener('canplaythrough', () => {
|
||||
console.log('断开音效加载完成')
|
||||
})
|
||||
|
||||
// 添加音频错误事件监听
|
||||
SOUND_CONNECT.addEventListener('error', (e) => {
|
||||
console.error('连接音效加载失败:', e)
|
||||
})
|
||||
SOUND_DISCONNECT.addEventListener('error', (e) => {
|
||||
console.error('断开音效加载失败:', e)
|
||||
})
|
||||
}
|
||||
|
||||
// 无人机数据
|
||||
const droneList = ref([])
|
||||
const loading = ref(false)
|
||||
@ -15,6 +41,12 @@ const flvPlayers = ref([])
|
||||
const playingVideos = ref(new Set()) // 记录正在播放的视频
|
||||
let ws = null // WebSocket 连接
|
||||
|
||||
// WebSocket 重连相关
|
||||
const wsRetryCount = ref(0)
|
||||
const MAX_RETRY_COUNT = 3
|
||||
let wsRetryTimer = null
|
||||
let pollingTimer = null
|
||||
|
||||
// 确保 playingVideos 始终是一个 Set
|
||||
const isVideoPlaying = (code) => {
|
||||
return playingVideos.value?.has(code) || false
|
||||
@ -112,58 +144,169 @@ const currentDroneIndex = ref(0)
|
||||
|
||||
// 初始化 WebSocket 连接
|
||||
const initWebSocket = () => {
|
||||
ws = new WebSocket('ws://192.168.1.158:6894')
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('WebSocket连接成功')
|
||||
if (wsRetryCount.value >= MAX_RETRY_COUNT) {
|
||||
console.warn('WebSocket重试次数超过限制,切换到HTTP轮询模式')
|
||||
startPolling()
|
||||
return
|
||||
}
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
if (data.type === 'device_status') {
|
||||
// 找到对应的设备并更新状态
|
||||
const droneIndex = droneList.value.findIndex(drone => drone.code === data.device_code)
|
||||
if (droneIndex !== -1) {
|
||||
const newStatus = data.status === 1 ? 'online' : 'offline'
|
||||
try {
|
||||
if (ws) {
|
||||
ws.close()
|
||||
ws = null
|
||||
}
|
||||
|
||||
// 如果状态发生变化
|
||||
if (droneList.value[droneIndex].status !== newStatus) {
|
||||
droneList.value[droneIndex].status = newStatus
|
||||
ws = new WebSocket('ws://localhost:6894')
|
||||
|
||||
// 如果设备上线且当前没有在线设备显示,则切换到该设备
|
||||
if (newStatus === 'online' &&
|
||||
(!droneList.value[currentDroneIndex.value] ||
|
||||
droneList.value[currentDroneIndex.value].status !== 'online')) {
|
||||
currentDroneIndex.value = droneIndex
|
||||
}
|
||||
|
||||
// 如果是当前选中的设备或刚切换到该设备
|
||||
if (droneIndex === currentDroneIndex.value) {
|
||||
nextTick(() => {
|
||||
initVideoPlayers()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
ws.onopen = () => {
|
||||
wsRetryCount.value = 0
|
||||
if (wsRetryTimer) {
|
||||
clearTimeout(wsRetryTimer)
|
||||
wsRetryTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
console.log('收到WebSocket消息:', data) // 添加日志
|
||||
if (data.type === 'device_status') {
|
||||
updateDeviceStatus(data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('WebSocket消息处理错误:', error)
|
||||
}
|
||||
}
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket错误:', error)
|
||||
wsRetryCount.value++
|
||||
reconnectWebSocket()
|
||||
}
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('WebSocket连接关闭')
|
||||
reconnectWebSocket()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('WebSocket连接失败:', error)
|
||||
reconnectWebSocket()
|
||||
}
|
||||
}
|
||||
|
||||
// 更新设备状态的函数
|
||||
const updateDeviceStatus = (data) => {
|
||||
const droneIndex = droneList.value.findIndex(drone => drone.code === data.device_code)
|
||||
if (droneIndex !== -1) {
|
||||
const newStatus = data.status === 1 ? 'online' : 'offline'
|
||||
const oldStatus = droneList.value[droneIndex].status
|
||||
|
||||
// 如果状态发生变化
|
||||
if (oldStatus !== newStatus) {
|
||||
console.log('设备状态变化:', {
|
||||
deviceName: droneList.value[droneIndex].name,
|
||||
oldStatus,
|
||||
newStatus
|
||||
})
|
||||
|
||||
// 更新设备状态
|
||||
const updatedDrone = {
|
||||
...droneList.value[droneIndex],
|
||||
status: newStatus,
|
||||
battery_level: data.battery_level || droneList.value[droneIndex].battery_level,
|
||||
signal_strength: data.signal_strength || droneList.value[droneIndex].signal_strength
|
||||
}
|
||||
|
||||
// 使用Vue的响应式更新方法
|
||||
droneList.value.splice(droneIndex, 1, updatedDrone)
|
||||
|
||||
// 显示状态变化通知
|
||||
showDeviceStatusNotification(newStatus, updatedDrone.name)
|
||||
|
||||
// 如果设备上线且当前没有在线设备显示,则切换到该设备
|
||||
if (newStatus === 'online' &&
|
||||
(!droneList.value[currentDroneIndex.value] ||
|
||||
droneList.value[currentDroneIndex.value].status !== 'online')) {
|
||||
currentDroneIndex.value = droneIndex
|
||||
}
|
||||
|
||||
// 如果是当前选中的设备,重新初始化视频播放器
|
||||
if (droneIndex === currentDroneIndex.value) {
|
||||
nextTick(() => {
|
||||
initVideoPlayers()
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('WebSocket消息处理错误:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket错误:', error)
|
||||
// WebSocket 重连
|
||||
const reconnectWebSocket = () => {
|
||||
if (wsRetryTimer) return
|
||||
|
||||
wsRetryTimer = setTimeout(() => {
|
||||
console.log('尝试重新连接WebSocket...')
|
||||
initWebSocket()
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
// 启动轮询
|
||||
const startPolling = () => {
|
||||
if (pollingTimer) return
|
||||
|
||||
// 立即执行一次
|
||||
getList()
|
||||
|
||||
// 每10秒轮询一次
|
||||
pollingTimer = setInterval(() => {
|
||||
getList()
|
||||
}, 10000) // 改为10秒
|
||||
}
|
||||
|
||||
// 停止轮询
|
||||
const stopPolling = () => {
|
||||
if (pollingTimer) {
|
||||
clearInterval(pollingTimer)
|
||||
pollingTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
// 显示设备状态通知
|
||||
const showDeviceStatusNotification = async (status, deviceName) => {
|
||||
try {
|
||||
// 播放对应的音效
|
||||
const sound = status === 'online' ? SOUND_CONNECT : SOUND_DISCONNECT
|
||||
sound.currentTime = 0 // 重置音频播放位置
|
||||
|
||||
// 尝试播放声音
|
||||
const playPromise = sound.play()
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.catch(error => {
|
||||
console.error('音效播放失败:', error)
|
||||
// 如果是自动播放策略导致的失败,尝试在用户交互后播放
|
||||
if (error.name === 'NotAllowedError') {
|
||||
console.log('浏览器阻止了自动播放,将在下次用户交互时尝试播放')
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('音效处理失败:', error)
|
||||
}
|
||||
|
||||
ws.onclose = () => {
|
||||
setTimeout(initWebSocket, 5000)
|
||||
}
|
||||
ElNotification({
|
||||
title: status === 'online' ? '设备上线' : '设备离线',
|
||||
message: `${deviceName} ${status === 'online' ? '已连接到系统' : '已断开连接'}`,
|
||||
type: status === 'online' ? 'success' : 'warning',
|
||||
duration: 3000,
|
||||
position: 'top-right'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取无人机列表
|
||||
const getList = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
const res = await getDeviceList({
|
||||
page: pagination.value.page,
|
||||
@ -172,11 +315,10 @@ const getList = async () => {
|
||||
})
|
||||
|
||||
if (res.code === 200) {
|
||||
droneList.value = res.data.list.map(drone => {
|
||||
// 检查 WebSocket 连接状态
|
||||
const wsConnected = ws?.readyState === WebSocket.OPEN
|
||||
const deviceStatus = drone.status.code || drone.status
|
||||
const deviceOnline = wsConnected && deviceStatus === 1
|
||||
const newDroneList = res.data.list.map(drone => {
|
||||
// 检查设备状态
|
||||
const deviceStatus = drone.status?.code || drone.status
|
||||
const deviceOnline = deviceStatus === 1
|
||||
const status = deviceOnline ? 'online' : 'offline'
|
||||
|
||||
return {
|
||||
@ -190,6 +332,19 @@ const getList = async () => {
|
||||
}
|
||||
})
|
||||
|
||||
// 检查状态变化并发送通知
|
||||
if (droneList.value.length > 0) {
|
||||
newDroneList.forEach((newDrone) => {
|
||||
const oldDrone = droneList.value.find(d => d.code === newDrone.code)
|
||||
if (oldDrone && oldDrone.status !== newDrone.status) {
|
||||
showDeviceStatusNotification(newDrone.status, newDrone.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 更新列表
|
||||
droneList.value = newDroneList
|
||||
|
||||
// 在列表更新后,如果当前没有选中在线设备,则自动选择第一个在线设备
|
||||
const currentDrone = droneList.value[currentDroneIndex.value]
|
||||
if (!currentDrone || currentDrone.status !== 'online') {
|
||||
@ -238,6 +393,7 @@ const handleCurrentChange = (val) => {
|
||||
onActivated(() => {
|
||||
// 如果 WebSocket 未连接,重新连接
|
||||
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
||||
wsRetryCount.value = 0
|
||||
initWebSocket()
|
||||
}
|
||||
// 如果数据为空,则重新获取
|
||||
@ -264,14 +420,20 @@ onDeactivated(() => {
|
||||
})
|
||||
flvPlayers.value = []
|
||||
playingVideos.value.clear()
|
||||
|
||||
// 停止轮询
|
||||
stopPolling()
|
||||
})
|
||||
|
||||
// 修改 onMounted
|
||||
onMounted(() => {
|
||||
// 初始化 WebSocket 连接
|
||||
initWebSocket()
|
||||
// 获取无人机列表
|
||||
wsRetryCount.value = 0
|
||||
// 预加载音频
|
||||
preloadSounds()
|
||||
// 先获取列表
|
||||
getList()
|
||||
// 然后初始化 WebSocket 连接
|
||||
initWebSocket()
|
||||
})
|
||||
|
||||
// 修改 onUnmounted
|
||||
@ -285,6 +447,16 @@ onUnmounted(() => {
|
||||
destroyFlvPlayer(mainFlvPlayer.value)
|
||||
}
|
||||
flvPlayers.value.forEach(player => destroyFlvPlayer(player))
|
||||
|
||||
// 清理定时器
|
||||
if (wsRetryTimer) {
|
||||
clearTimeout(wsRetryTimer)
|
||||
wsRetryTimer = null
|
||||
}
|
||||
stopPolling()
|
||||
|
||||
// 重置重试次数
|
||||
wsRetryCount.value = 0
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -3,10 +3,285 @@ import { ref, onMounted, onUnmounted } from "vue";
|
||||
import { Plus, Monitor, Timer } from "@element-plus/icons-vue";
|
||||
import { ElMessage, ElNotification } from "element-plus";
|
||||
import { getDeviceList, deleteDevice } from "@/api/device";
|
||||
import * as echarts from 'echarts';
|
||||
import soundEffect from '@/utils/SoundEffect';
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false);
|
||||
|
||||
// 图表相关
|
||||
const chartDialogVisible = ref(false);
|
||||
const chartInstance = ref(null);
|
||||
const chartData = ref([]);
|
||||
const currentSensor = ref(null);
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (!chartInstance.value) {
|
||||
const chartDom = document.getElementById('sensorChart');
|
||||
if (!chartDom) return;
|
||||
|
||||
chartInstance.value = echarts.init(chartDom);
|
||||
}
|
||||
|
||||
const option = {
|
||||
backgroundColor: '#ffffff',
|
||||
title: {
|
||||
text: 'TDS值实时监测趋势',
|
||||
left: 'center',
|
||||
top: 10,
|
||||
textStyle: {
|
||||
fontSize: 18,
|
||||
fontWeight: 500,
|
||||
color: '#333'
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.9)',
|
||||
borderColor: '#409EFF',
|
||||
borderWidth: 1,
|
||||
padding: [10, 15],
|
||||
textStyle: {
|
||||
color: '#666'
|
||||
},
|
||||
axisPointer: {
|
||||
type: 'line',
|
||||
lineStyle: {
|
||||
color: '#409EFF',
|
||||
opacity: 0.2,
|
||||
width: 2
|
||||
}
|
||||
},
|
||||
formatter: (params) => {
|
||||
const data = params[0];
|
||||
return `
|
||||
<div style="font-family: Arial, sans-serif;">
|
||||
<div style="color: #666; margin-bottom: 6px;">${data.name}</div>
|
||||
<div style="color: #333; font-weight: bold; font-size: 14px;">
|
||||
TDS值:${data.value} mg/L
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
top: 80,
|
||||
left: 60,
|
||||
right: 40,
|
||||
bottom: 60,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: chartData.value.map(item => item.time),
|
||||
axisLabel: {
|
||||
rotate: 45,
|
||||
formatter: (value) => {
|
||||
const [hour, minute, second] = value.split(':');
|
||||
return `${hour}:${minute}:${second}`;
|
||||
},
|
||||
color: '#666',
|
||||
fontSize: 12
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#eee'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#f5f5f5',
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: 'TDS值 (mg/L)',
|
||||
nameLocation: 'middle',
|
||||
nameGap: 45,
|
||||
nameTextStyle: {
|
||||
color: '#666',
|
||||
fontSize: 13,
|
||||
fontWeight: 500,
|
||||
padding: [0, 0, 10, 0]
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#eee'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666',
|
||||
fontSize: 12,
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#f5f5f5',
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: 'TDS值',
|
||||
type: 'line',
|
||||
data: chartData.value.map(item => item.value),
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
lineStyle: {
|
||||
width: 4,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#409EFF' },
|
||||
{ offset: 1, color: '#36CE9E' }
|
||||
]),
|
||||
shadowColor: 'rgba(64,158,255,0.3)',
|
||||
shadowBlur: 10
|
||||
},
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#409EFF' },
|
||||
{ offset: 1, color: '#36CE9E' }
|
||||
]),
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2,
|
||||
shadowColor: 'rgba(64,158,255,0.5)',
|
||||
shadowBlur: 5
|
||||
},
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(64,158,255,0.3)' },
|
||||
{ offset: 0.5, color: 'rgba(64,158,255,0.15)' },
|
||||
{ offset: 1, color: 'rgba(64,158,255,0.05)' }
|
||||
])
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderWidth: 3,
|
||||
borderColor: '#fff',
|
||||
shadowColor: 'rgba(64,158,255,0.8)',
|
||||
shadowBlur: 10
|
||||
}
|
||||
},
|
||||
animationDuration: 1000,
|
||||
animationEasing: 'cubicOut'
|
||||
}]
|
||||
};
|
||||
|
||||
// 根据不同的监测类型设置不同的y轴范围和渐变色
|
||||
if (currentSensor.value?.monitoringType === 'h') {
|
||||
option.yAxis.min = 1180;
|
||||
option.yAxis.max = 1190;
|
||||
option.series[0].lineStyle.color = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#36CE9E' },
|
||||
{ offset: 1, color: '#3B7FFF' }
|
||||
]);
|
||||
option.series[0].itemStyle.color = option.series[0].lineStyle.color;
|
||||
option.series[0].areaStyle.color = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(54,206,158,0.3)' },
|
||||
{ offset: 1, color: 'rgba(59,127,255,0.05)' }
|
||||
]);
|
||||
} else if (currentSensor.value?.monitoringType === 'c') {
|
||||
option.yAxis.min = 220;
|
||||
option.yAxis.max = 228;
|
||||
option.series[0].lineStyle.color = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#FF9F43' },
|
||||
{ offset: 1, color: '#FF6B6B' }
|
||||
]);
|
||||
option.series[0].itemStyle.color = option.series[0].lineStyle.color;
|
||||
option.series[0].areaStyle.color = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(255,159,67,0.3)' },
|
||||
{ offset: 1, color: 'rgba(255,107,107,0.05)' }
|
||||
]);
|
||||
} else if (currentSensor.value?.monitoringType === 'f') {
|
||||
option.yAxis.min = 466;
|
||||
option.yAxis.max = 474;
|
||||
option.series[0].lineStyle.color = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#845EF7' },
|
||||
{ offset: 1, color: '#BE4BDB' }
|
||||
]);
|
||||
option.series[0].itemStyle.color = option.series[0].lineStyle.color;
|
||||
option.series[0].areaStyle.color = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(132,94,247,0.3)' },
|
||||
{ offset: 1, color: 'rgba(190,75,219,0.05)' }
|
||||
]);
|
||||
}
|
||||
|
||||
chartInstance.value.setOption(option);
|
||||
}
|
||||
|
||||
// 窗口大小改变时重绘图表
|
||||
const handleResize = () => {
|
||||
if (chartInstance.value) {
|
||||
chartInstance.value.resize();
|
||||
}
|
||||
}
|
||||
|
||||
// 显示图表
|
||||
const showChart = (sensor) => {
|
||||
// 深拷贝传感器数据,确保不会相互影响
|
||||
currentSensor.value = JSON.parse(JSON.stringify(sensor));
|
||||
chartDialogVisible.value = true;
|
||||
|
||||
// 生成模拟数据
|
||||
const now = new Date();
|
||||
chartData.value = Array.from({ length: 10 }, (_, i) => {
|
||||
const time = new Date(now - (9 - i) * 1000);
|
||||
let value;
|
||||
|
||||
// 根据不同的监测类型生成不同范围的数据
|
||||
if (sensor.monitoringType === 'h') {
|
||||
// 海水 (1000-1370)
|
||||
value = 1185 + (Math.random() * 6 - 3);
|
||||
} else if (sensor.monitoringType === 'c') {
|
||||
// 茶水 (200-248)
|
||||
value = 224 + (Math.random() * 4 - 2);
|
||||
} else if (sensor.monitoringType === 'f') {
|
||||
// 芬达 (450-490)
|
||||
value = 470 + (Math.random() * 4 - 2);
|
||||
} else {
|
||||
value = sensor.data?.tds || 0;
|
||||
}
|
||||
|
||||
return {
|
||||
time: time.toLocaleTimeString('zh-CN', {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
}),
|
||||
value: Number(value.toFixed(2))
|
||||
};
|
||||
});
|
||||
|
||||
// 在下一个 tick 初始化图表
|
||||
setTimeout(() => {
|
||||
initChart();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 监听窗口大小变化
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', handleResize);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (chartInstance.value) {
|
||||
chartInstance.value.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
// 传感器列表数据
|
||||
const sensorList = ref([
|
||||
{
|
||||
@ -168,6 +443,53 @@ const dataRefreshTimers = ref({
|
||||
f: null,
|
||||
});
|
||||
|
||||
// 更新图表数据
|
||||
const updateChartData = (value) => {
|
||||
if (!chartDialogVisible.value) return;
|
||||
|
||||
const now = new Date();
|
||||
const time = now.toLocaleTimeString('zh-CN', {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
});
|
||||
|
||||
// 添加新数据点
|
||||
chartData.value.push({
|
||||
time,
|
||||
value: Number(value.toFixed(2))
|
||||
});
|
||||
|
||||
// 保持最多显示30个数据点
|
||||
if (chartData.value.length > 30) {
|
||||
chartData.value.shift();
|
||||
}
|
||||
|
||||
// 更新图表
|
||||
if (chartInstance.value) {
|
||||
chartInstance.value.setOption({
|
||||
xAxis: {
|
||||
data: chartData.value.map(item => item.time)
|
||||
},
|
||||
series: [{
|
||||
data: chartData.value.map(item => item.value)
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
// 更新当前传感器数据
|
||||
if (currentSensor.value) {
|
||||
currentSensor.value = {
|
||||
...currentSensor.value,
|
||||
data: {
|
||||
...currentSensor.value.data,
|
||||
tds: value
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 添加键盘事件处理函数
|
||||
const handleKeyPress = (event) => {
|
||||
const key = event.key.toLowerCase();
|
||||
@ -184,6 +506,17 @@ const handleKeyPress = (event) => {
|
||||
},
|
||||
}));
|
||||
|
||||
// 更新当前传感器状态
|
||||
if (currentSensor.value) {
|
||||
currentSensor.value = {
|
||||
...currentSensor.value,
|
||||
status: isOnline ? 0 : 1,
|
||||
data: {
|
||||
tds: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 清理所有定时器
|
||||
Object.entries(dataRefreshTimers.value).forEach(([timerKey, timer]) => {
|
||||
if (timer) {
|
||||
@ -192,6 +525,9 @@ const handleKeyPress = (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 播放对应的音效
|
||||
soundEffect.playStatusSound(!isOnline);
|
||||
|
||||
ElNotification({
|
||||
title: isOnline ? "设备离线" : "设备上线",
|
||||
message: isOnline ? "设备已停止工作" : "设备开始工作",
|
||||
@ -211,14 +547,17 @@ const handleKeyPress = (event) => {
|
||||
h: {
|
||||
// 海水参考值 (1000-1370)
|
||||
tds: 1185,
|
||||
monitoringType: 'h'
|
||||
},
|
||||
c: {
|
||||
// 茶水参考值 (200-248)
|
||||
tds: 224,
|
||||
monitoringType: 'c'
|
||||
},
|
||||
f: {
|
||||
// 芬达参考值 (450-490)
|
||||
tds: 470,
|
||||
monitoringType: 'f'
|
||||
},
|
||||
};
|
||||
|
||||
@ -233,7 +572,19 @@ const handleKeyPress = (event) => {
|
||||
data: {
|
||||
tds: null,
|
||||
},
|
||||
monitoringType: null
|
||||
}));
|
||||
|
||||
// 更新当前传感器状态
|
||||
if (currentSensor.value) {
|
||||
currentSensor.value = {
|
||||
...currentSensor.value,
|
||||
data: {
|
||||
tds: null
|
||||
},
|
||||
monitoringType: null
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -247,6 +598,19 @@ const handleKeyPress = (event) => {
|
||||
|
||||
// 开始新的数据刷新
|
||||
const startData = substanceData[key];
|
||||
sensorList.value = sensorList.value.map(sensor => ({
|
||||
...sensor,
|
||||
monitoringType: key
|
||||
}));
|
||||
|
||||
// 更新当前传感器监测类型
|
||||
if (currentSensor.value) {
|
||||
currentSensor.value = {
|
||||
...currentSensor.value,
|
||||
monitoringType: key
|
||||
};
|
||||
}
|
||||
|
||||
dataRefreshTimers.value[key] = setInterval(() => {
|
||||
// 生成随机波动值,根据不同液体设置不同的波动范围
|
||||
let randomValue;
|
||||
@ -278,6 +642,9 @@ const handleKeyPress = (event) => {
|
||||
tds: randomValue,
|
||||
},
|
||||
}));
|
||||
|
||||
// 更新图表数据
|
||||
updateChartData(randomValue);
|
||||
}, 1000); // 每秒更新一次
|
||||
}
|
||||
};
|
||||
@ -313,6 +680,7 @@ onUnmounted(() => {
|
||||
:key="sensor.id"
|
||||
class="sensor-card"
|
||||
:class="{ offline: sensor.status === 0 }"
|
||||
@click="showChart(sensor)"
|
||||
>
|
||||
<div class="card-header">
|
||||
<div class="sensor-info">
|
||||
@ -404,6 +772,41 @@ onUnmounted(() => {
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 图表对话框 -->
|
||||
<el-dialog
|
||||
v-model="chartDialogVisible"
|
||||
:title="currentSensor?.device_name"
|
||||
width="80%"
|
||||
destroy-on-close
|
||||
@closed="chartInstance = null"
|
||||
>
|
||||
<div class="chart-container">
|
||||
<!-- TDS值显示区域 -->
|
||||
<div class="tds-display">
|
||||
<div class="tds-value">
|
||||
<span class="label">实时TDS值</span>
|
||||
<span class="value" :class="{ 'offline': currentSensor?.status === 0 }">
|
||||
{{ formatValue(currentSensor?.data?.tds, 'mg/L') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="tds-info">
|
||||
<el-tag
|
||||
:type="currentSensor?.status === 1 ? 'success' : 'info'"
|
||||
size="large"
|
||||
>
|
||||
{{ currentSensor?.status === 1 ? '在线监测中' : '设备离线' }}
|
||||
</el-tag>
|
||||
<span class="update-time">
|
||||
<el-icon><Timer /></el-icon>
|
||||
更新时间: {{ new Date().toLocaleTimeString('zh-CN', { hour12: false }) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 图表区域 -->
|
||||
<div id="sensorChart" style="width: 100%; height: 400px;"></div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -450,10 +853,11 @@ onUnmounted(() => {
|
||||
overflow: hidden;
|
||||
transition: all 0.3s;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
@ -628,4 +1032,58 @@ onUnmounted(() => {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加图表相关样式
|
||||
.chart-container {
|
||||
.tds-display {
|
||||
background: #f8f9fb;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.tds-value {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.label {
|
||||
font-size: 16px;
|
||||
color: #606266;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 48px;
|
||||
font-weight: 600;
|
||||
color: #409EFF;
|
||||
font-family: "DIN Alternate", sans-serif;
|
||||
|
||||
&.offline {
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tds-info {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
|
||||
.update-time {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
.el-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -10,10 +10,7 @@ import {
|
||||
Connection,
|
||||
Loading
|
||||
} from '@element-plus/icons-vue'
|
||||
|
||||
// 音效资源
|
||||
const SOUND_CONNECT = new Audio('/src/assets/harmonyos-sound/notification_accomplished_08.wav')
|
||||
const SOUND_DISCONNECT = new Audio('/src/assets/harmonyos-sound/notification_wrong_04.wav')
|
||||
import soundEffect from '@/utils/SoundEffect'
|
||||
|
||||
// 添加用户交互标记
|
||||
let hasUserInteracted = false
|
||||
@ -26,17 +23,6 @@ const handleUserInteraction = () => {
|
||||
document.removeEventListener('keydown', handleUserInteraction)
|
||||
}
|
||||
|
||||
// 播放音效
|
||||
const playSound = (status) => {
|
||||
if (!hasUserInteracted) return
|
||||
|
||||
const sound = status === 'online' ? SOUND_CONNECT : SOUND_DISCONNECT
|
||||
sound.currentTime = 0 // 重置音频播放位置
|
||||
sound.play().catch(error => {
|
||||
console.error('音效播放失败:', error)
|
||||
})
|
||||
}
|
||||
|
||||
// 无人机数据
|
||||
const drone = ref(null)
|
||||
const loading = ref(false)
|
||||
@ -55,101 +41,228 @@ let wsRetryCount = 0
|
||||
const MAX_RETRY_COUNT = 3
|
||||
let wsRetryTimer = null
|
||||
|
||||
// 存储键名常量
|
||||
const CHART_DATA_STORAGE_KEY = 'wetland_ph_chart_data'
|
||||
const CHART_DATA_TIMESTAMP_KEY = 'wetland_ph_chart_timestamp'
|
||||
const CHART_DATA_EXPIRE_TIME = 24 * 60 * 60 * 1000 // 24小时过期
|
||||
|
||||
// 保存图表数据到本地存储
|
||||
const saveChartDataToStorage = (data) => {
|
||||
try {
|
||||
localStorage.setItem(CHART_DATA_STORAGE_KEY, JSON.stringify(data))
|
||||
localStorage.setItem(CHART_DATA_TIMESTAMP_KEY, Date.now().toString())
|
||||
} catch (error) {
|
||||
console.error('保存图表数据到本地存储失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 从本地存储获取图表数据
|
||||
const getChartDataFromStorage = () => {
|
||||
try {
|
||||
const timestamp = localStorage.getItem(CHART_DATA_TIMESTAMP_KEY)
|
||||
if (!timestamp) return null
|
||||
|
||||
// 检查数据是否过期
|
||||
if (Date.now() - parseInt(timestamp) > CHART_DATA_EXPIRE_TIME) {
|
||||
localStorage.removeItem(CHART_DATA_STORAGE_KEY)
|
||||
localStorage.removeItem(CHART_DATA_TIMESTAMP_KEY)
|
||||
return null
|
||||
}
|
||||
|
||||
const data = localStorage.getItem(CHART_DATA_STORAGE_KEY)
|
||||
return data ? JSON.parse(data) : null
|
||||
} catch (error) {
|
||||
console.error('从本地存储获取图表数据失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// 获取图表数据
|
||||
const getChartData = async () => {
|
||||
try {
|
||||
const res = await generateChartData({
|
||||
message: "ph柱状图"
|
||||
})
|
||||
|
||||
if (res.success) {
|
||||
initChart(res.data)
|
||||
console.log('完整的响应数据:', res);
|
||||
console.log('图表配置数据:', res.data?.echart_options);
|
||||
|
||||
if (!res.data?.echart_options) {
|
||||
console.error('图表配置数据结构不完整');
|
||||
// 尝试使用本地存储的数据
|
||||
const storageData = getChartDataFromStorage()
|
||||
if (storageData) {
|
||||
console.log('使用本地存储的图表数据');
|
||||
initChart(storageData)
|
||||
} else {
|
||||
initChart(getDefaultChartData().echart_options)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存新数据到本地存储
|
||||
saveChartDataToStorage(res.data.echart_options)
|
||||
initChart(res.data.echart_options)
|
||||
} else {
|
||||
console.error('获取图表数据失败:', res.message)
|
||||
initChart(getDefaultChartData())
|
||||
// 尝试使用本地存储的数据
|
||||
const storageData = getChartDataFromStorage()
|
||||
if (storageData) {
|
||||
console.log('使用本地存储的图表数据');
|
||||
initChart(storageData)
|
||||
} else {
|
||||
initChart(getDefaultChartData().echart_options)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取图表数据失败:', error)
|
||||
initChart(getDefaultChartData())
|
||||
// 尝试使用本地存储的数据
|
||||
const storageData = getChartDataFromStorage()
|
||||
if (storageData) {
|
||||
console.log('使用本地存储的图表数据');
|
||||
initChart(storageData)
|
||||
} else {
|
||||
initChart(getDefaultChartData().echart_options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化图表
|
||||
const initChart = (data) => {
|
||||
if (!chartRef.value) return
|
||||
|
||||
if (chart) {
|
||||
chart.dispose()
|
||||
const initChart = (options) => {
|
||||
|
||||
if (!chartRef.value) {
|
||||
console.error('图表DOM引用未找到');
|
||||
return;
|
||||
}
|
||||
|
||||
chart = echarts.init(chartRef.value)
|
||||
try {
|
||||
if (chart) {
|
||||
chart.dispose()
|
||||
}
|
||||
|
||||
// 直接使用后端返回的配置,只添加必要的样式
|
||||
const option = {
|
||||
backgroundColor: 'transparent',
|
||||
title: {
|
||||
...data.echart_options.title,
|
||||
textStyle: {
|
||||
color: '#fff'
|
||||
}
|
||||
},
|
||||
tooltip: data.echart_options.tooltip,
|
||||
legend: {
|
||||
...data.echart_options.legend,
|
||||
textStyle: {
|
||||
color: '#fff'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: data.echart_options.series[0].xAxis.data,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(255, 255, 255, 0.3)'
|
||||
chart = echarts.init(chartRef.value)
|
||||
|
||||
// 检查必要的数据结构
|
||||
if (!options.xAxis?.data && !options.series?.[0]?.data) {
|
||||
console.error('数据结构不正确,使用默认配置');
|
||||
options = getDefaultChartData().echart_options;
|
||||
}
|
||||
|
||||
// 确保 yAxis 配置正确
|
||||
const yAxisConfig = Array.isArray(options.yAxis) ? options.yAxis[0] : options.yAxis;
|
||||
|
||||
const option = {
|
||||
backgroundColor: 'transparent',
|
||||
title: {
|
||||
...(options.title || { text: 'pH值变化趋势' }),
|
||||
textStyle: {
|
||||
color: '#fff'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: 'rgba(255, 255, 255, 0.7)'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: 'pH值',
|
||||
max: 8,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(255, 255, 255, 0.3)'
|
||||
tooltip: options.tooltip || {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: 'rgba(255, 255, 255, 0.7)'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(255, 255, 255, 0.1)'
|
||||
legend: {
|
||||
...(options.legend || {}),
|
||||
textStyle: {
|
||||
color: '#fff'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: '酸性指数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: data.echart_options.series[0].xAxis.data.map(() => (Math.random() * 2 + 6).toFixed(1)), // 临时随机数据
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(64, 158, 255, 0.7)' },
|
||||
{ offset: 1, color: 'rgba(64, 158, 255, 0.1)' }
|
||||
])
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#409EFF'
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: options.xAxis?.data || [],
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(255, 255, 255, 0.3)'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: 'rgba(255, 255, 255, 0.7)'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: 'pH值',
|
||||
max: 8,
|
||||
...(yAxisConfig || {}),
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(255, 255, 255, 0.3)'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: 'rgba(255, 255, 255, 0.7)'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(255, 255, 255, 0.1)'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: Array.isArray(options.series) ? options.series.map(series => ({
|
||||
...series,
|
||||
yAxisIndex: 0, // 确保所有系列都使用同一个 yAxis
|
||||
areaStyle: series.areaStyle || {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(64, 158, 255, 0.7)' },
|
||||
{ offset: 1, color: 'rgba(64, 158, 255, 0.1)' }
|
||||
])
|
||||
}
|
||||
})) : [
|
||||
{
|
||||
name: 'pH值',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
yAxisIndex: 0,
|
||||
data: [],
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(64, 158, 255, 0.7)' },
|
||||
{ offset: 1, color: 'rgba(64, 158, 255, 0.1)' }
|
||||
])
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 设置配置前确保数据结构完整
|
||||
if (!option.yAxis || !option.xAxis || !option.series) {
|
||||
throw new Error('图表配置数据结构不完整');
|
||||
}
|
||||
|
||||
chart.setOption(option)
|
||||
|
||||
// 确保图表正确渲染
|
||||
nextTick(() => {
|
||||
if (chart) {
|
||||
chart.resize()
|
||||
}
|
||||
}]
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('图表初始化失败:', error);
|
||||
// 尝试使用完全默认的配置重新初始化
|
||||
try {
|
||||
if (chart) {
|
||||
const defaultOption = getDefaultChartData().echart_options;
|
||||
chart.setOption(defaultOption);
|
||||
}
|
||||
} catch (retryError) {
|
||||
console.error('使用默认配置重试失败:', retryError);
|
||||
}
|
||||
}
|
||||
|
||||
chart.setOption(option)
|
||||
}
|
||||
|
||||
// 生成默认图表数据
|
||||
// 修改默认图表数据的结构
|
||||
const getDefaultChartData = () => {
|
||||
return {
|
||||
echart_options: {
|
||||
@ -169,18 +282,17 @@ const getDefaultChartData = () => {
|
||||
type: "category",
|
||||
data: []
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: "value",
|
||||
name: "pH值",
|
||||
max: 8
|
||||
}
|
||||
],
|
||||
yAxis: {
|
||||
type: "value",
|
||||
name: "pH值",
|
||||
max: 8
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "pH值",
|
||||
type: "line",
|
||||
smooth: true,
|
||||
yAxisIndex: 0,
|
||||
areaStyle: {},
|
||||
data: []
|
||||
}
|
||||
@ -192,7 +304,7 @@ const getDefaultChartData = () => {
|
||||
// 显示设备状态通知
|
||||
const showDeviceStatusNotification = (status) => {
|
||||
// 播放对应音效
|
||||
playSound(status)
|
||||
soundEffect.playStatusSound(status === 'online')
|
||||
|
||||
ElNotification({
|
||||
title: status === 'online' ? '设备已接入' : '设备已接出',
|
||||
@ -222,7 +334,6 @@ const initWebSocket = () => {
|
||||
ws = new WebSocket('ws://127.0.0.1:6894')
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('WebSocket连接成功')
|
||||
wsConnected.value = true
|
||||
wsRetryCount = 0 // 重置重试次数
|
||||
if (wsRetryTimer) {
|
||||
@ -300,6 +411,7 @@ const initWebSocket = () => {
|
||||
} else {
|
||||
// 否则尝试重连
|
||||
wsRetryTimer = setTimeout(() => {
|
||||
|
||||
console.log(`尝试WebSocket重连 (${wsRetryCount}/${MAX_RETRY_COUNT})...`)
|
||||
initWebSocket()
|
||||
}, 5000 * Math.min(wsRetryCount, 3)) // 重试间隔随次数增加但最多15秒
|
||||
@ -579,6 +691,13 @@ onMounted(() => {
|
||||
document.addEventListener('click', handleUserInteraction)
|
||||
document.addEventListener('keydown', handleUserInteraction)
|
||||
|
||||
// 初始化时先尝试使用本地存储的数据
|
||||
const storageData = getChartDataFromStorage()
|
||||
if (storageData) {
|
||||
console.log('使用本地存储的图表数据初始化');
|
||||
initChart(storageData)
|
||||
}
|
||||
|
||||
// 初始化WebSocket连接
|
||||
initWebSocket()
|
||||
// 获取无人机信息
|
||||
|
@ -4,6 +4,7 @@ import path from 'path'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user