无人机显示调试,声音打开,右下角赋值

This commit is contained in:
zengmingjie 2025-06-21 20:00:17 +08:00
parent 7e19706ab9
commit d8f87fdf88
20 changed files with 1025 additions and 363 deletions

View File

@ -1,3 +1,3 @@
NODE_ENV = 'development'
VUE_APP_API_URL = 'http://114.66.57.139:8088'
VUE_APP_API_URL = 'http://114.66.57.139:5002'
VUE_APP_MESSAGE_SDK_DEBUG = true

212
package-lock.json generated
View File

@ -7,6 +7,8 @@
"": {
"version": "0.1.0",
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@fit-screen/vue": "^1.0.2",
"@microsoft/signalr": "^8.0.7",
"@vue-office/docx": "^1.6.2",
"@vue-office/excel": "^1.7.11",
@ -18,8 +20,10 @@
"echarts-liquidfill": "^3.1.0",
"element-ui": "^2.15.10",
"file-saver": "^2.0.5",
"lodash": "^4.17.21",
"moment": "^2.30.1",
"ol": "^10.5.0",
"qrcode": "^1.5.4",
"vue": "^2.7.16",
"vue-router": "^3.5.1",
"vueshowpdf": "^1.1.2",
@ -79,6 +83,11 @@
"node": "8 || 9 || 10 || 11 || 12 || 13 || 14 || 15 || 16 || 17 || 18"
}
},
"node_modules/@amap/amap-jsapi-loader": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
"integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw=="
},
"node_modules/@ampproject/remapping": {
"version": "2.2.0",
"resolved": "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.2.0.tgz",
@ -1933,6 +1942,47 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@fit-screen/vue": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/@fit-screen/vue/-/vue-1.0.2.tgz",
"integrity": "sha512-Byd+yyZhMw4x7kSfbCNG212EZxrGRi6L+dsAZi+JsbIUm6Wb+/xd6d5cfhtPJ/eubLbcKLVOstlRjQaj2NPJdQ==",
"dependencies": {
"vue-demi": "^0.13.11"
},
"peerDependencies": {
"vue": "^2.6.14 || ^3.2.39"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@fit-screen/vue/node_modules/vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@gar/promisify": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/@gar/promisify/-/promisify-1.1.3.tgz",
@ -4560,7 +4610,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -7380,7 +7429,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -7869,6 +7917,11 @@
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"node_modules/dijkstrajs": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
},
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz",
@ -8308,8 +8361,7 @@
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/emojis-list": {
"version": "3.0.0",
@ -9946,7 +9998,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
@ -10280,7 +10331,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
@ -12829,7 +12879,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -16303,7 +16352,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"dependencies": {
"p-locate": "^4.1.0"
},
@ -16314,8 +16362,7 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
@ -18014,7 +18061,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"dependencies": {
"p-try": "^2.0.0"
},
@ -18029,7 +18075,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"dependencies": {
"p-limit": "^2.2.0"
},
@ -18114,7 +18159,6 @@
"version": "2.2.0",
"resolved": "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true,
"engines": {
"node": ">=6"
}
@ -18222,7 +18266,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -18360,6 +18403,14 @@
"semver-compare": "^1.0.0"
}
},
"node_modules/pngjs": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz",
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/pngquant-bin": {
"version": "9.0.0",
"resolved": "https://registry.npmmirror.com/pngquant-bin/-/pngquant-bin-9.0.0.tgz",
@ -19574,6 +19625,121 @@
"node": ">=6"
}
},
"node_modules/qrcode": {
"version": "1.5.4",
"resolved": "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz",
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
"dependencies": {
"dijkstrajs": "^1.0.1",
"pngjs": "^5.0.0",
"yargs": "^15.3.1"
},
"bin": {
"qrcode": "bin/qrcode"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/qrcode/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/qrcode/node_modules/camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"engines": {
"node": ">=6"
}
},
"node_modules/qrcode/node_modules/cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"node_modules/qrcode/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/qrcode/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/qrcode/node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
},
"node_modules/qrcode/node_modules/yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"dependencies": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"dependencies": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz",
@ -19998,7 +20164,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -20012,6 +20177,11 @@
"node": ">=0.10.0"
}
},
"node_modules/require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz",
@ -20599,6 +20769,11 @@
"node": ">= 0.8.0"
}
},
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
"node_modules/set-cookie-parser": {
"version": "2.7.0",
"resolved": "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz",
@ -21301,7 +21476,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@ -21378,7 +21552,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
@ -24057,6 +24230,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-module": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz",
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
},
"node_modules/which-typed-array": {
"version": "1.1.15",
"resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.15.tgz",

View File

@ -12,6 +12,8 @@
"start:vite": "vite"
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@fit-screen/vue": "^1.0.2",
"@microsoft/signalr": "^8.0.7",
"@vue-office/docx": "^1.6.2",
"@vue-office/excel": "^1.7.11",
@ -23,8 +25,10 @@
"echarts-liquidfill": "^3.1.0",
"element-ui": "^2.15.10",
"file-saver": "^2.0.5",
"lodash": "^4.17.21",
"moment": "^2.30.1",
"ol": "^10.5.0",
"qrcode": "^1.5.4",
"vue": "^2.7.16",
"vue-router": "^3.5.1",
"vueshowpdf": "^1.1.2",
@ -72,4 +76,4 @@
"gitHooks": {
"pre-commit": "lint-staged"
}
}
}

View File

@ -8,3 +8,12 @@ export function Homeview(data) {
params: data
});
}
// 实时位置信息
export function HomeSyncLocation(data) {
let url = "/api/Home/syncLocation";
return request({
url: url,
method: "post",
data
});
}

View File

@ -8,3 +8,12 @@ export function login(data) {
data
});
}
// 登录后 获取当前防区
export function loginPosition(data) {
return request({
url: "/api/Position/Details",
method: "post",
data
});
}

View File

@ -84,6 +84,7 @@ body {
background-position: center;
padding: 0;
margin: 0;
pointer-events: none;
.header-left {
width: 20%;
height: 35px;
@ -228,6 +229,8 @@ body {
font-weight: 400;
text-align: left;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
}
}
.main {
@ -246,6 +249,8 @@ body {
.color-ef {
color: #0144ef;
font-size: 1.09vw;
overflow: hidden;
text-overflow: ellipsis;
}
.text-fff {
color: #000;
@ -292,6 +297,8 @@ body {
font-weight: 400;
text-align: left;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
}
}
.content-main {
@ -301,6 +308,8 @@ body {
.color-ef {
color: #0144ef;
font-size: 1.09vw;
overflow: hidden;
text-overflow: ellipsis;
}
.text-fff {
color: #000;
@ -328,6 +337,8 @@ body {
width: 100%;
height: 7%;
text-align: left;
display: flex;
align-items: center;
.text-fff {
// 超出隐藏
overflow: hidden;
@ -468,10 +479,13 @@ body {
.navigation-content-qrcode {
width: 80px;
height: 80px;
background-color: red;
margin: 0 auto;
margin-top: 5px;
margin-bottom: 5px;
img {
width: 100%;
height: 100%;
}
}
}
.navigation-content-btn {

BIN
src/assets/img/icon_uav.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -9,10 +9,10 @@ import "@/components/index.js";
import "@/plugins/element";
// 样式加载
import "@/assets/css/index.scss";
import FitScreen from "@fit-screen/vue";
// 全局事件总线bus
Vue.prototype.$bus = new Vue({});
Vue.use(FitScreen);
new Vue({
router,
store,

View File

@ -16,6 +16,9 @@ const routes = [
// 登录已过期,执行自动退出操作
localStorage.removeItem("setToken");
localStorage.removeItem("expires");
localStorage.removeItem("userId");
localStorage.removeItem("isAdmin");
localStorage.removeItem("PositionIds");
next("/login");
}
const token = localStorage.getItem("setToken");

View File

@ -6,6 +6,8 @@ const getters = {
map: (state) => state.map.map,
adsbisFlag: (state) => state.map.adsbisFlag, //是否显示adsb
targetCode: (state) => state.chart.targetCode, //防护目标单一点击更改两侧数据
airspaceCode: (state) => state.chart.airspaceCode //低空空域单一点击更改两侧数据
airspaceCode: (state) => state.chart.airspaceCode, //低空空域单一点击更改两侧数据
positionPoint: (state) => state.chart.positionPoint, //实时位置更新
isZoomedIn: (state) => state.chart.isZoomedIn //音频是否打开
};
export default getters;

View File

@ -8,7 +8,10 @@ const user = {
endTime: ""
},
targetCode: {},
airspaceCode: {}
airspaceCode: {},
positionPoint: false, // 位置上报
isZoomedIn: true // 音频是否打开
},
mutations: {
@ -29,6 +32,12 @@ const user = {
},
SET_AIRSPACECODE: (state, value) => {
state.airspaceCode = value;
},
SET_POSITIONPOINT: (state, value) => {
state.positionPoint = value;
},
SET_ISZOOMEDIN: (state, value) => {
state.isZoomedIn = value;
}
},

View File

@ -33,6 +33,9 @@ service.interceptors.response.use(
// 登录已过期,执行自动退出操作
localStorage.removeItem("setToken");
localStorage.removeItem("expires");
localStorage.removeItem("userId");
localStorage.removeItem("isAdmin");
localStorage.removeItem("PositionIds");
router.push("/login");
}
const res = response.data;

View File

@ -13,13 +13,16 @@
<li
v-for="(drone, index) in drones"
:key="index"
@click="handleDroneClick(drone)"
:style="{
height: drone.detailsShow ? '60px' : '372px',
height: droneStates[drone.BatchId] ? '60px' : '372px',
padding: 0
}"
>
<div class="details-one" v-if="drone.detailsShow">
<div
class="details-one"
v-if="droneStates[drone.BatchId]"
@click="handleDroneClick(drone)"
>
<div class="top">
<div class="left">
{{ index < 9 ? "0" + (index + 1) : index + 1 }}
@ -33,7 +36,7 @@
<div class="top_main">
<div class="text">
<span class="color-ef">距离</span>
<span class="text-fff">{{ drone.currTime || 0 }}</span>
<span class="text-fff">{{ drone.distance || 0 }}</span>
</div>
<div class="text">
<span class="color-ef">高度</span>
@ -42,7 +45,7 @@
</div>
</div>
</div>
<div class="details-all" v-else>
<div class="details-all" v-else @click="handleDroneClick(drone)">
<div class="top">
<div class="left">
{{ index < 9 ? "0" + (index + 1) : index + 1 }}
@ -56,29 +59,29 @@
<div class="content-top">
<div class="top-left">
<span class="color-ef"> 距离</span>
<span class="text-fff">{{ drone.currTime || 0 }}</span>
<span class="text-fff">{{ drone.distance || 0 }}</span>
</div>
<div class="top-right">
<span class="color-ef"> 高度</span>
<span class="text-fff">{{ drone.height || 0 }}</span>
</div>
</div>
<div class="content-serial">
<!-- <div class="content-serial">
<span class="color-ef"> 序列号</span>
<span class="text-fff">11VJF4D00201LE</span>
</div>
<span class="text-fff">{{ drone.serial_number }}</span>
</div> -->
<div class="content-serial">
<span class="color-ef"> 型号</span>
<span class="text-fff">DJI Air 2S</span>
<span class="text-fff">{{ drone.device_type }}</span>
</div>
<div class="content-serial">
<span class="color-ef"> 更新时间</span>
<span class="text-fff-time">2025.6.15 21:12:43</span>
<span class="text-fff-time">{{ drone.times }}</span>
</div>
<div class="content-serial">
<span class="color-ef-fw">无人机方位</span>
</div>
<div class="content-serial" style="height: 22%">
<div class="content-serial" style="height: 35%">
<div class="content-potions">
<div class="content-potions-lon">
<p class="text">经纬度</p>
@ -91,62 +94,90 @@
<p class="text">高度</p>
<p class="characters">{{ drone.height || 0 }}M</p>
</div>
<div class="content-text content-potions-speed">
<p class="text">速度</p>
<p class="characters">{{ drone.height }}M/h</p>
</div>
</div>
<div class="content-potions-lon">
<p class="text">速度</p>
<p class="characters">
E{{ drone.speed_E }} N{{ drone.speed_N }} U{{
drone.speed_U
}}
</p>
</div>
</div>
</div>
<div class="content-serial">
<span class="color-ef-fw">飞手</span>
<span class="color-ef-fw">飞手</span>
</div>
<div class="content-serial" style="height: 22%">
<div class="content-serial" style="height: 15%">
<div class="content-fs">
<div class="content-fs-lon">
<p class="text">经纬度</p>
<p class="characters">
{{ drone.drone_lon }}, {{ drone.drone_lat }}
{{ drone.app_lon }}, {{ drone.app_lat }}
</p>
</div>
<div class="content-fs-heig">
<p class="text">高度</p>
<p class="characters">{{ drone.height || 0 }}m</p>
</div>
</div>
</div>
<div class="content-serial" style="height: 10%">
<div class="btns">
<div class="btn-trust">
<el-button type="primary">信任</el-button>
<el-button
type="primary"
@click.stop="handlewhiteList(drone)"
>
信任
</el-button>
</div>
<div class="btn-navigation">
<el-button type="primary">导航</el-button>
<el-button
type="primary"
@click.stop="handleNavigation(drone)"
>
导航
</el-button>
</div>
</div>
</div>
</div>
</div>
<div class="navigation-content" v-if="!drone.detailsShow">
<div class="navigation-content-text">
<div
class="navigation-content"
v-if="navigationStates[drone.BatchId]"
>
<!-- <div class="navigation-content-text">
<span class="color-ef">距飞手</span>
<span class="text-fff">{{ drone.height || 0 }}</span>
</div> -->
<div class="navigation-content-text" style="text-align: center">
<span class="color-ef" style="font-weight: 800">
导航高德地图
</span>
</div>
<div class="navigation-content-text">
<span class="color-ef">距我</span>
<span class="text-fff">{{ drone.height || 0 }}</span>
<div class="navigation-content-qrcode">
<img
v-if="qrCodes[drone.BatchId]"
:src="qrCodes[drone.BatchId]"
alt="导航二维码"
/>
<span v-else>二维码生成中...</span>
</div>
<div class="navigation-content-qrcode"></div>
<div class="navigation-content-text">
<span class="text-fff">跳转到导航系统</span>
</div>
<div class="navigation-content-btn">
<div class="btns">
<div class="btn-trust">
<el-button type="primary"></el-button>
<el-button
type="primary"
@click.stop="closeNavigation(drone)"
>
</el-button>
</div>
<div class="btn-navigation">
<el-button type="primary"></el-button>
<el-button type="primary" @click.stop="noNavigation(drone)">
</el-button>
</div>
</div>
</div>
@ -160,6 +191,7 @@
ref="uavAudio"
v-show="iswarning"
style="display: none"
id="uavAudio"
>
<source src="@/assets/img/wargin.mp3" type="audio/mpeg" />
</audio>
@ -172,8 +204,16 @@
</template>
<script>
import { mapGetters } from "vuex";
import moment from "moment";
import { mapUavFiex } from "../index.js";
import Style from "ol/style/Style";
import Stroke from "ol/style/Stroke";
import { fromLonLat, toLonLat } from "ol/proj";
import { whitListAdd } from "@/api/whitList.js";
import AMapLoader from "@amap/amap-jsapi-loader";
import QRCode from "qrcode";
export default {
name: "LeftSidebar",
props: {
@ -194,89 +234,38 @@ export default {
{
id: "1",
name: "今日预警",
value: 20
value: 0
},
{
id: "2",
name: "累计预警",
value: 20
}
],
drones: [
{
id: "1",
serial_number: "123456789",
DeviceName: "设备名称",
freq: "123.456GHz",
device_type: "UAV",
drone_lat: 30.592852,
drone_lon: 104.060059,
height: 100,
alarmLevel: 1,
times: "2021-01-01 12:00:00",
BatchId: "123456789",
DeviceId: "123456789",
currTime: 15,
detailsShow: true
},
{
id: "1",
serial_number: "123456789",
DeviceName: "设备名称",
freq: "123.456GHz",
device_type: "UAV",
drone_lat: 30.592852,
drone_lon: 104.060059,
height: 100,
alarmLevel: 1,
times: "2021-01-01 12:00:00",
BatchId: "123456789",
DeviceId: "123456789",
currTime: 15,
detailsShow: true
},
{
id: "1",
serial_number: "123456789",
DeviceName: "设备名称",
freq: "123.456GHz",
device_type: "UAV",
drone_lat: 30.592852,
drone_lon: 104.060059,
height: 100,
alarmLevel: 1,
times: "2021-01-01 12:00:00",
BatchId: "123456789",
DeviceId: "123456789",
currTime: 15,
detailsShow: true
},
{
id: "1",
serial_number: "123456789",
DeviceName: "设备名称",
freq: "123.456GHz",
device_type: "UAV",
drone_lat: 30.592852,
drone_lon: 104.060059,
height: 100,
alarmLevel: 1,
times: "2021-01-01 12:00:00",
BatchId: "123456789",
DeviceId: "123456789",
currTime: 15,
detailsShow: true
value: 0
}
],
drones: [],
droneStates: {}, // detailsShow
navigationStates: {}, // navigation-content
qrCodes: {}, // URL
isContracted: false,
homeView: {},
droneTimers: new Map(),
iswarning: false,
showAudioPrompt: false
showAudioPrompt: false,
startTime: "", //
endTime: "",
qrCodeUrl: ""
};
},
computed: {
...mapGetters(["isZoomedIn"])
},
mounted() {
this.startTracking();
this.endTime = moment.utc().format("YYYY-MM-DD HH:mm:ss");
this.startTime = moment
.utc()
.subtract(1, "month")
.format("YYYY-MM-DD HH:mm:ss");
console.log("Initialized time range:", this.startTime, "to", this.endTime);
},
watch: {
homeData: {
@ -284,14 +273,45 @@ export default {
this.homeView = newVal;
this.warningDay[0].value = newVal.alarmCount.todaywaring;
this.warningDay[1].value = newVal.alarmCount.totalcount;
this.warningDay[2].value = newVal.alarmCount.todayhandle;
this.warningDay[3].value = newVal.alarmCount.totalhandle;
},
deep: true
},
signaData: {
handler(newVal) {
if (newVal) {
console.log(newVal, "newVal");
// newVal = [
// {
// BatchId: "1936279216064696320",
// serial_number: "1581F6CDC23B6003DTL2",
// device_type: "8",
// device_type_8: 91088,
// app_lat: 39.055,
// app_lon: 117.303466,
// drone_lat: 39.040924,
// drone_lon: 117.337103,
// height: 0.0,
// altitude: 0.0,
// home_lat: 0.0,
// home_lon: 0.0,
// distance: 3299.608332218683,
// centerdistance: 5023.652200054709,
// IsWhitelist: false,
// speed_E: 12210.0,
// speed_N: 3120.0,
// speed_U: 130.0,
// RSSI: 0.0,
// positionId: "1924768527160578048",
// PostionName: "louding",
// DeviceId: "1924798246178394112",
// DeviceName: "0007",
// freq: 0.0,
// alarmLevel: 0,
// Time: 1744872277,
// CreateTime: "2025-06-21T12:25:14.0948095+08:00",
// Id: "1936279217155215360"
// }
// ];
newVal.forEach((newItem) => {
// BatchId
if (newItem.BatchId) {
@ -306,15 +326,28 @@ export default {
const timer = this.startTimer(newItem);
this.droneTimers.set(newItem.BatchId, timer);
// detailsShow
if (!(newItem.BatchId in this.droneStates)) {
this.$set(this.droneStates, newItem.BatchId, true);
}
// navigation-content
if (!(newItem.BatchId in this.navigationStates)) {
this.$set(this.navigationStates, newItem.BatchId, false);
}
//
const existingIndex = this.drones.findIndex(
(d) => d.BatchId === newItem.BatchId
);
newItem.times = moment(newItem.CreateTime).format("HH:mm:ss");
newItem.distance = parseInt(newItem.distance.toFixed(0));
// newItem.drone_lon = newItem.drone_lon.toFixed(6);
// newItem.drone_lat = newItem.drone_lat.toFixed(6);
if (existingIndex !== -1) {
this.$set(this.drones, existingIndex, { ...newItem });
} else {
this.drones.push({ ...newItem });
this.$set(this.drones, this.drones.length, { ...newItem });
}
}
});
@ -324,10 +357,10 @@ export default {
}
if (this.drones) {
mapUavFiex(this.drones);
mapUavFiex(this.drones, window.olMap);
}
let alarm = this.drones.find((d) => d.alarmLevel === 1);
const media = this.$refs.uavAudio; // ref "uavAudio"
const media = this.$refs.uavAudio;
if (alarm) {
this.iswarning = true;
this.$nextTick(() => {
@ -337,7 +370,11 @@ export default {
.play()
.then(() => {
console.log("播放成功,取消静音");
media.muted = false; //
if (this.isZoomedIn) {
media.muted = false; //
} else {
media.muted = true; //
}
})
.catch((error) => {
console.log("播放失败:", error);
@ -355,40 +392,78 @@ export default {
}
},
deep: true
},
isZoomedIn: {
handler(newVal) {
if (this.iswarning) {
const media = this.$refs.uavAudio;
if (newVal) {
media.muted = false; //
} else {
media.muted = true; //
}
}
},
deep: true
}
},
methods: {
startTracking() {
if (!navigator.geolocation) {
console.error("您的浏览器不支持地理位置功能");
return;
}
this.loading = true;
// 使 watchPosition
this.watchId = navigator.geolocation.watchPosition(
this.handleSuccess,
this.handleError,
{
enableHighAccuracy: true, //
timeout: 5000, // 5
maximumAge: 0 // 使
}
);
this.isTracking = true;
}, //
handleSuccess(position) {
this.loading = false;
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
this.lastUpdated = new Date().toLocaleString();
console.log(position, "this.watchId");
closeNavigation(drone) {
const naviUrl = `https://uri.amap.com/navigation?to=${
drone.app_lon + "," + drone.app_lat
},飞手位置&callnative=1`;
window.open(naviUrl, "_blank"); // '_blank'
},
//
handleError(error) {
this.loading = false;
this.error = this.getErrorMessage(error.code);
noNavigation(drone) {
this.$set(this.navigationStates, drone.BatchId, false);
},
async handleNavigation(drone) {
console.log("导航", drone);
this.$set(
this.navigationStates,
drone.BatchId,
!this.navigationStates[drone.BatchId]
);
if (!this.navigationStates[drone.BatchId]) {
return; //
}
// 使 amapuri App
const naviUrl = `https://uri.amap.com/navigation?to=${
drone.app_lon + "," + drone.app_lat
},飞手位置&callnative=1`;
console.log(naviUrl, "naviUrl");
try {
// qrCodes
const qrCodeDataUrl = await QRCode.toDataURL(naviUrl, {
width: 200,
margin: 2
});
this.$set(this.qrCodes, drone.BatchId, qrCodeDataUrl);
} catch (err) {
console.error("二维码生成失败:", err);
this.$message.error("二维码生成失败,请重试!");
}
},
handlewhiteList(drone) {
let params = {
model: " ",
sn: drone.serial_number,
allDay: true,
startTime: this.startTime,
endTime: this.endTime,
positionId: [],
company: " ",
mark: " "
};
whitListAdd(params)
.then((res) => {
if (res.code === 0) {
console.log(res, "添加成功");
}
})
.catch((err) => {
console.log(err, "添加失败");
});
},
enableAudio() {
this.iswarning = true;
@ -397,7 +472,11 @@ export default {
console.log("用户手动启用音频", media);
if (media !== undefined) {
clearInterval(time);
media.muted = false; //
if (this.isZoomedIn) {
media.muted = false; //
} else {
media.muted = true; //
}
media
.play()
.then(() => {
@ -422,6 +501,9 @@ export default {
this.$set(this.drones, index, { ...item });
}
} else {
this.droneStates = {};
this.navigationStates = {};
this.qrCodes = {}; //
clearInterval(this.droneTimers.get(item.BatchId));
this.droneTimers.delete(item.BatchId);
this.handleTimerExpiration(item);
@ -440,61 +522,149 @@ export default {
} else {
this.drones = this.drones.filter((d) => d.BatchId !== item.BatchId);
}
this.$delete(this.droneStates, item.BatchId); //
this.$delete(this.navigationStates, item.BatchId); //
this.$delete(this.qrCodes, item.BatchId);
//
let graphicLayer = window.marsMap.getLayerById("uavFiex");
// OpenLayers
const graphicLayer = window.olMap
.getLayers()
.getArray()
.find((layer) => layer.get("id") === "uavFiex");
const graphicLayerGJ = window.olMap
.getLayers()
.getArray()
.find((layer) => layer.get("id") === "guiji");
const graphicLayerFSGJX = window.olMap
.getLayers()
.getArray()
.find((layer) => layer.get("id") === "fsguiji");
// Feature
if (graphicLayer) {
let graphic = graphicLayer.getGraphicById(item.BatchId);
let startPoint = graphicLayer.getGraphicById(item.BatchId + "start");
const graphic = graphicLayer.getSource().getFeatureById(item.BatchId); //
const appGraphic = graphicLayer
.getSource()
.getFeatureById(item.BatchId + "_app"); //
if (graphic) {
graphic.destroy();
graphicLayer.removeGraphic(graphic);
graphicLayer.getSource().removeFeature(graphic);
}
if (startPoint) {
graphicLayer.removeGraphic(startPoint);
}
if (this.drones.length === 0) {
window.marsMap.removeLayer(graphicLayer);
if (appGraphic) {
graphicLayer.getSource().removeFeature(appGraphic);
}
}
let graphicDevice = window.marsMap.getLayerById("devLog");
if (graphicDevice) {
let deviceGraphic = graphicDevice.getGraphicById(item.DeviceId);
if (deviceGraphic !== undefined) {
deviceGraphic.setOptions({
style: {
scale: 1.5
}
});
//
if (graphicLayerGJ) {
const track = graphicLayerGJ
.getSource()
.getFeatureById(item.BatchId + "_track");
if (track) {
graphicLayerGJ.getSource().removeFeature(track);
}
}
//
if (graphicLayerFSGJX) {
const appTrack = graphicLayerFSGJX
.getSource()
.getFeatureById(item.BatchId + "_app_track");
if (appTrack) {
graphicLayerFSGJX.getSource().removeFeature(appTrack);
}
}
// drones
if (this.drones.length === 0) {
if (graphicLayer) {
window.olMap.removeLayer(graphicLayer);
}
if (graphicLayerGJ) {
window.olMap.removeLayer(graphicLayerGJ);
}
if (graphicLayerFSGJX) {
window.olMap.removeLayer(graphicLayerFSGJX);
}
}
},
handleContractClick() {
this.isContracted = !this.isContracted; //
},
handleDroneClick(value) {
value.detailsShow = !value.detailsShow;
if (value.drone_lon == 0 || value.drone_lat == 0) {
handleDroneClick(drone) {
console.log(drone, "isVisible");
this.$set(
this.droneStates,
drone.BatchId,
!this.droneStates[drone.BatchId]
);
const isVisible = this.droneStates[drone.BatchId];
// 线
let graphicLayerGJ = window.olMap
.getLayers()
.getArray()
.find((layer) => layer.get("id") === "guiji");
let graphic = graphicLayerGJ
.getSource()
.getFeatureById(drone.BatchId + "_track");
const trackStyle = new Style({
stroke: new Stroke({
color: this.getRandomColor(),
width: 0,
zIndex: 1
})
});
if (!isVisible) {
graphic.setStyle(trackStyle);
} else {
window.marsMap.setCameraView({
lat: value.drone_lat,
lng: value.drone_lon,
alt: value.height + 800,
pitch: -90
});
let graphicLayer = window.marsMap.getLayerById("uavFiex");
// let startPoint = graphicLayer.getGraphicById(value.BatchId + "start");
if (graphicLayer) {
graphicLayer.eachGraphic((car) => {
//
if (value.BatchId === car.id) {
// car.openPopup();
car.polyline.show = !car.polyline.show; // 线
}
});
}
graphic.setStyle(null);
}
// 线
let graphicLayerFSGJX = window.olMap
.getLayers()
.getArray()
.find((layer) => layer.get("id") === "fsguiji");
if (!graphicLayerFSGJX) {
graphicLayerFSGJX = new VectorLayer({
source: new VectorSource(),
zIndex: 10
});
graphicLayerFSGJX.set("id", "fsguiji");
map.addLayer(graphicLayerFSGJX);
}
let graphiclianjiexian = graphicLayerFSGJX
.getSource()
.getFeatureById(drone.BatchId + "_app_track");
const trackStyleljx = new Style({
stroke: new Stroke({
color: this.getRandomColor(),
width: 2,
lineDash: [4, 4],
zIndex: 1
})
});
if (!isVisible) {
graphiclianjiexian.setStyle(trackStyleljx);
} else {
graphiclianjiexian.setStyle(null);
}
if (drone.drone_lon !== 0 && drone.drone_lat !== 0) {
window.olMap.getView().animate({
center: fromLonLat([drone.drone_lon, drone.drone_lat]),
zoom: 13
});
}
},
//
getRandomColor() {
const letters = "0123456789ABCDEF";
let color = "#";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
}
};
@ -510,9 +680,9 @@ export default {
}
.audio-prompt {
position: fixed;
top: 0;
top: 0%;
left: 50%;
width: 15%;
width: 20%;
height: 10%;
background: rgba(0, 0, 0, 0.5);
display: flex;
@ -522,5 +692,6 @@ export default {
color: #fff;
border-radius: 5px;
transform: translateX(-50%);
pointer-events: auto;
}
</style>

View File

@ -1,28 +1,33 @@
<template>
<div class="header">
<div class="header-left">
<!-- <div class="header-logo"></div> -->
<div class="time_date">
{{ currentDate }} <span>{{ currentTime }}</span>
</div>
</div>
<div class="header-main">
<div class="textTile">
<!-- <img src="@/assets/img/title.svg" alt="" /> -->
</div>
<div class="textTile"></div>
</div>
<div class="header-menu">
<span>{{ leftText }}</span>
<span style="width: 20px"> | </span>
<span>{{ rightText }}</span>
</div>
<div v-if="showPermissionPrompt" class="permission-prompt">
<p>请允许地理位置权限以启用定位功能</p>
<p>您可以在浏览器地址栏设置中启用位置访问或点击下方按钮重试</p>
<button @click="retryTracking">重试定位</button>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import { HomeSyncLocation } from "@/api/home";
import _ from "lodash";
export default {
name: "header-top",
components: {},
props: {
homeData: {
type: Object,
@ -33,30 +38,139 @@ export default {
return {
currentTime: "",
currentDate: "",
currentDialog: "",
fromItem: {},
isAdmins: false,
leftText: "平台已连接",
rightText: "定位正常"
rightText: "定位正常",
latitude: null,
longitude: null,
lastUpdated: "",
watchId: null,
timer: null,
showPermissionPrompt: false
};
},
created() {},
watch: {
homeData: {
handler(newVal) {},
deep: true
}
computed: {
...mapGetters(["positionPoint"])
},
mounted() {
console.log("组件挂载,启动定位");
this.isAdmins = JSON.parse(localStorage.getItem("isAdmin"));
this.updateTime();
setInterval(this.updateTime, 1000); //
this.startTracking();
this.timer = setInterval(() => {
this.updateTime();
}, 1000);
},
watch: {
positionPoint: {
handler(newVal, oldVal) {
if (newVal) {
console.log("定位更新:", this.latitude, this.longitude);
const newLocation = [this.longitude, this.latitude]; //
const zoomLevel = 13; //
window.olMap.getView().animate({
center: newLocation,
zoom: zoomLevel
});
this.startTracking();
}
this.$store.commit("SET_POSITIONPOINT", false);
}
},
deep: true
},
methods: {
updateTime() {
const now = new Date();
this.currentTime = now.toLocaleTimeString(); //
this.currentDate = now.toLocaleDateString(); //
this.currentTime = now.toLocaleTimeString();
this.currentDate = now.toLocaleDateString();
},
startTracking() {
console.log("启动定位");
if (!navigator.geolocation) {
this.$message.error("您的浏览器不支持地理位置功能");
this.leftText = "不支持定位";
this.rightText = "定位异常";
return;
}
this.watchId = navigator.geolocation.watchPosition(
(position) => this.handleSuccess(position),
(error) => this.handleError(error),
{
enableHighAccuracy: false,
timeout: 15000,
maximumAge: 0
}
);
},
syncLocation: _.debounce(function (latitude, longitude) {
console.log("触发上报:", {
latitude,
longitude,
time: new Date().toLocaleString()
});
let params = {
lat: latitude,
lon: longitude,
userId: localStorage.getItem("userId")
};
HomeSyncLocation(params)
.then((res) => {
if (res.code === 0) {
this.leftText = "平台已连接";
this.rightText = "定位正常";
} else {
this.leftText = "平台连接失败";
this.rightText = "定位异常";
}
})
.catch((err) => {
console.error("上报失败:", err);
this.leftText = "平台连接失败";
this.rightText = "定位异常";
});
}, 1000),
handleSuccess(position) {
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
this.lastUpdated = new Date().toLocaleString();
this.showPermissionPrompt = false;
this.syncLocation(this.latitude, this.longitude);
},
handleError(error) {
let message = "";
switch (error.code) {
case error.PERMISSION_DENIED:
message = "请允许地理位置权限";
this.showPermissionPrompt = true;
this.$message.error("请在浏览器设置中启用地理位置权限");
break;
case error.POSITION_UNAVAILABLE:
message = "无法获取位置信息";
setTimeout(() => this.startTracking(), 5000);
break;
case error.TIMEOUT:
message = "获取位置超时";
setTimeout(() => this.startTracking(), 5000);
break;
default:
message = "未知错误";
}
this.leftText = message;
this.rightText = "定位异常";
console.error("定位错误:", error);
},
retryTracking() {
this.showPermissionPrompt = false;
this.startTracking();
}
},
beforeDestroy() {
if (this.watchId) {
navigator.geolocation.clearWatch(this.watchId);
}
if (this.timer) {
clearInterval(this.timer);
}
}
};
@ -76,4 +190,24 @@ export default {
margin-left: 10px;
cursor: pointer;
}
.permission-prompt {
position: fixed;
top: 20px;
right: 20px;
background: #fff;
padding: 15px;
border: 1px solid #ddd;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.permission-prompt p {
margin: 0 0 10px;
}
.permission-prompt button {
padding: 5px 10px;
background: #409eff;
color: #fff;
border: none;
cursor: pointer;
}
</style>

View File

@ -1,5 +1,20 @@
import route from "@/router/index";
import iconimg from "@/assets/img/dianweidingweiqizi.png";
import { geom, layer, source } from "ol";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import LineString from "ol/geom/LineString";
import Style from "ol/style/Style";
import Icon from "ol/style/Icon";
import Stroke from "ol/style/Stroke";
import Fill from "ol/style/Fill";
import Text from "ol/style/Text";
import CircleStyle from "ol/style/Circle";
import { fromLonLat, toLonLat } from "ol/proj";
export function allPositions(options, show, type, value) {
options.forEach((item, index) => {
let graphic = window.marsMap.getLayerById(item.id);
@ -344,130 +359,171 @@ function bindLayerPopup(graphicLayer, graphic) {
);
}
}
export function mapUavFiex(options) {
let map = window.marsMap; // 记录map
let graphicLayer = map.getLayerById("uavFiex");
export function mapUavFiex(options, map) {
// 获取或创建矢量图层(对应 Mars3D 的 GraphicLayer
let graphicLayer = map
.getLayers()
.getArray()
.find((layer) => layer.get("id") === "uavFiex");
if (!graphicLayer) {
// eslint-disable-next-line no-undef
graphicLayer = new mars3d.layer.GraphicLayer({ id: "uavFiex" });
graphicLayer = new VectorLayer({
source: new VectorSource(),
zIndex: 10
});
graphicLayer.set("id", "uavFiex");
map.addLayer(graphicLayer);
}
if (options.length === 0) {
graphicLayer.remove();
} else {
options.forEach((item) => {
if (item.drone_lon !== 0 || item.drone_lat !== 0) {
let graphic = graphicLayer.getGraphicById(item.BatchId);
// let startPoint = graphicLayer.getGraphicById(item.BatchId + "start"); // 起始点
//发现无人机
if (!graphic) {
// eslint-disable-next-line no-undef
graphic = new mars3d.graphic.Route({
id: item.BatchId,
name: "无人机",
maxCacheCount: -1,
polyline: {
width: 2,
opacity: 1,
randomColor: true,
show: true
},
// billboard: {
// image: require("@/assets/img/uav.svg"),
// scale: 0.5,
// horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM
// },
model: {
scale: window.mapConfig.uavSize || 8,
url: "/uav/scene.gltf",
// 航向
heading: 0,
// 俯仰
pitch: 0,
// 滚转
roll: 0.0,
color: window.mapConfig.uaColor,
show: true
},
attr: item
});
graphicLayer.addGraphic(graphic);
}
graphic.attr = item;
bindLayerPopup(graphicLayer, graphic);
}
if (item.app_lon !== 0 || item.app_lat !== 0) {
let app_graphic = graphicLayer.getGraphicById(item.BatchId + "_app");
// let startPoint = graphicLayer.getGraphicById(item.BatchId + "start"); // 起始点
//发现飞手
if (!app_graphic) {
// eslint-disable-next-line no-undef
app_graphic = new mars3d.graphic.Route({
id: item.BatchId + "_app",
name: "飞手",
maxCacheCount: -1,
label: {
text: "飞手位置",
font_size: 14,
font_family: "微软雅黑"
},
polyline: {
width: 2,
opacity: 1,
randomColor: true,
show: true
},
point: {
color: "#00ffff",
pixelSize: 8,
outlineColor: "#ffffff",
outlineWidth: 2
},
attr: item
});
graphicLayer.addGraphic(app_graphic);
}
}
// 更新发现无人机设备的大小
let graphicDevice = window.marsMap.getLayerById("devLog");
if (graphicDevice) {
let deviceGraphic = graphicDevice.getGraphicById(item.DeviceId);
if (deviceGraphic !== undefined) {
deviceGraphic.setOptions({
style: {
scale: 2
}
});
}
}
let graphicLayerGJ = map
.getLayers()
.getArray()
.find((layer) => layer.get("id") === "guiji");
if (!graphicLayerGJ) {
graphicLayerGJ = new VectorLayer({
source: new VectorSource(),
zIndex: 10
});
//绑定气泡弹窗
graphicLayer.eachGraphic((car) => {
// 取出对应无人机的轨迹列表
options.map((item) => {
if (item.BatchId === car.id) {
if (item.drone_lon !== 0 || item.drone_lat !== 0) {
// eslint-disable-next-line no-undef
const point = new mars3d.LngLatPoint(
item.drone_lon,
item.drone_lat,
item.height || 10
);
car.addDynamicPosition(point, 0);
}
} else if (item.BatchId + "_app" === car.id) {
if (item.app_lon !== 0 || item.app_lat !== 0) {
// eslint-disable-next-line no-undef
const point = new mars3d.LngLatPoint(item.app_lon, item.app_lat, 0);
car.addDynamicPosition(point, 0);
}
graphicLayerGJ.set("id", "guiji");
map.addLayer(graphicLayerGJ);
}
let graphicLayerFSGJX = map
.getLayers()
.getArray()
.find((layer) => layer.get("id") === "fsguiji");
if (!graphicLayerFSGJX) {
graphicLayerFSGJX = new VectorLayer({
source: new VectorSource(),
zIndex: 10
});
graphicLayerFSGJX.set("id", "fsguiji");
map.addLayer(graphicLayerFSGJX);
}
if (options.length === 0) {
graphicLayer.getSource().clear();
} else {
// 处理每个无人机和飞手
options.forEach((item) => {
// 处理无人机
if (item.drone_lon !== 0 || item.drone_lat !== 0) {
let graphic = graphicLayer.getSource().getFeatureById(item.BatchId);
if (!graphic) {
// 创建无人机 Feature
graphic = new Feature({
geometry: new Point(fromLonLat([item.drone_lon, item.drone_lat])),
name: "无人机"
});
graphic.setId(item.BatchId);
let imgUav = require("@/assets/img/icon_uav.png");
// 无人机样式(用图标替代 GLTF 模型)
graphic.setStyle(
new Style({
image: new Icon({
src: imgUav, // 使用导入的图标
scale: 1, // 合理缩放
color: window.mapConfig?.uaColor || "#ff0000"
})
})
);
// 创建轨迹 Feature
let track = new Feature({
geometry: new LineString([
fromLonLat([item.drone_lon, item.drone_lat])
]),
name: "无人机轨迹"
});
track.setId(item.BatchId + "_track");
graphicLayer.getSource().addFeature(graphic);
graphicLayerGJ.getSource().addFeature(track);
graphicLayerGJ.setStyle(null);
}
});
console.log(graphicLayer, graphicLayerGJ, graphic, "graphic");
// 更新无人机属性和位置
graphic.set("attr", item);
if (graphic.id_ === item.BatchId) {
const point = fromLonLat([item.drone_lon, item.drone_lat]);
graphic.getGeometry().setCoordinates(point);
// 更新轨迹
const track = graphicLayerGJ
.getSource()
.getFeatureById(item.BatchId + "_track");
track.getGeometry().appendCoordinate(point);
graphicLayerGJ.setStyle(null);
}
// 绑定弹窗
// bindPopup(graphicLayer, graphic, map);
}
// 处理飞手
if (item.app_lon !== 0 || item.app_lat !== 0) {
let appGraphic = graphicLayer
.getSource()
.getFeatureById(item.BatchId + "_app");
if (!appGraphic) {
// 创建飞手 Feature
appGraphic = new Feature({
geometry: new Point(fromLonLat([item.app_lon, item.app_lat])),
name: "飞手",
attr: item
});
appGraphic.setId(item.BatchId + "_app");
let imgUavfs = require("@/assets/img/icon_user.png");
// 飞手样式
appGraphic.setStyle(
new Style({
image: new Icon({
src: imgUavfs, // 飞手图标
scale: 1, // 合理缩放
color: window.mapConfig?.uaColor || "#ff0000"
}),
text: new Text({
text: "飞手位置",
font: "14px 微软雅黑",
offsetY: -15,
fill: new Fill({ color: "#000000" }),
stroke: new Stroke({ color: "#ffffff", width: 2 })
})
})
);
// 创建飞手轨迹 Feature
const appTrack = new Feature({
geometry: new LineString([
fromLonLat([item.app_lon, item.app_lat])
]),
name: "飞手轨迹"
});
appTrack.setId(item.BatchId + "_app_track");
graphicLayer.getSource().addFeature(appGraphic);
graphicLayerFSGJX.getSource().addFeature(appTrack);
}
// 更新飞手位置
const pointFS = fromLonLat([item.app_lon, item.app_lat]);
appGraphic.getGeometry().setCoordinates(pointFS);
// 更新飞手轨迹
const point = fromLonLat([item.drone_lon, item.drone_lat]);
const appTrack = graphicLayerFSGJX
.getSource()
.getFeatureById(item.BatchId + "_app_track");
// const appTrackGeom = appTrack.getGeometry();
// appTrackGeom.appendCoordinate(point);
appTrack.getGeometry().setCoordinates([
fromLonLat([item.app_lon, item.app_lat]), // 飞手位置
fromLonLat([item.drone_lon, item.drone_lat]) // 无人机位置
]);
graphicLayerFSGJX.setStyle(null);
// 绑定弹窗
// bindPopup(graphicLayer, appGraphic, map);
}
});
}
}

View File

@ -1,8 +1,18 @@
<template>
<div id="home">
<contentData id="contentData" :signaData="signaData" :homeData="homeData" />
<map-control id="mapControl" :signaData="signaData" :homeData="homeData" />
</div>
<fit-screen :width="1280" :height="800" mode="fit">
<div id="home">
<contentData
id="contentData"
:signaData="signaData"
:homeData="homeData"
/>
<map-control
id="mapControl"
:signaData="signaData"
:homeData="homeData"
/>
</div>
</fit-screen>
</template>
<script>
@ -31,9 +41,9 @@ export default {
},
mounted() {
this.initHomeData();
// this.timeInterval = setInterval(() => {
// this.initHomeData();
// }, 2000);
this.timeInterval = setInterval(() => {
this.initHomeData();
}, 2000);
},
methods: {
initHomeData() {
@ -62,7 +72,7 @@ export default {
? localhostPath
: process.env.VUE_APP_API_URL;
connection = new signalR.HubConnectionBuilder()
.withUrl(uploadUrl + "/websocket", {
.withUrl("ws://" + "114.66.57.139:5001" + "/websocket", {
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets
})

View File

@ -36,7 +36,7 @@
</template>
<script>
import { login } from "@/api/login.js";
import { login, loginPosition } from "@/api/login.js";
export default {
name: "my-Login", //
@ -85,10 +85,16 @@ export default {
localStorage.setItem("expires", res.data.expires); //
localStorage.setItem("userId", res.data.userid); // id
localStorage.setItem("isAdmin", res.data.isAdmin); //
// Vue 2 Pinia
this.$router.push("/"); // Vue 2 使 this.$router
// localStorage.setItem("PositionIds", res.data.PositionIds); //
this.$router.push("/");
let arrParams = res.data.positionIds;
loginPosition(arrParams).then((positionRes) => {
if (positionRes.code === 0) {
localStorage.setItem("PositionIds", positionRes.data); //
} else {
this.$message.error(positionRes.msg);
}
});
} else {
this.state.password = this.state.password;
this.$message.error(res.msg);

View File

@ -10,13 +10,13 @@
<img src="@/assets/img/query.png" alt="" />
</div>
<div class="configuration">
<div class="refresh">
<div class="refresh" @click="refreshClick">
<img src="@/assets/img/refresh.png" alt="" />
</div>
<div class="refresh">
<div class="refresh" @click="positionClick">
<img src="@/assets/img/icon_postions.png" alt="" />
</div>
<div class="refresh">
<div class="refresh" @click="modelClick">
<img src="@/assets/img/icon_model.png" alt="" />
</div>
</div>
@ -31,13 +31,30 @@ import TileLayer from "ol/layer/Tile";
import { fromLonLat } from "ol/proj";
import XYZ from "ol/source/XYZ";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import LineString from "ol/geom/LineString";
import Style from "ol/style/Style";
import Icon from "ol/style/Icon";
import Stroke from "ol/style/Stroke";
import Fill from "ol/style/Fill";
import Text from "ol/style/Text";
import CircleStyle from "ol/style/Circle";
import Static from "ol/source/ImageStatic.js";
import uaImg from "@/assets/img/icon_uav.png";
export default {
name: "HomeMap",
data() {
return {
map: null,
zoomLevel: null,
isZoomedIn: false
isZoomedIn: true,
isZoomedOut: false,
showPermissionPrompt: false
};
},
created() {
@ -56,26 +73,63 @@ export default {
}
},
methods: {
refreshClick() {
//
window.location.reload();
},
positionClick() {
console.log("位置点击");
this.$store.commit("SET_POSITIONPOINT", true);
},
modelClick() {
//
const newBaseMap = this.currentBaseMap === "gaode" ? "tianditu" : "gaode";
this.map.getLayers().forEach((layer) => {
const name = layer.get("name");
if (name === "gaode" || name === "tianditu") {
layer.setVisible(name === newBaseMap);
}
});
this.currentBaseMap = newBaseMap;
},
soundAndMenu() {
this.isZoomedIn = !this.isZoomedIn;
this.$store.commit("SET_ISZOOMEDIN", this.isZoomedIn);
// const media = document.getElementById("uavAudio");
// if (media) {
// media.muted = !this.isZoomedIn; // isZoomedIntrue
// if (!this.isZoomedIn) {
// //
// media.play().catch((error) => {
// console.log(":", error);
// });
// }
// }
},
initMap() {
// OpenLayers
this.map = new Map({
target: this.$refs.olMap,
layers: [
new TileLayer({
name: "gaode", //
visible: true,
source: new XYZ({
visible: true,
url: "http://webrd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=2&scale=1&style=8"
})
}),
new TileLayer({
name: "tianditu",
source: new XYZ({
url: "https://{a-d}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png"
}),
visible: false
})
],
view: new View({
projection: "EPSG:4326",
center: [116.4, 39.9], //
projection: "EPSG:3857",
center: fromLonLat([117.337103, 39.040924]), //
zoom: 10,
minZoom: 3,
maxZoom: 18,

View File

@ -18,7 +18,7 @@ module.exports = defineConfig({
productionSourceMap: false,
transpileDependencies: true,
devServer: {
host: "192.168.1.9",
host: "127.0.0.1",
port: 9997,
open: true,
proxy: {}