From f3e92fa13107b569e0aa4d3ffff013fd2983660b Mon Sep 17 00:00:00 2001
From: sean.zhou <sean.zhou@dji.com>
Date: Tue, 25 Apr 2023 20:28:45 +0800
Subject: [PATCH] initial v1.4.0
---
src/components/GMap.vue | 54
src/mqtt/config.ts | 12
src/components/task/TaskPanel.vue | 59
src/components/devices/device-hms/DeviceHmsDrawer.vue | 16
src/components/g-map/use-drone-control.ts | 40
package-lock.json | 453 +++++++
src/components/g-map/DockControlPanel.vue | 10
src/components/g-map/use-mqtt.ts | 132 ++
src/pages/page-web/projects/livestream.vue | 5
src/pages/page-web/projects/tsa.vue | 43
src/components/g-map/use-manual-control.ts | 162 +++
src/pages/page-web/projects/dock.vue | 2
src/types/device.ts | 103 +
src/mqtt/index.ts | 117 ++
src/pages/page-web/projects/Firmwares.vue | 6
src/types/drone-control.ts | 68 +
src/components/g-map/DroneControlInfoPanel.vue | 34
src/types/enums.ts | 9
src/api/wayline.ts | 23
src/types/drc.ts | 71 +
src/pages/page-web/projects/workspace.vue | 9
src/shims-mqtt.d.ts | 4
src/api/drone-control/drone.ts | 58 +
src/components/g-map/DroneControlPanel.vue | 756 ++++++++++++++
src/components/devices/device-upgrade/DeviceFirmwareUpgrade.vue | 2
src/components/g-map/use-device-setting.ts | 0
src/hooks/use-g-map-tsa.ts | 3
src/types/task.ts | 6
src/api/drone-control/payload.ts | 93 +
src/components/g-map/use-payload-control.ts | 120 ++
src/event-bus/index.ts | 2
src/components/g-map/use-dock-control.ts | 20
src/pages/page-web/projects/devices.vue | 17
src/store/index.ts | 22
src/types/live-stream.ts | 71 +
src/components/g-map/DeviceSettingBox.vue | 4
src/components/g-map/use-drone-control-ws-event.ts | 97 +
src/components/g-map/use-connect-mqtt.ts | 71 +
src/components/task/CreatePlan.vue | 3
yarn.lock | 189 +++
package.json | 5
src/components/g-map/use-drone-control-mqtt-event.ts | 61 +
src/types/device-cmd.ts | 21
src/components/g-map/DroneControlPopover.vue | 115 ++
src/api/drc.ts | 58 +
45 files changed, 3,048 insertions(+), 178 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f3082b8..47e9d0c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,7 +15,9 @@
"agora-rtc-sdk-ng": "^4.12.1",
"ant-design-vue": "^2.2.8",
"axios": "^0.21.1",
+ "eventemitter3": "^5.0.0",
"mitt": "^3.0.0",
+ "mqtt": "^4.3.7",
"query-string": "^7.0.1",
"reconnecting-websocket": "^4.4.0",
"vconsole": "^3.8.1",
@@ -1535,6 +1537,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+ },
"node_modules/big-integer": {
"version": "1.6.51",
"resolved": "https://registry.npmmirror.com/big-integer/download/big-integer-1.6.51.tgz",
@@ -1574,6 +1581,16 @@
"license": "MIT",
"engines": {
"node": ">=8"
+ }
+ },
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
}
},
"node_modules/bluebird": {
@@ -1634,6 +1651,20 @@
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
}
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"node_modules/buffer-indexof-polyfill": {
"version": "1.0.2",
@@ -2000,6 +2031,15 @@
"node": ">= 10"
}
},
+ "node_modules/commist": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/commist/-/commist-1.1.0.tgz",
+ "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==",
+ "dependencies": {
+ "leven": "^2.1.0",
+ "minimist": "^1.1.0"
+ }
+ },
"node_modules/component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz",
@@ -2018,6 +2058,20 @@
"resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"license": "MIT"
+ },
+ "node_modules/concat-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/concat-stream/-/concat-stream-2.0.0.tgz",
+ "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+ "engines": [
+ "node >= 6.0"
+ ],
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.0.2",
+ "typedarray": "^0.0.6"
+ }
},
"node_modules/constant-case": {
"version": "3.0.4",
@@ -2467,6 +2521,17 @@
"safe-buffer": "~5.1.0"
}
},
+ "node_modules/duplexify": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmmirror.com/duplexify/-/duplexify-4.1.2.tgz",
+ "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==",
+ "dependencies": {
+ "end-of-stream": "^1.4.1",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1",
+ "stream-shift": "^1.0.0"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.4.43",
"resolved": "https://registry.npmmirror.com/electron-to-chromium/download/electron-to-chromium-1.4.43.tgz",
@@ -2488,6 +2553,14 @@
"license": "MIT",
"engines": {
"node": ">= 4"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dependencies": {
+ "once": "^1.4.0"
}
},
"node_modules/enquirer": {
@@ -3421,6 +3494,11 @@
"node": ">= 0.6"
}
},
+ "node_modules/eventemitter3": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.0.tgz",
+ "integrity": "sha512-riuVbElZZNXLeLEoprfNYoDSwTBRR44X3mnhdI1YcnENpWTCsTTVZ2zFuqQcpoyqPQIUXdiPEU0ECAq0KQRaHg=="
+ },
"node_modules/expand-brackets": {
"version": "2.1.4",
"resolved": "https://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz",
@@ -3745,7 +3823,6 @@
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true,
"license": "ISC"
},
"node_modules/fsevents": {
@@ -3858,7 +3935,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmmirror.com/glob/download/glob-7.2.0.tgz",
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
- "dev": true,
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
@@ -4120,6 +4196,15 @@
"dev": true,
"license": "0BSD"
},
+ "node_modules/help-me": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmmirror.com/help-me/-/help-me-3.0.0.tgz",
+ "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==",
+ "dependencies": {
+ "glob": "^7.1.6",
+ "readable-stream": "^3.6.0"
+ }
+ },
"node_modules/htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmmirror.com/htmlparser2/download/htmlparser2-3.10.1.tgz?cache=0&sync_timestamp=1636640933377&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-3.10.1.tgz",
@@ -4134,6 +4219,11 @@
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
},
"node_modules/ignore": {
"version": "5.2.0",
@@ -4196,7 +4286,6 @@
"version": "1.0.6",
"resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true,
"license": "ISC",
"dependencies": {
"once": "^1.3.0",
@@ -4207,7 +4296,6 @@
"version": "2.0.4",
"resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz",
"integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=",
- "dev": true,
"license": "ISC"
},
"node_modules/internal-slot": {
@@ -4611,6 +4699,11 @@
"dev": true,
"license": "BSD-3-Clause"
},
+ "node_modules/js-sdsl": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.3.0.tgz",
+ "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ=="
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.nlark.com/js-tokens/download/js-tokens-4.0.0.tgz?cache=0&sync_timestamp=1619345098261&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fjs-tokens%2Fdownload%2Fjs-tokens-4.0.0.tgz",
@@ -4688,6 +4781,14 @@
"integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=",
"dev": true,
"license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/leven": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/leven/-/leven-2.1.0.tgz",
+ "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==",
"engines": {
"node": ">=0.10.0"
}
@@ -4801,7 +4902,6 @@
"version": "6.0.0",
"resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1599054167787&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz",
"integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=",
- "dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
@@ -4977,6 +5077,48 @@
"license": "MIT",
"engines": {
"node": "*"
+ }
+ },
+ "node_modules/mqtt": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmmirror.com/mqtt/-/mqtt-4.3.7.tgz",
+ "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==",
+ "dependencies": {
+ "commist": "^1.0.0",
+ "concat-stream": "^2.0.0",
+ "debug": "^4.1.1",
+ "duplexify": "^4.1.1",
+ "help-me": "^3.0.0",
+ "inherits": "^2.0.3",
+ "lru-cache": "^6.0.0",
+ "minimist": "^1.2.5",
+ "mqtt-packet": "^6.8.0",
+ "number-allocator": "^1.0.9",
+ "pump": "^3.0.0",
+ "readable-stream": "^3.6.0",
+ "reinterval": "^1.1.0",
+ "rfdc": "^1.3.0",
+ "split2": "^3.1.0",
+ "ws": "^7.5.5",
+ "xtend": "^4.0.2"
+ },
+ "bin": {
+ "mqtt": "bin/mqtt.js",
+ "mqtt_pub": "bin/pub.js",
+ "mqtt_sub": "bin/sub.js"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/mqtt-packet": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmmirror.com/mqtt-packet/-/mqtt-packet-6.10.0.tgz",
+ "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==",
+ "dependencies": {
+ "bl": "^4.0.2",
+ "debug": "^4.1.1",
+ "process-nextick-args": "^2.0.1"
}
},
"node_modules/ms": {
@@ -5157,6 +5299,15 @@
},
"funding": {
"url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
+ "node_modules/number-allocator": {
+ "version": "1.0.14",
+ "resolved": "https://registry.npmmirror.com/number-allocator/-/number-allocator-1.0.14.tgz",
+ "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
+ "dependencies": {
+ "debug": "^4.3.1",
+ "js-sdsl": "4.3.0"
}
},
"node_modules/object-assign": {
@@ -5374,7 +5525,6 @@
"version": "1.4.0",
"resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
"license": "ISC",
"dependencies": {
"wrappy": "1"
@@ -5525,7 +5675,6 @@
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -5695,7 +5844,6 @@
"version": "2.0.1",
"resolved": "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz",
"integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=",
- "dev": true,
"license": "MIT"
},
"node_modules/progress": {
@@ -5706,6 +5854,15 @@
"license": "MIT",
"engines": {
"node": ">=0.4.0"
+ }
+ },
+ "node_modules/pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
}
},
"node_modules/punycode": {
@@ -5760,7 +5917,6 @@
"version": "3.6.0",
"resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz",
"integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=",
- "dev": true,
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
@@ -5873,6 +6029,11 @@
"url": "https://github.com/sponsors/mysticatea"
}
},
+ "node_modules/reinterval": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/reinterval/-/reinterval-1.1.0.tgz",
+ "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ=="
+ },
"node_modules/repeat-element": {
"version": "1.1.4",
"resolved": "https://registry.nlark.com/repeat-element/download/repeat-element-1.1.4.tgz",
@@ -5962,6 +6123,11 @@
"iojs": ">=1.0.0",
"node": ">=0.10.0"
}
+ },
+ "node_modules/rfdc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.3.0.tgz",
+ "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
},
"node_modules/rimraf": {
"version": "3.0.2",
@@ -6541,6 +6707,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/split2": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmmirror.com/split2/-/split2-3.2.2.tgz",
+ "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
+ "dependencies": {
+ "readable-stream": "^3.0.0"
+ }
+ },
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz",
@@ -6649,6 +6823,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/stream-shift": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/stream-shift/-/stream-shift-1.0.1.tgz",
+ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
+ },
"node_modules/strict-uri-encode": {
"version": "2.0.0",
"resolved": "https://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-2.0.0.tgz",
@@ -6662,7 +6841,6 @@
"version": "1.3.0",
"resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.3.0.tgz",
"integrity": "sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4=",
- "dev": true,
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.2.0"
@@ -6672,7 +6850,6 @@
"version": "5.2.1",
"resolved": "https://registry.nlark.com/safe-buffer/download/safe-buffer-5.2.1.tgz",
"integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=",
- "dev": true,
"funding": [
{
"type": "github",
@@ -7343,6 +7520,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
+ },
"node_modules/typescript": {
"version": "4.5.4",
"resolved": "https://registry.npmmirror.com/typescript/download/typescript-4.5.4.tgz",
@@ -7577,7 +7759,6 @@
"version": "1.0.2",
"resolved": "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true,
"license": "MIT"
},
"node_modules/v8-compile-cache": {
@@ -7970,14 +8151,40 @@
"version": "1.0.2",
"resolved": "https://registry.nlark.com/wrappy/download/wrappy-1.0.2.tgz?cache=0&sync_timestamp=1619133505879&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwrappy%2Fdownload%2Fwrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true,
"license": "ISC"
+ },
+ "node_modules/ws": {
+ "version": "7.5.9",
+ "resolved": "https://registry.npmmirror.com/ws/-/ws-7.5.9.tgz",
+ "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "engines": {
+ "node": ">=8.3.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "engines": {
+ "node": ">=0.4"
+ }
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz",
"integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=",
- "dev": true,
"license": "ISC"
}
},
@@ -9002,6 +9209,11 @@
}
}
},
+ "base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+ },
"big-integer": {
"version": "1.6.51",
"resolved": "https://registry.npmmirror.com/big-integer/download/big-integer-1.6.51.tgz",
@@ -9029,6 +9241,16 @@
"resolved": "https://registry.nlark.com/binary-extensions/download/binary-extensions-2.2.0.tgz",
"integrity": "sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0=",
"devOptional": true
+ },
+ "bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "requires": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
},
"bluebird": {
"version": "3.7.2",
@@ -9070,6 +9292,20 @@
"node-releases": "^2.0.1",
"picocolors": "^1.0.0"
}
+ },
+ "buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "requires": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"buffer-indexof-polyfill": {
"version": "1.0.2",
@@ -9354,6 +9590,15 @@
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true
},
+ "commist": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/commist/-/commist-1.1.0.tgz",
+ "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==",
+ "requires": {
+ "leven": "^2.1.0",
+ "minimist": "^1.1.0"
+ }
+ },
"component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz",
@@ -9369,6 +9614,17 @@
"version": "0.0.1",
"resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "concat-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/concat-stream/-/concat-stream-2.0.0.tgz",
+ "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.0.2",
+ "typedarray": "^0.0.6"
+ }
},
"constant-case": {
"version": "3.0.4",
@@ -9700,6 +9956,17 @@
}
}
},
+ "duplexify": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmmirror.com/duplexify/-/duplexify-4.1.2.tgz",
+ "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==",
+ "requires": {
+ "end-of-stream": "^1.4.1",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1",
+ "stream-shift": "^1.0.0"
+ }
+ },
"electron-to-chromium": {
"version": "1.4.43",
"resolved": "https://registry.npmmirror.com/electron-to-chromium/download/electron-to-chromium-1.4.43.tgz",
@@ -9716,6 +9983,14 @@
"resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz",
"integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang=",
"dev": true
+ },
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "requires": {
+ "once": "^1.4.0"
+ }
},
"enquirer": {
"version": "2.3.6",
@@ -10310,6 +10585,11 @@
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
"dev": true
},
+ "eventemitter3": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.0.tgz",
+ "integrity": "sha512-riuVbElZZNXLeLEoprfNYoDSwTBRR44X3mnhdI1YcnENpWTCsTTVZ2zFuqQcpoyqPQIUXdiPEU0ECAq0KQRaHg=="
+ },
"expand-brackets": {
"version": "2.1.4",
"resolved": "https://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz",
@@ -10545,8 +10825,7 @@
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fsevents": {
"version": "2.3.2",
@@ -10624,7 +10903,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmmirror.com/glob/download/glob-7.2.0.tgz",
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
- "dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -10806,6 +11084,15 @@
}
}
},
+ "help-me": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmmirror.com/help-me/-/help-me-3.0.0.tgz",
+ "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==",
+ "requires": {
+ "glob": "^7.1.6",
+ "readable-stream": "^3.6.0"
+ }
+ },
"htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmmirror.com/htmlparser2/download/htmlparser2-3.10.1.tgz?cache=0&sync_timestamp=1636640933377&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-3.10.1.tgz",
@@ -10819,6 +11106,11 @@
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
+ },
+ "ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
},
"ignore": {
"version": "5.2.0",
@@ -10858,7 +11150,6 @@
"version": "1.0.6",
"resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
@@ -10867,8 +11158,7 @@
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz",
- "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=",
- "dev": true
+ "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w="
},
"internal-slot": {
"version": "1.0.3",
@@ -11132,6 +11422,11 @@
"integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
"dev": true
},
+ "js-sdsl": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.3.0.tgz",
+ "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ=="
+ },
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.nlark.com/js-tokens/download/js-tokens-4.0.0.tgz?cache=0&sync_timestamp=1619345098261&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fjs-tokens%2Fdownload%2Fjs-tokens-4.0.0.tgz",
@@ -11187,6 +11482,11 @@
"resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz",
"integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=",
"dev": true
+ },
+ "leven": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/leven/-/leven-2.1.0.tgz",
+ "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA=="
},
"levn": {
"version": "0.4.1",
@@ -11276,7 +11576,6 @@
"version": "6.0.0",
"resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1599054167787&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz",
"integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=",
- "dev": true,
"requires": {
"yallist": "^4.0.0"
}
@@ -11400,6 +11699,40 @@
"version": "2.29.1",
"resolved": "https://registry.npmmirror.com/moment/download/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+ },
+ "mqtt": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmmirror.com/mqtt/-/mqtt-4.3.7.tgz",
+ "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==",
+ "requires": {
+ "commist": "^1.0.0",
+ "concat-stream": "^2.0.0",
+ "debug": "^4.1.1",
+ "duplexify": "^4.1.1",
+ "help-me": "^3.0.0",
+ "inherits": "^2.0.3",
+ "lru-cache": "^6.0.0",
+ "minimist": "^1.2.5",
+ "mqtt-packet": "^6.8.0",
+ "number-allocator": "^1.0.9",
+ "pump": "^3.0.0",
+ "readable-stream": "^3.6.0",
+ "reinterval": "^1.1.0",
+ "rfdc": "^1.3.0",
+ "split2": "^3.1.0",
+ "ws": "^7.5.5",
+ "xtend": "^4.0.2"
+ }
+ },
+ "mqtt-packet": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmmirror.com/mqtt-packet/-/mqtt-packet-6.10.0.tgz",
+ "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==",
+ "requires": {
+ "bl": "^4.0.2",
+ "debug": "^4.1.1",
+ "process-nextick-args": "^2.0.1"
+ }
},
"ms": {
"version": "2.1.2",
@@ -11534,6 +11867,15 @@
"dev": true,
"requires": {
"boolbase": "^1.0.0"
+ }
+ },
+ "number-allocator": {
+ "version": "1.0.14",
+ "resolved": "https://registry.npmmirror.com/number-allocator/-/number-allocator-1.0.14.tgz",
+ "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
+ "requires": {
+ "debug": "^4.3.1",
+ "js-sdsl": "4.3.0"
}
},
"object-assign": {
@@ -11688,7 +12030,6 @@
"version": "1.4.0",
"resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
"requires": {
"wrappy": "1"
}
@@ -11809,8 +12150,7 @@
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "dev": true
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-key": {
"version": "3.1.1",
@@ -11926,14 +12266,22 @@
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz",
- "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=",
- "dev": true
+ "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I="
},
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/progress/download/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
+ },
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
},
"punycode": {
"version": "2.1.1",
@@ -11961,7 +12309,6 @@
"version": "3.6.0",
"resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz",
"integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=",
- "dev": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -12039,6 +12386,11 @@
"integrity": "sha1-BCWido2PI7rXDKS5BGH6LxIT4bI=",
"dev": true
},
+ "reinterval": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/reinterval/-/reinterval-1.1.0.tgz",
+ "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ=="
+ },
"repeat-element": {
"version": "1.1.4",
"resolved": "https://registry.nlark.com/repeat-element/download/repeat-element-1.1.4.tgz",
@@ -12094,6 +12446,11 @@
"version": "1.0.4",
"resolved": "https://registry.npm.taobao.org/reusify/download/reusify-1.0.4.tgz",
"integrity": "sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY="
+ },
+ "rfdc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.3.0.tgz",
+ "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
},
"rimraf": {
"version": "3.0.2",
@@ -12516,6 +12873,14 @@
}
}
},
+ "split2": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmmirror.com/split2/-/split2-3.2.2.tgz",
+ "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
+ "requires": {
+ "readable-stream": "^3.0.0"
+ }
+ },
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz",
@@ -12600,6 +12965,11 @@
}
}
},
+ "stream-shift": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/stream-shift/-/stream-shift-1.0.1.tgz",
+ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
+ },
"strict-uri-encode": {
"version": "2.0.0",
"resolved": "https://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-2.0.0.tgz",
@@ -12609,7 +12979,6 @@
"version": "1.3.0",
"resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.3.0.tgz",
"integrity": "sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4=",
- "dev": true,
"requires": {
"safe-buffer": "~5.2.0"
},
@@ -12617,8 +12986,7 @@
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.nlark.com/safe-buffer/download/safe-buffer-5.2.1.tgz",
- "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=",
- "dev": true
+ "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY="
}
}
},
@@ -13093,6 +13461,11 @@
"integrity": "sha1-G/IH9LKPkVg2ZstfvTJ4hzAc1fQ=",
"dev": true
},
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
+ },
"typescript": {
"version": "4.5.4",
"resolved": "https://registry.npmmirror.com/typescript/download/typescript-4.5.4.tgz",
@@ -13282,8 +13655,7 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"v8-compile-cache": {
"version": "2.3.0",
@@ -13544,14 +13916,23 @@
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.nlark.com/wrappy/download/wrappy-1.0.2.tgz?cache=0&sync_timestamp=1619133505879&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwrappy%2Fdownload%2Fwrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "ws": {
+ "version": "7.5.9",
+ "resolved": "https://registry.npmmirror.com/ws/-/ws-7.5.9.tgz",
+ "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "requires": {}
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz",
- "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=",
- "dev": true
+ "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI="
}
}
}
diff --git a/package.json b/package.json
index 2b5640f..34c4aa0 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,9 @@
"agora-rtc-sdk-ng": "^4.12.1",
"ant-design-vue": "^2.2.8",
"axios": "^0.21.1",
+ "eventemitter3": "^5.0.0",
"mitt": "^3.0.0",
+ "mqtt": "^4.3.7",
"query-string": "^7.0.1",
"reconnecting-websocket": "^4.4.0",
"vconsole": "^3.8.1",
@@ -97,9 +99,12 @@
"ant-design-vue/es/tree/style/css",
"ant-design-vue/es/upload/style/css",
"axios",
+ "eventemitter3",
"lodash",
"mitt",
"moment",
+ "mqtt",
+ "mqtt/dist/mqtt.min",
"reconnecting-websocket",
"vconsole",
"vue",
diff --git a/src/api/drc.ts b/src/api/drc.ts
new file mode 100644
index 0000000..ea415a9
--- /dev/null
+++ b/src/api/drc.ts
@@ -0,0 +1,58 @@
+import request, { IWorkspaceResponse } from '/@/api/http/request'
+import { ELocalStorageKey } from '/@/types'
+
+// DRC 链路
+const DRC_API_PREFIX = '/control/api/v1'
+const workspaceId: string = localStorage.getItem(ELocalStorageKey.WorkspaceId) || ''
+
+export interface PostDrcBody {
+ client_id?: string // token过期时,用于续期则必填
+ expire_sec?: number // 过期时间,单位秒,默认3600
+}
+
+export interface DrcParams {
+ address: string
+ username: string
+ password: string
+ client_id: string
+ expire_time: number // 过期时间
+ enable_tls: boolean // 是否开启tls
+}
+
+// 获取 mqtt 连接认证
+export async function postDrc (body: PostDrcBody): Promise<IWorkspaceResponse<DrcParams>> {
+ const resp = await request.post(`${DRC_API_PREFIX}/workspaces/${workspaceId}/drc/connect`, body)
+ return resp.data
+}
+
+export interface DrcEnterBody {
+ client_id: string
+ dock_sn: string
+ expire_sec?: number // 过期时间,单位秒,默认3600
+ device_info?: {
+ osd_frequency?: number
+ hsi_frequency?: number
+ }
+}
+
+export interface DrcEnterResp {
+ sub: string[] // 需要订阅接收的topic
+ pub: string[] // 推送的topic地址
+}
+
+// 进入飞行控制 (建立drc连接&获取云控控制权)
+export async function postDrcEnter (body: DrcEnterBody): Promise<IWorkspaceResponse<DrcEnterResp>> {
+ const resp = await request.post(`${DRC_API_PREFIX}/workspaces/${workspaceId}/drc/enter`, body)
+ return resp.data
+}
+
+export interface DrcExitBody {
+ client_id: string
+ dock_sn: string
+}
+
+// 退出飞行控制 (退出drc连接&退出云控控制权)
+export async function postDrcExit (body: DrcExitBody): Promise<IWorkspaceResponse<null>> {
+ const resp = await request.post(`${DRC_API_PREFIX}/workspaces/${workspaceId}/drc/exit`, body)
+ return resp.data
+}
diff --git a/src/api/drone-control/drone.ts b/src/api/drone-control/drone.ts
new file mode 100644
index 0000000..7539a4d
--- /dev/null
+++ b/src/api/drone-control/drone.ts
@@ -0,0 +1,58 @@
+import request, { IWorkspaceResponse } from '/@/api/http/request'
+// import { ELocalStorageKey } from '/@/types'
+
+const API_PREFIX = '/control/api/v1'
+// const workspaceId: string = localStorage.getItem(ELocalStorageKey.WorkspaceId) || '
+
+// 获取飞行控制权
+export async function postFlightAuth (sn: string): Promise<IWorkspaceResponse<null>> {
+ const resp = await request.post(`${API_PREFIX}/devices/${sn}/authority/flight`)
+ return resp.data
+}
+export enum WaylineLostControlActionInCommandFlight {
+ CONTINUE = 0,
+ EXEC_LOST_ACTION = 1
+}
+export enum LostControlActionInCommandFLight {
+ HOVER = 0, // 悬停
+ Land = 1, // 着陆
+ RETURN_HOME = 2, // 返航
+}
+export interface PointBody {
+ latitude: number;
+ longitude: number;
+ height: number;
+}
+export interface PostFlyToPointBody {
+ max_speed: number,
+ points: PointBody[]
+}
+
+// 飞向目标点
+export async function postFlyToPoint (sn: string, body: PostFlyToPointBody): Promise<IWorkspaceResponse<null>> {
+ const resp = await request.post(`${API_PREFIX}/devices/${sn}/jobs/fly-to-point`, body)
+ return resp.data
+}
+
+// 停止飞向目标点
+export async function deleteFlyToPoint (sn: string): Promise<IWorkspaceResponse<null>> {
+ const resp = await request.delete(`${API_PREFIX}/devices/${sn}/jobs/fly-to-point`)
+ return resp.data
+}
+
+export interface PostTakeoffToPointBody{
+ target_height: number;
+ target_latitude: number;
+ target_longitude: number;
+ security_takeoff_height: number; // 安全起飞高
+ max_speed: number; // flyto过程中能达到的最大速度, 单位m/s 跟飞机档位有关
+ rc_lost_action: LostControlActionInCommandFLight; // 失控行为
+ rth_altitude: number; // 返航高度
+ exit_wayline_when_rc_lost: WaylineLostControlActionInCommandFlight
+}
+
+// 一键起飞
+export async function postTakeoffToPoint (sn: string, body: PostTakeoffToPointBody): Promise<IWorkspaceResponse<null>> {
+ const resp = await request.post(`${API_PREFIX}/devices/${sn}/jobs/takeoff-to-point`, body)
+ return resp.data
+}
diff --git a/src/api/drone-control/payload.ts b/src/api/drone-control/payload.ts
new file mode 100644
index 0000000..03b89c5
--- /dev/null
+++ b/src/api/drone-control/payload.ts
@@ -0,0 +1,93 @@
+import request, { IWorkspaceResponse } from '/@/api/http/request'
+import { CameraType, CameraMode } from '/@/types/live-stream'
+import { GimbalResetMode } from '/@/types/drone-control'
+// import { ELocalStorageKey } from '/@/types'
+
+const API_PREFIX = '/control/api/v1'
+// const workspaceId: string = localStorage.getItem(ELocalStorageKey.WorkspaceId) || '
+
+export interface PostPayloadAuthBody {
+ payload_index: string
+}
+
+// 获取负载控制权
+export async function postPayloadAuth (sn: string, body: PostPayloadAuthBody): Promise<IWorkspaceResponse<null>> {
+ const resp = await request.post(`${API_PREFIX}/devices/${sn}/authority/payload`, body)
+ return resp.data
+}
+
+// TODO: 画面拖动控制
+export enum PayloadCommandsEnum {
+ CameraModeSwitch = 'camera_mode_switch',
+ CameraPhotoTake = 'camera_photo_take',
+ CameraRecordingStart = 'camera_recording_start',
+ CameraRecordingStop = 'camera_recording_stop',
+ CameraFocalLengthSet = 'camera_focal_length_set',
+ GimbalReset = 'gimbal_reset',
+ CameraAim = 'camera_aim'
+}
+
+export interface PostCameraModeBody {
+ payload_index: string
+ camera_mode: CameraMode
+}
+
+export interface PostCameraPhotoBody {
+ payload_index: string
+}
+
+export interface PostCameraRecordingBody {
+ payload_index: string
+}
+
+export interface DeleteCameraRecordingParams {
+ payload_index: string
+}
+
+export interface PostCameraFocalLengthBody {
+ payload_index: string,
+ camera_type: CameraType,
+ zoom_factor: number
+}
+
+export interface PostGimbalResetBody{
+ payload_index: string,
+ reset_mode: GimbalResetMode,
+}
+
+export interface PostCameraAimBody{
+ payload_index: string,
+ camera_type: CameraType,
+ locked: boolean,
+ x: number,
+ y: number,
+}
+
+export type PostPayloadCommandsBody = {
+ cmd: PayloadCommandsEnum.CameraModeSwitch,
+ data: PostCameraModeBody
+} | {
+ cmd: PayloadCommandsEnum.CameraPhotoTake,
+ data: PostCameraPhotoBody
+} | {
+ cmd: PayloadCommandsEnum.CameraRecordingStart,
+ data: PostCameraRecordingBody
+} | {
+ cmd: PayloadCommandsEnum.CameraRecordingStop,
+ data: DeleteCameraRecordingParams
+} | {
+ cmd: PayloadCommandsEnum.CameraFocalLengthSet,
+ data: PostCameraFocalLengthBody
+} | {
+ cmd: PayloadCommandsEnum.GimbalReset,
+ data: PostGimbalResetBody
+} | {
+ cmd: PayloadCommandsEnum.CameraAim,
+ data: PostCameraAimBody
+}
+
+// 发送负载名称
+export async function postPayloadCommands (sn: string, body: PostPayloadCommandsBody): Promise<IWorkspaceResponse<null>> {
+ const resp = await request.post(`${API_PREFIX}/devices/${sn}/payload/commands`, body)
+ return resp.data
+}
diff --git a/src/api/wayline.ts b/src/api/wayline.ts
index b7d4987..a917804 100644
--- a/src/api/wayline.ts
+++ b/src/api/wayline.ts
@@ -42,7 +42,8 @@
dock_sn: string,
task_type: TaskType, // 任务类型
wayline_type: WaylineType, // 航线类型
- execute_time?: number // 执行时间(毫秒)
+ task_days?: number[] // 执行任务的日期(秒)
+ task_periods?: number[][] // 执行任务的时间点(秒)
rth_altitude: number // 相对机场返航高度 20 - 500
out_of_control_action: OutOfControlAction // 失控动作
}
@@ -90,7 +91,7 @@
job_id: string
}
-// 取消机场任务
+// 删除机场任务
export async function deleteTask (workspaceId: string, params: DeleteTaskParams): Promise<IWorkspaceResponse<{}>> {
const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/jobs`
const result = await request.delete(url, {
@@ -99,6 +100,24 @@
return result.data
}
+export enum UpdateTaskStatus {
+ Suspend = 0, // 暂停
+ Resume = 1, // 恢复
+}
+export interface UpdateTaskStatusBody {
+ job_id: string
+ status: UpdateTaskStatus
+}
+
+// 更新机场任务状态
+export async function updateTaskStatus (workspaceId: string, body: UpdateTaskStatusBody): Promise<IWorkspaceResponse<{}>> {
+ const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/jobs/${body.job_id}`
+ const result = await request.put(url, {
+ status: body.status
+ })
+ return result.data
+}
+
// Upload Wayline file
export const importKmzFile = async function (workspaceId: string, file: {}): Promise<IWorkspaceResponse<any>> {
const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/waylines/file/upload`
diff --git a/src/components/GMap.vue b/src/components/GMap.vue
index cb8653e..1a99fcc 100644
--- a/src/components/GMap.vue
+++ b/src/components/GMap.vue
@@ -1,8 +1,10 @@
<template>
<div class="g-map-wrapper">
+ <!-- 地图区域 -->
<div id="g-container" :style="{ width: '100%', height: '100%' }" />
+ <!-- 绘制面板 -->
<div
- class="g-action-panle"
+ class="g-action-panel"
:style="{ right: drawVisible ? '316px' : '16px' }"
>
<div :class="state.currentType === 'pin' ? 'g-action-item selection' : 'g-action-item'" @click="draw('pin', true)">
@@ -18,6 +20,7 @@
<a style="color: red;"><CloseOutlined /></a>
</div>
</div>
+ <!-- 飞机OSD -->
<div v-if="osdVisible.visible && !osdVisible.is_dock" class="osd-panel fz12">
<div class="pl5 pr5 flex-align-center flex-row flex-justify-between" style="border-bottom: 1px solid #515151; height: 18%;">
<span>{{ osdVisible.callsign }}</span>
@@ -270,12 +273,13 @@
</a-row>
<a-row class="p5">
<a-col span="24">
- <a-button type="primary" :disabled="controlPanelVisible" size="small" @click="setControlPanelVisible(true)">
- 设备操作
+ <a-button type="primary" :disabled="dockControlPanelVisible" size="small" @click="setDockControlPanelVisible(true)">
+ Actions
</a-button>
</a-col>
</a-row>
- <DockControlPanel v-if="controlPanelVisible" :sn="osdVisible.gateway_sn" :deviceInfo="deviceInfo" @close-control-panel="dockDebugOnOff">
+ <!-- 机场控制面板 -->
+ <DockControlPanel v-if="dockControlPanelVisible" :sn="osdVisible.gateway_sn" :deviceInfo="deviceInfo" @close-control-panel="onCloseControlPanel">
</DockControlPanel>
</div>
</div>
@@ -406,7 +410,8 @@
{{ 10 > (deviceInfo.device.battery.remain_flight_time % 60) ? '0' : ''}}{{deviceInfo.device.battery.remain_flight_time % 60 }}
</div>
</div>
-
+ <!-- 飞行指令 -->
+ <DroneControlPanel :sn="osdVisible.gateway_sn" :deviceInfo="deviceInfo" :payloads="osdVisible.payloads"></DroneControlPanel>
</div>
</div>
</template>
@@ -444,7 +449,9 @@
} from '@ant-design/icons-vue'
import { EDeviceTypeName } from '../types'
import DockControlPanel from './g-map/DockControlPanel.vue'
-import { useDockControl } from './g-map/useDockControl'
+import { useDockControl } from './g-map/use-dock-control'
+import DroneControlPanel from './g-map/DroneControlPanel.vue'
+import { useConnectMqtt } from './g-map/use-connect-mqtt'
export default defineComponent({
components: {
@@ -466,6 +473,7 @@
ArrowUpOutlined,
ArrowDownOutlined,
DockControlPanel,
+ DroneControlPanel,
CarryOutOutlined,
RocketOutlined
},
@@ -567,7 +575,7 @@
deviceTsaUpdateHook.initMarker(EDeviceTypeName.Dock, [EDeviceTypeName.Dock], data.currentSn, data.dockInfo[data.currentSn].basic_osd?.longitude, data.dockInfo[data.currentSn].basic_osd?.latitude)
if (osdVisible.value.visible && osdVisible.value.is_dock && osdVisible.value.gateway_sn !== '') {
deviceInfo.dock = data.dockInfo[osdVisible.value.gateway_sn]
- deviceInfo.device = data.deviceInfo[deviceInfo.dock.basic_osd?.sub_device?.device_sn ?? osdVisible.value.sn]
+ deviceInfo.device = data.deviceInfo[deviceInfo.dock.basic_osd.sub_device?.device_sn ?? osdVisible.value.sn]
}
}
}, {
@@ -634,21 +642,21 @@
mouseMode.value = bool
}
- // dock 控制指令
+ // dock 控制面板
const {
- controlPanelVisible,
- setControlPanelVisible,
- sendDockControlCmd,
- dockDebugOnOff,
+ dockControlPanelVisible,
+ setDockControlPanelVisible,
+ onCloseControlPanel,
} = useDockControl()
+
+ // 连接或断开drc
+ useConnectMqtt()
onMounted(() => {
const app = getApp()
useGMapManageHook.globalPropertiesConfig(app)
- setInterval(() => {
- console.info(deviceInfo.dock)
- }, 1000)
})
+
function getDrawCallback ({ obj }) {
switch (state.currentType) {
case MapDoodleEnum.PIN:
@@ -816,9 +824,9 @@
EModeCode,
str,
EDockModeCode,
- controlPanelVisible,
- dockDebugOnOff,
- setControlPanelVisible,
+ dockControlPanelVisible,
+ setDockControlPanelVisible,
+ onCloseControlPanel,
NetworkStateTypeEnum,
NetworkStateQualityEnum,
RainfallEnum,
@@ -834,7 +842,7 @@
height: 100%;
width: 100%;
- .g-action-panle {
+ .g-action-panel {
position: absolute;
top: 16px;
right: 16px;
@@ -870,12 +878,12 @@
left: 10px;
top: 10px;
width: 480px;
- background: black;
- color: white;
+ background: #000;
+ color: #fff;
border-radius: 2px;
- opacity: 0.7;
+ opacity: 0.8;
}
-.osd > div {
+.osd > div:not(.dock-control-panel) {
margin-top: 5px;
padding-left: 5px;
}
diff --git a/src/components/devices/device-hms/DeviceHmsDrawer.vue b/src/components/devices/device-hms/DeviceHmsDrawer.vue
index 7ff68fc..808b7cb 100644
--- a/src/components/devices/device-hms/DeviceHmsDrawer.vue
+++ b/src/components/devices/device-hms/DeviceHmsDrawer.vue
@@ -67,7 +67,12 @@
</template>
<template v-for="col in ['code', 'message']" #[col]="{ text }" :key="col">
<a-tooltip :title="text">
- <span>{{ text }}</span>
+ <div >{{ text }}</div>
+ </a-tooltip>
+ </template>
+ <template #domain="{text}">
+ <a-tooltip :title="EDeviceTypeName[text]">
+ <div >{{ EDeviceTypeName[text] }}</div>
</a-tooltip>
</template>
</a-table>
@@ -77,7 +82,7 @@
<!-- 暂时只抽取该组件 -->
<script lang="ts" setup>
-import { watchEffect, reactive, ref, defineProps, defineEmits } from 'vue'
+import { watchEffect, reactive, ref, defineProps, defineEmits, watch } from 'vue'
import { getDeviceHms, HmsQueryBody } from '/@/api/manage'
import moment, { Moment } from 'moment'
import { ColumnProps, TableState } from 'ant-design-vue/lib/table/interface'
@@ -95,7 +100,7 @@
// 健康状态
const sVisible = ref(false)
-watchEffect(() => {
+watch(props, () => {
sVisible.value = props.visible
// 显示弹框时,获取设备hms信息
if (props.visible) {
@@ -117,9 +122,10 @@
const hmsColumns: ColumnProps[] = [
{ title: 'Alarm Begin | End Time', dataIndex: 'create_time', width: '25%', className: 'titleStyle', slots: { customRender: 'time' } },
{ title: 'Level', dataIndex: 'level', width: '120px', className: 'titleStyle', slots: { customRender: 'level' } },
- { title: 'Device', dataIndex: 'domain', width: '12%', className: 'titleStyle' },
- { title: 'Error Code', dataIndex: 'key', width: '20%', className: 'titleStyle', slots: { customRender: 'code' } },
+ { title: 'Device', dataIndex: 'domain', width: '12%', className: 'titleStyle', slots: { customRender: 'domain' } },
+ { title: 'Error Code', dataIndex: 'key', width: '20%', className: 'titleStyle', ellipsis: true, slots: { customRender: 'code' } },
{ title: 'Hms Message', dataIndex: 'message_en', className: 'titleStyle', ellipsis: true, slots: { customRender: 'message' } },
+ { title: 'Hms Message', dataIndex: 'message_zh', className: 'titleStyle', ellipsis: true, slots: { customRender: 'message' } },
]
interface DeviceHmsData {
diff --git a/src/components/devices/device-upgrade/DeviceFirmwareUpgrade.vue b/src/components/devices/device-upgrade/DeviceFirmwareUpgrade.vue
index 84b0ad8..cbd5d61 100644
--- a/src/components/devices/device-upgrade/DeviceFirmwareUpgrade.vue
+++ b/src/components/devices/device-upgrade/DeviceFirmwareUpgrade.vue
@@ -13,7 +13,7 @@
</span>
<!-- 进度 -->
<span v-if="device.firmware_status === DeviceFirmwareStatusEnum.DuringUpgrade">
- {{ `${device.firmware_progress}%`}}
+ {{ `${device.firmware_progress}`}}
</span>
</div>
</template>
diff --git a/src/components/g-map/DeviceSettingBox.vue b/src/components/g-map/DeviceSettingBox.vue
index 0f7d508..5f6f330 100644
--- a/src/components/g-map/DeviceSettingBox.vue
+++ b/src/components/g-map/DeviceSettingBox.vue
@@ -1,6 +1,6 @@
<template>
<div class="device-setting-wrapper">
- <div class="device-setting-header">设备属性设置</div>
+ <div class="device-setting-header">Device Property Set</div>
<div class="device-setting-box">
<!-- 飞行器夜航灯 -->
<div class="control-setting-item">
@@ -154,7 +154,7 @@
import { cloneDeep } from 'lodash'
import { initDeviceSetting, initDeviceSettingFormModel, DeviceSettingKeyEnum } from '/@/types/device-setting'
import { updateDeviceSettingInfoByOsd, updateDeviceSettingFormModelByOsd } from '/@/utils/device-setting'
-import { useDeviceSetting } from './useDeviceSetting'
+import { useDeviceSetting } from './use-device-setting'
import DeviceSettingPopover from './DeviceSettingPopover.vue'
const props = defineProps<{
diff --git a/src/components/g-map/DockControlPanel.vue b/src/components/g-map/DockControlPanel.vue
index 93e5628..ade675b 100644
--- a/src/components/g-map/DockControlPanel.vue
+++ b/src/components/g-map/DockControlPanel.vue
@@ -2,7 +2,7 @@
<div class="dock-control-panel">
<!-- title -->
<div class="dock-control-panel-header fz16 pl5 pr5 flex-align-center flex-row flex-justify-between">
- <span>设备操作 {{ props.sn}}</span>
+ <span>Device Control<span class="fz12 pl15">{{ props.sn}}</span></span>
<span @click="closeControlPanel">
<CloseOutlined />
</span>
@@ -12,7 +12,7 @@
<!-- cmd -->
<div class="control-cmd-wrapper">
<div class="control-cmd-header">
- 远程调试
+ Device Remote Debug
<a-switch class="debug-btn" checked-children="开" un-checked-children="关" v-model:checked="debugStatus" @change="onDeviceStatusChange"/>
</div>
<div class="control-cmd-box">
@@ -28,7 +28,7 @@
</div>
</div>
</div>
- </div>
+ </div>
</div>
</template>
@@ -38,7 +38,7 @@
import {
CloseOutlined
} from '@ant-design/icons-vue'
-import { useDockControl } from './useDockControl'
+import { useDockControl } from './use-dock-control'
import { DeviceInfoType, EDockModeCode } from '/@/types/device'
import { cmdList as baseCmdList, DeviceCmdItem } from '/@/types/device-cmd'
import { useMyStore } from '/@/store'
@@ -76,7 +76,7 @@
const emit = defineEmits(['close-control-panel'])
function closeControlPanel () {
- emit('close-control-panel', props.sn, false)
+ emit('close-control-panel', props.sn)
}
// dock 控制指令
diff --git a/src/components/g-map/DroneControlInfoPanel.vue b/src/components/g-map/DroneControlInfoPanel.vue
new file mode 100644
index 0000000..4b10ec5
--- /dev/null
+++ b/src/components/g-map/DroneControlInfoPanel.vue
@@ -0,0 +1,34 @@
+<template>
+<div class="drone-control-info-wrap">
+ <a-textarea v-model:value="info" placeholder="drc info" :rows="5" disabled/>
+</div>
+</template>
+
+<script lang="ts" setup>
+import { ref, defineProps, watch } from 'vue'
+
+const props = defineProps<{
+ message?: string,
+}>()
+
+const info = ref('')
+watch(() => props.message, message => {
+ info.value = message || ''
+}, {
+ immediate: true
+})
+
+// const emit = defineEmits(['cancel', 'confirm'])
+</script>
+
+<style lang="scss" scoped>
+.drone-control-info-wrap {
+ &::v-deep{
+ textarea.ant-input {
+ background-color: #000;
+ color: #fff;
+ white-space: pre-wrap;
+ }
+ }
+}
+</style>
diff --git a/src/components/g-map/DroneControlPanel.vue b/src/components/g-map/DroneControlPanel.vue
new file mode 100644
index 0000000..af2311f
--- /dev/null
+++ b/src/components/g-map/DroneControlPanel.vue
@@ -0,0 +1,756 @@
+<template>
+ <div class="drone-control-wrapper">
+ <div class="drone-control-header">Drone Flight Control</div>
+ <div class="drone-control-box">
+ <div class="box">
+ <div class="row">
+ <div class="drone-control"><Button :ghost="!flightController" size="small" @click="onClickFightControl">{{ flightController ? 'Exit Remote Control' : 'Enter Remote Control'}}</Button></div>
+ </div>
+ <div class="row">
+ <div class="drone-control-direction">
+ <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_Q)" @onmouseup="onMouseUp">
+ <template #icon><UndoOutlined /></template><span class="word">Q</span>
+ </Button>
+ <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_W)" @onmouseup="onMouseUp">
+ <template #icon><UpOutlined/></template><span class="word">W</span>
+ </Button>
+ <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_E)" @onmouseup="onMouseUp">
+ <template #icon><RedoOutlined /></template><span class="word">E</span>
+ </Button>
+ <Button size="small" ghost @mousedown="onMouseDown(KeyCode.ARROW_UP)" @onmouseup="onMouseUp">
+ <template #icon><ArrowUpOutlined /></template>
+ </Button>
+ <br />
+ <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_A)" @onmouseup="onMouseUp">
+ <template #icon><LeftOutlined/></template><span class="word">A</span>
+ </Button>
+ <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_S)" @onmouseup="onMouseUp">
+ <template #icon><DownOutlined/></template><span class="word">S</span>
+ </Button>
+ <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_D)" @onmouseup="onMouseUp">
+ <template #icon><RightOutlined/></template><span class="word">D</span>
+ </Button>
+ <Button size="small" ghost @mousedown="onMouseDown(KeyCode.ARROW_DOWN)" @onmouseup="onMouseUp">
+ <template #icon><ArrowDownOutlined /></template>
+ </Button>
+ </div>
+ <Button type="primary" size="small" danger ghost @click="handleEmergencyStop" >
+ <template #icon><PauseCircleOutlined/></template><span>Break</span>
+ </Button>
+ </div>
+ <div class="row">
+ <DroneControlPopover
+ :visible="flyToPointPopoverData.visible"
+ :loading="flyToPointPopoverData.loading"
+ @confirm="($event) => onFlyToConfirm(true)"
+ @cancel="($event) =>onFlyToConfirm(false)"
+ >
+ <template #formContent>
+ <div class="form-content">
+ <div>
+ <span class="form-label">latitude:</span>
+ <a-input-number v-model:value="flyToPointPopoverData.latitude"/>
+ </div>
+ <div>
+ <span class="form-label">longitude:</span>
+ <a-input-number v-model:value="flyToPointPopoverData.longitude"/>
+ </div>
+ <div>
+ <span class="form-label">height(m):</span>
+ <a-input-number v-model:value="flyToPointPopoverData.height"/>
+ </div>
+ </div>
+ </template>
+ <Button size="small" ghost @click="onShowFlyToPopover" >
+ <span>Fly to</span>
+ </Button>
+ </DroneControlPopover>
+ <Button size="small" ghost @click="onStopFlyToPoint" >
+ <span>Stop Fly to</span>
+ </Button>
+ <DroneControlPopover
+ :visible="takeoffToPointPopoverData.visible"
+ :loading="takeoffToPointPopoverData.loading"
+ @confirm="($event) => onTakeoffToPointConfirm(true)"
+ @cancel="($event) =>onTakeoffToPointConfirm(false)"
+ >
+ <template #formContent>
+ <div class="form-content">
+ <div>
+ <span class="form-label">latitude:</span>
+ <a-input-number v-model:value="takeoffToPointPopoverData.latitude"/>
+ </div>
+ <div>
+ <span class="form-label">longitude:</span>
+ <a-input-number v-model:value="takeoffToPointPopoverData.longitude"/>
+ </div>
+ <div>
+ <span class="form-label">height(m):</span>
+ <a-input-number v-model:value="takeoffToPointPopoverData.height"/>
+ </div>
+ <div>
+ <span class="form-label">Safe Takeoff Altitude(m):</span>
+ <a-input-number v-model:value="takeoffToPointPopoverData.securityTakeoffHeight"/>
+ </div>
+ <div>
+ <span class="form-label">Return-to-Home Altitude(m):</span>
+ <a-input-number v-model:value="takeoffToPointPopoverData.rthAltitude"/>
+ </div>
+ <div>
+ <span class="form-label">Lost Action:</span>
+ <a-select
+ v-model:value="takeoffToPointPopoverData.rcLostAction"
+ style="width: 120px"
+ :options="LostControlActionInCommandFLightOptions"
+ ></a-select>
+ </div>
+ <div>
+ <span class="form-label">Wayline Lost Action:</span>
+ <a-select
+ v-model:value="takeoffToPointPopoverData.exitWaylineWhenRcLost"
+ style="width: 120px"
+ :options="WaylineLostControlActionInCommandFlightOptions"
+ ></a-select>
+ </div>
+ </div>
+ </template>
+ <Button size="small" ghost @click="onShowTakeoffToPointPopover" >
+ <span>Take off</span>
+ </Button>
+ </DroneControlPopover>
+ <Button :loading="cmdItem.loading" size="small" ghost @click="sendControlCmd(cmdItem, index)">
+ {{ cmdItem.operateText }}
+ </Button>
+ </div>
+ </div>
+ <div class="box">
+ <div class="row">
+ <Select v-model:value="payloadSelectInfo.value" style="width: 110px; marginRight: 5px" :options="payloadSelectInfo.options" @change="handlePayloadChange"/>
+ <div class="drone-control">
+ <Button type="primary" size="small" @click="onAuthPayload">Payload Control</Button>
+ </div>
+ </div>
+ <div class="row">
+ <DroneControlPopover
+ :visible="gimbalResetPopoverData.visible"
+ :loading="gimbalResetPopoverData.loading"
+ @confirm="($event) => onGimbalResetConfirm(true)"
+ @cancel="($event) =>onGimbalResetConfirm(false)"
+ >
+ <template #formContent>
+ <div class="form-content">
+ <div>
+ <span class="form-label">reset mode:</span>
+ <a-select
+ v-model:value="gimbalResetPopoverData.resetMode"
+ style="width: 180px"
+ :options="GimbalResetModeOptions"
+ ></a-select>
+ </div>
+ </div>
+ </template>
+ <Button size="small" ghost @click="onShowGimbalResetPopover">
+ <span>Gimbal Reset</span>
+ </Button>
+ </DroneControlPopover>
+ <Button size="small" ghost @click="onSwitchCameraMode">
+ <span>Camera Mode Switch</span>
+ </Button>
+ </div>
+ <div class="row">
+ <Button size="small" ghost @click="onStartCameraRecording">
+ <span>Start Recording</span>
+ </Button>
+ <Button size="small" ghost @click="onStopCameraRecording">
+ <span>Stop Recording</span>
+ </Button>
+ </div>
+ <div class="row">
+ <Button size="small" ghost @click="onTakeCameraPhoto">
+ <span>Take Photo</span>
+ </Button>
+ <DroneControlPopover
+ :visible="zoomFactorPopoverData.visible"
+ :loading="zoomFactorPopoverData.loading"
+ @confirm="($event) => onZoomFactorConfirm(true)"
+ @cancel="($event) =>onZoomFactorConfirm(false)"
+ >
+ <template #formContent>
+ <div class="form-content">
+ <div>
+ <span class="form-label">camera type:</span>
+ <a-select
+ v-model:value="zoomFactorPopoverData.cameraType"
+ style="width: 120px"
+ :options="ZoomCameraTypeOptions"
+ ></a-select>
+ </div>
+ <div>
+ <span class="form-label">zoom factor:</span>
+ <a-input-number v-model:value="zoomFactorPopoverData.zoomFactor" :min="2" :max="200" />
+ </div>
+ </div>
+ </template>
+ <Button size="small" ghost @click="($event) => onShowZoomFactorPopover()">
+ <span class="word" @click=";">Zoom</span>
+ </Button>
+ </DroneControlPopover>
+ <DroneControlPopover
+ :visible="cameraAimPopoverData.visible"
+ :loading="cameraAimPopoverData.loading"
+ @confirm="($event) => onCameraAimConfirm(true)"
+ @cancel="($event) =>onCameraAimConfirm(false)"
+ >
+ <template #formContent>
+ <div class="form-content">
+ <div>
+ <span class="form-label">camera type:</span>
+ <a-select
+ v-model:value="cameraAimPopoverData.cameraType"
+ style="width: 120px"
+ :options="CameraTypeOptions"
+ ></a-select>
+ </div>
+ <div>
+ <span class="form-label">locked:</span>
+ <a-switch v-model:checked="cameraAimPopoverData.locked"/>
+ </div>
+ <div>
+ <span class="form-label">x:</span>
+ <a-input-number v-model:value="cameraAimPopoverData.x" :min="0" :max="1"/>
+ </div>
+ <div>
+ <span class="form-label">y:</span>
+ <a-input-number v-model:value="cameraAimPopoverData.y" :min="0" :max="1"/>
+ </div>
+ </div>
+ </template>
+ <Button size="small" ghost @click="($event) => onShowCameraAimPopover()">
+ <span class="word" @click=";">AIM</span>
+ </Button>
+ </DroneControlPopover>
+ </div>
+ </div>
+ </div>
+ <!-- 信息提示 -->
+ <DroneControlInfoPanel :message="drcInfo"></DroneControlInfoPanel>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { defineProps, reactive, ref, watch, computed, onMounted, watchEffect } from 'vue'
+import { Select, message, Button } from 'ant-design-vue'
+import { PayloadInfo, DeviceInfoType, ControlSource, DeviceOsdCamera, DrcStateEnum } from '/@/types/device'
+import { useMyStore } from '/@/store'
+import { postDrcEnter, postDrcExit } from '/@/api/drc'
+import { useMqtt, DeviceTopicInfo } from './use-mqtt'
+import { DownOutlined, UpOutlined, LeftOutlined, RightOutlined, PauseCircleOutlined, UndoOutlined, RedoOutlined, ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons-vue'
+import { useManualControl, KeyCode } from './use-manual-control'
+import { usePayloadControl } from './use-payload-control'
+import { CameraMode, CameraType, CameraTypeOptions, ZoomCameraTypeOptions, CameraListItem } from '/@/types/live-stream'
+import { useDroneControlWsEvent } from './use-drone-control-ws-event'
+import { useDroneControlMqttEvent } from './use-drone-control-mqtt-event'
+import { postFlightAuth, LostControlActionInCommandFLight, WaylineLostControlActionInCommandFlight } from '/@/api/drone-control/drone'
+import { useDroneControl } from './use-drone-control'
+import { GimbalResetMode, GimbalResetModeOptions, LostControlActionInCommandFLightOptions, WaylineLostControlActionInCommandFlightOptions } from '/@/types/drone-control'
+import DroneControlPopover from './DroneControlPopover.vue'
+import DroneControlInfoPanel from './DroneControlInfoPanel.vue'
+import { noDebugCmdList as baseCmdList, DeviceCmdItem, DeviceCmd } from '/@/types/device-cmd'
+import { useDockControl } from './use-dock-control'
+
+const props = defineProps<{
+ sn: string,
+ deviceInfo: DeviceInfoType,
+ payloads: null | PayloadInfo[]
+}>()
+
+const store = useMyStore()
+const clientId = computed(() => {
+ return store.state.clientId
+})
+
+const initCmdList = baseCmdList.find(item => item.cmdKey === DeviceCmd.ReturnHome)
+const cmdItem = ref(initCmdList)
+
+const {
+ sendDockControlCmd
+} = useDockControl()
+
+async function sendControlCmd (cmdItem: DeviceCmdItem, index: number) {
+ cmdItem.loading = true
+ const result = await sendDockControlCmd({
+ sn: props.sn,
+ cmd: cmdItem.cmdKey,
+ action: cmdItem.action
+ }, false)
+ if (result && flightController.value) {
+ exitFlightCOntrol()
+ }
+ cmdItem.loading = false
+}
+
+const { flyToPoint, stopFlyToPoint, takeoffToPoint } = useDroneControl()
+const MAX_SPEED = 14
+
+const flyToPointPopoverData = reactive({
+ visible: false,
+ loading: false,
+ latitude: null as null | number,
+ longitude: null as null | number,
+ height: null as null | number,
+ maxSpeed: MAX_SPEED,
+})
+
+function onShowFlyToPopover () {
+ flyToPointPopoverData.visible = !flyToPointPopoverData.visible
+ flyToPointPopoverData.loading = false
+ flyToPointPopoverData.latitude = null
+ flyToPointPopoverData.longitude = null
+ flyToPointPopoverData.height = null
+}
+
+async function onFlyToConfirm (confirm: boolean) {
+ if (confirm) {
+ if (!flyToPointPopoverData.height || !flyToPointPopoverData.latitude || !flyToPointPopoverData.longitude) {
+ message.error('Input error')
+ return
+ }
+ try {
+ await flyToPoint(props.sn, {
+ max_speed: flyToPointPopoverData.maxSpeed,
+ points: [
+ {
+ latitude: flyToPointPopoverData.latitude,
+ longitude: flyToPointPopoverData.longitude,
+ height: flyToPointPopoverData.height
+ }
+ ]
+ })
+ } catch (error) {
+ }
+ }
+ flyToPointPopoverData.visible = false
+}
+
+async function onStopFlyToPoint () {
+ await stopFlyToPoint(props.sn)
+}
+
+const takeoffToPointPopoverData = reactive({
+ visible: false,
+ loading: false,
+ latitude: null as null | number,
+ longitude: null as null | number,
+ height: null as null | number,
+ securityTakeoffHeight: null as null | number,
+ maxSpeed: MAX_SPEED,
+ rthAltitude: null as null | number,
+ rcLostAction: LostControlActionInCommandFLight.RETURN_HOME,
+ exitWaylineWhenRcLost: WaylineLostControlActionInCommandFlight.RETURN_HOME
+})
+
+function onShowTakeoffToPointPopover () {
+ takeoffToPointPopoverData.visible = !takeoffToPointPopoverData.visible
+ takeoffToPointPopoverData.loading = false
+ takeoffToPointPopoverData.latitude = null
+ takeoffToPointPopoverData.longitude = null
+ takeoffToPointPopoverData.securityTakeoffHeight = null
+ takeoffToPointPopoverData.rthAltitude = null
+ takeoffToPointPopoverData.rcLostAction = LostControlActionInCommandFLight.RETURN_HOME
+ takeoffToPointPopoverData.exitWaylineWhenRcLost = WaylineLostControlActionInCommandFlight.RETURN_HOME
+}
+
+async function onTakeoffToPointConfirm (confirm: boolean) {
+ if (confirm) {
+ if (!takeoffToPointPopoverData.height ||
+ !takeoffToPointPopoverData.latitude ||
+ !takeoffToPointPopoverData.longitude ||
+ !takeoffToPointPopoverData.securityTakeoffHeight ||
+ !takeoffToPointPopoverData.rthAltitude) {
+ message.error('Input error')
+ return
+ }
+ try {
+ await takeoffToPoint(props.sn, {
+ target_latitude: takeoffToPointPopoverData.latitude,
+ target_longitude: takeoffToPointPopoverData.longitude,
+ target_height: takeoffToPointPopoverData.height,
+ security_takeoff_height: takeoffToPointPopoverData.securityTakeoffHeight,
+ rth_altitude: takeoffToPointPopoverData.rthAltitude,
+ max_speed: takeoffToPointPopoverData.maxSpeed,
+ rc_lost_action: takeoffToPointPopoverData.rcLostAction,
+ exit_wayline_when_rc_lost: takeoffToPointPopoverData.exitWaylineWhenRcLost
+ })
+ } catch (error) {
+ }
+ }
+ takeoffToPointPopoverData.visible = false
+}
+
+const deviceTopicInfo: DeviceTopicInfo = reactive({
+ sn: props.sn,
+ pubTopic: '',
+ subTopic: ''
+})
+
+useMqtt(deviceTopicInfo)
+
+// 飞行控制
+const drcState = computed(() => {
+ return store.state.deviceState?.dockInfo[props.sn]?.link_osd?.drc_state === DrcStateEnum.CONNECTED
+})
+const flightController = ref(drcState.value)
+
+async function onClickFightControl () {
+ if (flightController.value) {
+ exitFlightCOntrol()
+ return
+ }
+ enterFlightControl()
+}
+
+// 进入飞行控制
+async function enterFlightControl () {
+ try {
+ const { code, data } = await postDrcEnter({
+ client_id: clientId.value,
+ dock_sn: props.sn,
+ })
+ if (code === 0) {
+ flightController.value = true
+ if (data.sub && data.sub.length > 0) {
+ deviceTopicInfo.subTopic = data.sub[0]
+ }
+ if (data.pub && data.pub.length > 0) {
+ deviceTopicInfo.pubTopic = data.pub[0]
+ }
+ // 获取飞行控制权
+ if (droneControlSource.value !== ControlSource.A) {
+ await postFlightAuth(props.sn)
+ }
+ message.success('Get flight control successfully')
+ }
+ } catch (error: any) {
+ }
+}
+
+// 退出飞行控制
+async function exitFlightCOntrol () {
+ try {
+ const { code } = await postDrcExit({
+ client_id: clientId.value,
+ dock_sn: props.sn,
+ })
+ if (code === 0) {
+ flightController.value = false
+ deviceTopicInfo.subTopic = ''
+ deviceTopicInfo.pubTopic = ''
+ message.success('Exit flight control')
+ }
+ } catch (error: any) {
+ }
+}
+
+// drc mqtt message
+const { drcInfo } = useDroneControlMqttEvent(props.sn)
+
+const {
+ handleKeyup,
+ handleEmergencyStop,
+ resetControlState,
+} = useManualControl(deviceTopicInfo, flightController)
+
+function onMouseDown (type: KeyCode) {
+ handleKeyup(type)
+}
+
+function onMouseUp () {
+ resetControlState()
+}
+
+// 负载控制
+const payloadSelectInfo = {
+ value: null as any,
+ controlSource: undefined as undefined | ControlSource,
+ options: [] as any,
+ payloadIndex: '' as string,
+ camera: undefined as undefined | DeviceOsdCamera // 当前负载osd信息
+}
+
+const handlePayloadChange = (value: string) => {
+ const payload = props.payloads?.find(item => item.payload_sn === value)
+ if (payload) {
+ payloadSelectInfo.payloadIndex = payload.payload_index || ''
+ payloadSelectInfo.controlSource = payload.control_source
+ payloadSelectInfo.camera = undefined
+ }
+}
+
+// function getCurrentCamera (cameraList: CameraListItem[], cameraIndex?: string):CameraListItem | null {
+// let camera = null
+// cameraList.forEach(item => {
+// if (item.camera_index === cameraIndex) {
+// camera = item
+// }
+// })
+// return camera
+// }
+
+// const currentCamera = computed(() => {
+// return getCurrentCamera(props.deviceInfo.dock.basic_osd.live_capacity?.device_list[0]?.camera_list as CameraListItem[], camera_index)
+// })
+// 更新负载信息
+watch(() => props.payloads, (payloads) => {
+ if (payloads && payloads.length > 0) {
+ payloadSelectInfo.value = payloads[0].payload_sn
+ payloadSelectInfo.controlSource = payloads[0].control_source || ControlSource.B
+ payloadSelectInfo.payloadIndex = payloads[0].payload_index || ''
+ payloadSelectInfo.options = payloads.map(item => ({ label: item.payload_name, value: item.payload_sn }))
+ payloadSelectInfo.camera = undefined
+ } else {
+ payloadSelectInfo.value = null
+ payloadSelectInfo.controlSource = undefined
+ payloadSelectInfo.options = []
+ payloadSelectInfo.payloadIndex = ''
+ payloadSelectInfo.camera = undefined
+ }
+}, {
+ immediate: true,
+ deep: true
+})
+watch(() => props.deviceInfo.device, (droneOsd) => {
+ if (droneOsd && droneOsd.cameras) {
+ payloadSelectInfo.camera = droneOsd.cameras.find(item => item.payload_index === payloadSelectInfo.payloadIndex)
+ } else {
+ payloadSelectInfo.camera = undefined
+ }
+}, {
+ immediate: true,
+ deep: true
+})
+
+// ws 消息通知
+const { droneControlSource, payloadControlSource } = useDroneControlWsEvent(props.sn, payloadSelectInfo.value)
+watch(() => payloadControlSource, (controlSource) => {
+ payloadSelectInfo.controlSource = controlSource.value
+}, {
+ immediate: true,
+ deep: true
+})
+const {
+ checkPayloadAuth,
+ authPayload,
+ resetGimbal,
+ switchCameraMode,
+ takeCameraPhoto,
+ startCameraRecording,
+ stopCameraRecording,
+ changeCameraFocalLength,
+ cameraAim,
+} = usePayloadControl()
+
+async function onAuthPayload () {
+ const result = await authPayload(props.sn, payloadSelectInfo.payloadIndex)
+ if (result) {
+ payloadControlSource.value = ControlSource.A
+ }
+}
+
+const gimbalResetPopoverData = reactive({
+ visible: false,
+ loading: false,
+ resetMode: null as null | GimbalResetMode,
+})
+
+function onShowGimbalResetPopover () {
+ gimbalResetPopoverData.visible = !gimbalResetPopoverData.visible
+ gimbalResetPopoverData.loading = false
+ gimbalResetPopoverData.resetMode = null
+}
+
+async function onGimbalResetConfirm (confirm: boolean) {
+ if (confirm) {
+ if (gimbalResetPopoverData.resetMode === null) {
+ message.error('Please select reset mode')
+ return
+ }
+ gimbalResetPopoverData.loading = true
+ try {
+ await resetGimbal(props.sn, {
+ payload_index: payloadSelectInfo.payloadIndex,
+ reset_mode: gimbalResetPopoverData.resetMode
+ })
+ } catch (err) {
+ }
+ }
+ gimbalResetPopoverData.visible = false
+}
+
+async function onSwitchCameraMode () {
+ if (!checkPayloadAuth(payloadSelectInfo.controlSource)) {
+ return
+ }
+ const currentCameraMode = payloadSelectInfo.camera?.camera_mode
+ await switchCameraMode(props.sn, {
+ payload_index: payloadSelectInfo.payloadIndex,
+ camera_mode: currentCameraMode === CameraMode.Photo ? CameraMode.Video : CameraMode.Photo
+ })
+}
+
+async function onTakeCameraPhoto () {
+ if (!checkPayloadAuth(payloadSelectInfo.controlSource)) {
+ return
+ }
+ await takeCameraPhoto(props.sn, payloadSelectInfo.payloadIndex)
+}
+
+async function onStartCameraRecording () {
+ if (!checkPayloadAuth(payloadSelectInfo.controlSource)) {
+ return
+ }
+ await startCameraRecording(props.sn, payloadSelectInfo.payloadIndex)
+}
+
+async function onStopCameraRecording () {
+ if (!checkPayloadAuth(payloadSelectInfo.controlSource)) {
+ return
+ }
+ await stopCameraRecording(props.sn, payloadSelectInfo.payloadIndex)
+}
+
+const zoomFactorPopoverData = reactive({
+ visible: false,
+ loading: false,
+ cameraType: null as null | CameraType,
+ zoomFactor: null as null | number,
+})
+
+function onShowZoomFactorPopover () {
+ zoomFactorPopoverData.visible = !zoomFactorPopoverData.visible
+ zoomFactorPopoverData.loading = false
+ zoomFactorPopoverData.cameraType = null
+ zoomFactorPopoverData.zoomFactor = null
+}
+
+async function onZoomFactorConfirm (confirm: boolean) {
+ if (confirm) {
+ if (!zoomFactorPopoverData.zoomFactor || zoomFactorPopoverData.cameraType === null) {
+ message.error('Please input Zoom Factor')
+ return
+ }
+ zoomFactorPopoverData.loading = true
+ try {
+ await changeCameraFocalLength(props.sn, {
+ payload_index: payloadSelectInfo.payloadIndex,
+ camera_type: zoomFactorPopoverData.cameraType,
+ zoom_factor: zoomFactorPopoverData.zoomFactor
+ })
+ } catch (err) {
+ }
+ }
+ zoomFactorPopoverData.visible = false
+}
+
+const cameraAimPopoverData = reactive({
+ visible: false,
+ loading: false,
+ cameraType: null as null | CameraType,
+ locked: false,
+ x: null as null | number,
+ y: null as null | number,
+})
+
+function onShowCameraAimPopover () {
+ cameraAimPopoverData.visible = !cameraAimPopoverData.visible
+ cameraAimPopoverData.loading = false
+ cameraAimPopoverData.cameraType = null
+ cameraAimPopoverData.locked = false
+ cameraAimPopoverData.x = null
+ cameraAimPopoverData.y = null
+}
+
+async function onCameraAimConfirm (confirm: boolean) {
+ if (confirm) {
+ if (cameraAimPopoverData.cameraType === null || cameraAimPopoverData.x === null || cameraAimPopoverData.y === null) {
+ message.error('Input error')
+ return
+ }
+ try {
+ await cameraAim(props.sn, {
+ payload_index: payloadSelectInfo.payloadIndex,
+ camera_type: cameraAimPopoverData.cameraType,
+ locked: cameraAimPopoverData.locked,
+ x: cameraAimPopoverData.x,
+ y: cameraAimPopoverData.y,
+ })
+ } catch (error) {
+ }
+ }
+ cameraAimPopoverData.visible = false
+}
+</script>
+
+<style lang='scss' scoped>
+.drone-control-wrapper{
+ // border-bottom: 1px solid #515151;
+
+ .drone-control-header{
+ font-size: 14px;
+ font-weight: 600;
+ padding: 10px 10px 0px;
+ }
+
+ .drone-control-box {
+ display: flex;
+ flex-wrap: 1;
+ .box {
+ width: 50%;
+ padding: 5px;
+ border: 0.5px solid rgba(255,255,255,0.3);
+
+ .row {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 2px;
+
+ + .row{
+ margin-bottom: 6px;
+ }
+
+ &::v-deep{
+ .ant-btn{
+ font-size: 12px;
+ padding: 0px 4px;
+ margin-right: 5px;
+ }
+ }
+ }
+
+ .drone-control{
+ &::v-deep{
+
+ .ant-select-single:not(.ant-select-customize-input) .ant-select-selector{
+ padding: 0 2px;
+ }
+ }
+ }
+
+ .drone-control-direction{
+ margin-right: 10px;
+
+ .ant-btn {
+ // padding: 0px 1px;
+ margin-right: 0;
+ }
+
+ .word{
+ width: 12px;
+ margin-left: 2px;
+ font-size: 12px;
+ color: #aaa;
+ }
+ }
+ }
+ }
+}
+</style>
diff --git a/src/components/g-map/DroneControlPopover.vue b/src/components/g-map/DroneControlPopover.vue
new file mode 100644
index 0000000..9948c28
--- /dev/null
+++ b/src/components/g-map/DroneControlPopover.vue
@@ -0,0 +1,115 @@
+<template>
+ <a-popover :visible="state.sVisible"
+ trigger="click"
+ v-bind="$attrs"
+ :overlay-class-name="overlayClassName"
+ placement="bottom"
+ @visibleChange=";"
+ v-on="$attrs">
+ <template #content>
+ <div class="title-content">
+ </div>
+ <slot name="formContent" />
+ <div class="uranus-popconfirm-btns">
+ <a-button size="sm"
+ @click="onCancel">
+ {{ cancelText || 'cancel'}}
+ </a-button>
+ <a-button size="sm"
+ :loading="loading"
+ type="primary"
+ class="confirm-btn"
+ @click="onConfirm">
+ {{ okText || 'ok' }}
+ </a-button>
+ </div>
+ </template>
+ <template v-if="$slots.default">
+ <slot></slot>
+ </template>
+ </a-popover>
+</template>
+
+<script lang="ts" setup>
+import { defineProps, defineEmits, reactive, watch, computed } from 'vue'
+
+const props = defineProps<{
+ visible?: boolean,
+ loading?: Boolean,
+ disabled?: Boolean,
+ title?: String,
+ okText?: String,
+ cancelText?: String,
+ width?: Number,
+}>()
+
+const emit = defineEmits(['cancel', 'confirm'])
+
+const state = reactive({
+ sVisible: false,
+ loading: false,
+})
+
+watch(() => props.visible, (val) => {
+ state.sVisible = val || false
+})
+
+const loading = computed(() => {
+ return props.loading
+})
+const okLabel = computed(() => {
+ return props.loading ? '' : '确定'
+})
+
+const overlayClassName = computed(() => {
+ const classList = ['drone-control-popconfirm']
+ return classList.join(' ')
+})
+
+function onConfirm (e: Event) {
+ if (props.disabled) {
+ return
+ }
+ emit('confirm', e)
+}
+
+function onCancel (e: Event) {
+ state.sVisible = false
+ emit('cancel', e)
+}
+
+</script>
+
+<style lang="scss">
+.drone-control-popconfirm {
+ min-width: 300px;
+
+ .uranus-popconfirm-btns{
+ display: flex;
+ padding: 10px 0px;
+ justify-content: flex-end;
+
+ .confirm-btn{
+ margin-left: 10px;
+ }
+ }
+
+ .form-content{
+ display: flex;
+ flex-direction: column;
+
+ > div {
+ display: flex;
+ margin-bottom: 5px;
+
+ .form-label {
+ flex: 1 0 60px;
+ margin-right: 10px;
+ }
+
+ > div {
+ }
+ }
+ }
+}
+</style>
diff --git a/src/components/g-map/use-connect-mqtt.ts b/src/components/g-map/use-connect-mqtt.ts
new file mode 100644
index 0000000..a032168
--- /dev/null
+++ b/src/components/g-map/use-connect-mqtt.ts
@@ -0,0 +1,71 @@
+
+import {
+ ref,
+ watch,
+ computed,
+ onUnmounted,
+} from 'vue'
+import { useMyStore } from '/@/store'
+import { postDrc } from '/@/api/drc'
+import {
+ UranusMqtt,
+} from '/@/mqtt'
+
+type StatusOptions = {
+ status: 'close';
+ event?: CloseEvent;
+} | {
+ status: 'open';
+ retryCount: number;
+} | {
+ status: 'pending';
+}
+
+export function useConnectMqtt () {
+ const store = useMyStore()
+ const dockOsdVisible = computed(() => {
+ return store.state.osdVisible && store.state.osdVisible.visible && store.state.osdVisible.is_dock
+ })
+ const mqttState = ref<UranusMqtt | null>(null)
+
+ // 监听已打开的设备小窗 窗口数量
+ watch(() => dockOsdVisible.value, async (val) => {
+ // 1.打开小窗
+ // 2.设备拥有飞行控制权
+ // 3.请求建立mqtt连接的认证信息
+ if (val) {
+ if (mqttState.value) return
+ const result = await postDrc({})
+ if (result?.code === 0) {
+ const { address, client_id, username, password, expire_time } = result.data
+ // @TODO: 校验 expire_time
+ mqttState.value = new UranusMqtt(address, {
+ clientId: client_id,
+ username,
+ password,
+ })
+ mqttState.value?.initMqtt()
+ mqttState.value?.on('onStatus', (statusOptions: StatusOptions) => {
+ // @TODO: 异常case
+ })
+
+ store.commit('SET_MQTT_STATE', mqttState.value)
+ store.commit('SET_CLIENT_ID', client_id)
+ }
+ // @TODO: 认证失败case
+ return
+ }
+ // 关闭所有小窗后
+ // 1.销毁mqtt连接重置mqtt状态
+ if (mqttState?.value) {
+ mqttState.value?.destroyed()
+ mqttState.value = null
+ store.commit('SET_MQTT_STATE', null)
+ store.commit('SET_CLIENT_ID', '')
+ }
+ }, { immediate: true })
+
+ onUnmounted(() => {
+ mqttState.value?.destroyed()
+ })
+}
diff --git a/src/components/g-map/useDeviceSetting.ts b/src/components/g-map/use-device-setting.ts
similarity index 100%
rename from src/components/g-map/useDeviceSetting.ts
rename to src/components/g-map/use-device-setting.ts
diff --git a/src/components/g-map/useDockControl.ts b/src/components/g-map/use-dock-control.ts
similarity index 75%
rename from src/components/g-map/useDockControl.ts
rename to src/components/g-map/use-dock-control.ts
index 5e8c38c..3cf9b1a 100644
--- a/src/components/g-map/useDockControl.ts
+++ b/src/components/g-map/use-dock-control.ts
@@ -4,10 +4,10 @@
import { DeviceCmd, DeviceCmdItemAction } from '/@/types/device-cmd'
export function useDockControl () {
- const controlPanelVisible = ref(false)
+ const dockControlPanelVisible = ref(false)
- function setControlPanelVisible (visible: boolean) {
- controlPanelVisible.value = visible
+ function setDockControlPanelVisible (visible: boolean) {
+ dockControlPanelVisible.value = visible
}
// 远程调试开关
@@ -16,9 +16,6 @@
sn: sn,
cmd: on ? DeviceCmd.DebugModeOpen : DeviceCmd.DebugModeClose
}, false)
- if (result) {
- setControlPanelVisible(on)
- }
return result
}
@@ -47,10 +44,17 @@
}
}
+ // 控制面板关闭
+ async function onCloseControlPanel (sn: string) {
+ await dockDebugOnOff(sn, false)
+ setDockControlPanelVisible(false)
+ }
+
return {
- controlPanelVisible,
- setControlPanelVisible,
+ dockControlPanelVisible,
+ setDockControlPanelVisible,
sendDockControlCmd,
dockDebugOnOff,
+ onCloseControlPanel,
}
}
diff --git a/src/components/g-map/use-drone-control-mqtt-event.ts b/src/components/g-map/use-drone-control-mqtt-event.ts
new file mode 100644
index 0000000..4a3d299
--- /dev/null
+++ b/src/components/g-map/use-drone-control-mqtt-event.ts
@@ -0,0 +1,61 @@
+import { ref, onMounted, onBeforeUnmount } from 'vue'
+import EventBus from '/@/event-bus/'
+import {
+ DRC_METHOD,
+ DRCHsiInfo,
+ DRCOsdInfo,
+ DRCDelayTimeInfo,
+} from '/@/types/drc'
+
+export function useDroneControlMqttEvent (sn: string) {
+ const drcInfo = ref('')
+ const hsiInfo = ref('')
+ const osdInfo = ref('')
+ const delayInfo = ref('')
+
+ function handleHsiInfo (data: DRCHsiInfo) {
+ hsiInfo.value = `method: ${DRC_METHOD.HSI_INFO_PUSH}\r\n ${JSON.stringify(data)}\r\n `
+ }
+
+ function handleOsdInfo (data: DRCOsdInfo) {
+ osdInfo.value = `method: ${DRC_METHOD.OSD_INFO_PUSH}\r\n ${JSON.stringify(data)}\r\n `
+ }
+
+ function handleDelayTimeInfo (data: DRCDelayTimeInfo) {
+ delayInfo.value = `method: ${DRC_METHOD.DELAY_TIME_INFO_PUSH}\r\n ${JSON.stringify(data)}\r\n `
+ }
+
+ function handleDroneControlMqttEvent (payload: any) {
+ if (!payload || !payload.method) {
+ return
+ }
+
+ switch (payload.method) {
+ case DRC_METHOD.HSI_INFO_PUSH: {
+ handleHsiInfo(payload.data)
+ break
+ }
+ case DRC_METHOD.OSD_INFO_PUSH: {
+ handleOsdInfo(payload.data)
+ break
+ }
+ case DRC_METHOD.DELAY_TIME_INFO_PUSH: {
+ handleDelayTimeInfo(payload.data)
+ break
+ }
+ }
+ drcInfo.value = hsiInfo.value + osdInfo.value + delayInfo.value
+ }
+
+ onMounted(() => {
+ EventBus.on('droneControlMqttInfo', handleDroneControlMqttEvent)
+ })
+
+ onBeforeUnmount(() => {
+ EventBus.off('droneControlMqttInfo', handleDroneControlMqttEvent)
+ })
+
+ return {
+ drcInfo: drcInfo
+ }
+}
diff --git a/src/components/g-map/use-drone-control-ws-event.ts b/src/components/g-map/use-drone-control-ws-event.ts
new file mode 100644
index 0000000..34981c2
--- /dev/null
+++ b/src/components/g-map/use-drone-control-ws-event.ts
@@ -0,0 +1,97 @@
+import { message, notification } from 'ant-design-vue'
+import { ref, onMounted, onBeforeUnmount } from 'vue'
+import EventBus from '/@/event-bus/'
+import { EBizCode } from '/@/types'
+import { ControlSource } from '/@/types/device'
+import { ControlSourceChangeType, ControlSourceChangeInfo, FlyToPointMessage, TakeoffToPointMessage, DrcModeExitNotifyMessage, DrcStatusNotifyMessage } from '/@/types/drone-control'
+
+export interface UseDroneControlWsEventParams {
+}
+
+export function useDroneControlWsEvent (sn: string, payloadSn: string, funcs?: UseDroneControlWsEventParams) {
+ const droneControlSource = ref(ControlSource.A)
+ const payloadControlSource = ref(ControlSource.B)
+ function onControlSourceChange (data: ControlSourceChangeInfo) {
+ if (data.type === ControlSourceChangeType.Flight && data.sn === sn) {
+ droneControlSource.value = data.control_source
+ message.info(`Flight control is changed to ${droneControlSource.value}`)
+ return
+ }
+ if (data.type === ControlSourceChangeType.Payload && data.sn === payloadSn) {
+ payloadControlSource.value = data.control_source
+ message.info(`Payload control is changed to ${ payloadControlSource.value }.`)
+ return
+ }
+ }
+
+ function handleProgress(key: string, message: string, error: number) {
+ if (error !== 0) {
+ notification.error({
+ key: key,
+ message: key + 'Error code:' + error,
+ description: message,
+ duration: null
+ })
+ } else {
+ notification.info({
+ key: key,
+ message: key,
+ description: message,
+ duration: 30
+ })
+ }
+ }
+
+ function handleDroneControlWsEvent (payload: any) {
+ if (!payload) {
+ return
+ }
+
+ switch (payload.biz_code) {
+ case EBizCode.ControlSourceChange: {
+ onControlSourceChange(payload.data)
+ break
+ }
+ case EBizCode.FlyToPointProgress: {
+ const { sn: deviceSn, result, message: msg } = payload.data as FlyToPointMessage
+ if (deviceSn !== sn) return
+ handleProgress(EBizCode.FlyToPointProgress, `device(sn: ${deviceSn}) ${msg}`, result)
+ break
+ }
+ case EBizCode.TakeoffToPointProgress: {
+ const { sn: deviceSn, result, message: msg } = payload.data as TakeoffToPointMessage
+ if (deviceSn !== sn) return
+ handleProgress(EBizCode.TakeoffToPointProgress, `device(sn: ${deviceSn}) ${msg}`, result)
+ break
+ }
+ case EBizCode.JoystickInvalidNotify: {
+ const { sn: deviceSn, result, message: msg } = payload.data as DrcModeExitNotifyMessage
+ if (deviceSn !== sn) return
+ handleProgress(EBizCode.JoystickInvalidNotify, `device(sn: ${deviceSn}) ${msg}`, result)
+ break
+ }
+ case EBizCode.DrcStatusNotify: {
+ const { sn: deviceSn, result, message: msg } = payload.data as DrcStatusNotifyMessage
+ if (deviceSn !== sn) return
+ // handleProgress(EBizCode.DrcStatusNotify, `device(sn: ${deviceSn}) ${msg}`, result)
+
+ break
+ }
+ }
+ // eslint-disable-next-line no-unused-expressions
+ // console.log('payload.biz_code', payload.data)
+ }
+
+ onMounted(() => {
+ EventBus.on('droneControlWs', handleDroneControlWsEvent)
+ })
+
+ onBeforeUnmount(() => {
+ EventBus.off('droneControlWs', handleDroneControlWsEvent)
+ })
+
+ return {
+ droneControlSource: droneControlSource,
+ payloadControlSource: payloadControlSource
+ }
+}
diff --git a/src/components/g-map/use-drone-control.ts b/src/components/g-map/use-drone-control.ts
new file mode 100644
index 0000000..dee8366
--- /dev/null
+++ b/src/components/g-map/use-drone-control.ts
@@ -0,0 +1,40 @@
+import { ref } from 'vue'
+import { postFlyToPoint, PostFlyToPointBody, deleteFlyToPoint, postTakeoffToPoint, PostTakeoffToPointBody } from '/@/api/drone-control/drone'
+import { message } from 'ant-design-vue'
+
+export function useDroneControl () {
+ const droneControlPanelVisible = ref(false)
+
+ function setDroneControlPanelVisible (visible: boolean) {
+ droneControlPanelVisible.value = visible
+ }
+
+ async function flyToPoint (sn: string, body: PostFlyToPointBody) {
+ const { code } = await postFlyToPoint(sn, body)
+ if (code === 0) {
+ message.success('Fly to')
+ }
+ }
+
+ async function stopFlyToPoint (sn: string) {
+ const { code } = await deleteFlyToPoint(sn)
+ if (code === 0) {
+ message.success('Stop fly to')
+ }
+ }
+
+ async function takeoffToPoint (sn: string, body: PostTakeoffToPointBody) {
+ const { code } = await postTakeoffToPoint(sn, body)
+ if (code === 0) {
+ message.success('Take off successfully')
+ }
+ }
+
+ return {
+ droneControlPanelVisible,
+ setDroneControlPanelVisible,
+ flyToPoint,
+ stopFlyToPoint,
+ takeoffToPoint
+ }
+}
diff --git a/src/components/g-map/use-manual-control.ts b/src/components/g-map/use-manual-control.ts
new file mode 100644
index 0000000..eb178a8
--- /dev/null
+++ b/src/components/g-map/use-manual-control.ts
@@ -0,0 +1,162 @@
+import {
+ ref,
+ onUnmounted,
+ watch,
+ Ref,
+} from 'vue'
+import { message } from 'ant-design-vue'
+import {
+ DRC_METHOD,
+ DroneControlProtocol,
+} from '/@/types/drc'
+import {
+ useMqtt,
+ DeviceTopicInfo
+} from './use-mqtt'
+
+let myInterval: any
+
+export enum KeyCode {
+ KEY_W = 'KeyW',
+ KEY_A = 'KeyA',
+ KEY_S = 'KeyS',
+ KEY_D = 'KeyD',
+ KEY_Q = 'KeyQ',
+ KEY_E = 'KeyE',
+ ARROW_UP = 'ArrowUp',
+ ARROW_DOWN = 'ArrowDown',
+}
+
+export function useManualControl (deviceTopicInfo: DeviceTopicInfo, isCurrentFlightController: Ref<boolean>) {
+ const activeCodeKey = ref(null) as Ref<KeyCode | null>
+ const mqttHooks = useMqtt(deviceTopicInfo)
+
+ function handlePublish (params: DroneControlProtocol) {
+ const body = {
+ method: DRC_METHOD.DRONE_CONTROL,
+ data: params,
+ }
+ handleClearInterval()
+ myInterval = setInterval(() => {
+ window.console.log('keyCode>>>>', activeCodeKey.value, body)
+ body.data.seq = new Date().getTime()
+ mqttHooks?.publishMqtt(deviceTopicInfo.pubTopic, body, { qos: 0 })
+ }, 50)
+ }
+
+ function handleKeyup (keyCode: KeyCode) {
+ if (!deviceTopicInfo.pubTopic) {
+ message.error('请确保已经建立DRC链路')
+ return
+ }
+ const SPEED = 5 // check
+ const HEIGHT = 5 // check
+ const W_SPEED = 20 // 机头角速度
+ switch (keyCode) {
+ case 'KeyA':
+ if (activeCodeKey.value === keyCode) return
+ handlePublish({ y: -SPEED })
+ activeCodeKey.value = keyCode
+ break
+ case 'KeyW':
+ if (activeCodeKey.value === keyCode) return
+ handlePublish({ x: SPEED })
+ activeCodeKey.value = keyCode
+ break
+ case 'KeyS':
+ if (activeCodeKey.value === keyCode) return
+ handlePublish({ x: -SPEED })
+ activeCodeKey.value = keyCode
+ break
+ case 'KeyD':
+ if (activeCodeKey.value === keyCode) return
+ handlePublish({ y: SPEED })
+ activeCodeKey.value = keyCode
+ break
+ case 'ArrowUp':
+ if (activeCodeKey.value === keyCode) return
+ handlePublish({ h: HEIGHT })
+ activeCodeKey.value = keyCode
+ break
+ case 'ArrowDown':
+ if (activeCodeKey.value === keyCode) return
+ handlePublish({ h: -HEIGHT })
+ activeCodeKey.value = keyCode
+ break
+ case 'KeyQ':
+ if (activeCodeKey.value === keyCode) return
+ handlePublish({ w: -W_SPEED })
+ activeCodeKey.value = keyCode
+ break
+ case 'KeyE':
+ if (activeCodeKey.value === keyCode) return
+ handlePublish({ w: W_SPEED })
+ activeCodeKey.value = keyCode
+ break
+ default:
+ break
+ }
+ }
+
+ function handleClearInterval () {
+ clearInterval(myInterval)
+ myInterval = undefined
+ }
+
+ function resetControlState () {
+ activeCodeKey.value = null
+ handleClearInterval()
+ }
+
+ function onKeyup () {
+ resetControlState()
+ }
+
+ function onKeydown (e: KeyboardEvent) {
+ handleKeyup(e.code as KeyCode)
+ }
+
+ function startKeyboardManualControl () {
+ window.addEventListener('keydown', onKeydown)
+ window.addEventListener('keyup', onKeyup)
+ }
+
+ function closeKeyboardManualControl () {
+ resetControlState()
+ window.removeEventListener('keydown', onKeydown)
+ window.removeEventListener('keyup', onKeyup)
+ }
+
+ watch(() => isCurrentFlightController.value, (val) => {
+ if (val && deviceTopicInfo.pubTopic) {
+ startKeyboardManualControl()
+ } else {
+ closeKeyboardManualControl()
+ }
+ }, { immediate: true })
+
+ onUnmounted(() => {
+ closeKeyboardManualControl()
+ })
+
+ function handleEmergencyStop () {
+ if (!deviceTopicInfo.pubTopic) {
+ message.error('请确保已经建立DRC链路')
+ return
+ }
+ const body = {
+ method: DRC_METHOD.DRONE_EMERGENCY_STOP,
+ data: {}
+ }
+ resetControlState()
+ window.console.log('handleEmergencyStop>>>>', deviceTopicInfo.pubTopic, body)
+ mqttHooks?.publishMqtt(deviceTopicInfo.pubTopic, body, { qos: 1 })
+ }
+
+ return {
+ activeCodeKey,
+ handleKeyup,
+ handleEmergencyStop,
+ resetControlState,
+ }
+}
diff --git a/src/components/g-map/use-mqtt.ts b/src/components/g-map/use-mqtt.ts
new file mode 100644
index 0000000..c02f537
--- /dev/null
+++ b/src/components/g-map/use-mqtt.ts
@@ -0,0 +1,132 @@
+import {
+ ref,
+ reactive,
+ computed,
+ watch,
+ onUnmounted,
+} from 'vue'
+import {
+ IClientPublishOptions,
+ IPublishPacket,
+} from '/@/mqtt'
+import { useMyStore } from '/@/store'
+import {
+ DRC_METHOD,
+} from '/@/types/drc'
+import EventBus from '/@/event-bus'
+
+export interface DeviceTopicInfo{
+ sn: string
+ pubTopic: string
+ subTopic: string
+}
+
+type MessageMqtt = (topic: string, payload: Buffer, packet: IPublishPacket) => void | Promise<void>
+
+export function useMqtt (deviceTopicInfo: DeviceTopicInfo) {
+ let cacheSubscribeArr: {
+ topic: string;
+ callback?: MessageMqtt;
+ }[] = []
+
+ const store = useMyStore()
+
+ const mqttState = computed(() => {
+ return store.state.mqttState
+ })
+
+ function publishMqtt (topic: string, body: object, ots?: IClientPublishOptions) {
+ // const buffer = Buffer.from(JSON.stringify(body))
+ mqttState.value?.publishMqtt(topic, JSON.stringify(body), ots)
+ }
+
+ function subscribeMqtt (topic: string, handleMessageMqtt?: MessageMqtt) {
+ mqttState.value?.subscribeMqtt(topic)
+ const handler = handleMessageMqtt || onMessageMqtt
+ mqttState.value?.on('onMessageMqtt', handler)
+ cacheSubscribeArr.push({
+ topic,
+ callback: handler,
+ })
+ }
+
+ function onMessageMqtt (message: any) {
+ if (cacheSubscribeArr.findIndex(item => item.topic === message?.topic) !== -1) {
+ const payloadStr = new TextDecoder('utf-8').decode(message?.payload)
+ const payloadObj = JSON.parse(payloadStr)
+ switch (payloadObj?.method) {
+ case DRC_METHOD.HEART_BEAT:
+ break
+ case DRC_METHOD.DELAY_TIME_INFO_PUSH:
+ case DRC_METHOD.HSI_INFO_PUSH:
+ case DRC_METHOD.OSD_INFO_PUSH:
+ EventBus.emit('droneControlMqttInfo', payloadObj)
+ break
+ default:
+ break
+ }
+ }
+ }
+
+ function unsubscribeDrc () {
+ // 销毁已订阅事件
+ cacheSubscribeArr.forEach(item => {
+ mqttState.value?.off('onMessageMqtt', item.callback)
+ mqttState.value?.unsubscribeMqtt(item.topic)
+ })
+ cacheSubscribeArr = []
+ }
+
+ // 心跳
+ const heartBeatSeq = ref(0)
+ const state = reactive({
+ heartState: new Map<string, {
+ pingInterval: any;
+ }>(),
+ })
+
+ // 监听云控控制权
+ watch(() => deviceTopicInfo, (val, oldVal) => {
+ if (val.subTopic !== '') {
+ // 1.订阅topic
+ subscribeMqtt(deviceTopicInfo.subTopic)
+ // 2.发心跳
+ publishDrcPing(deviceTopicInfo.sn)
+ } else {
+ clearInterval(state.heartState.get(deviceTopicInfo.sn)?.pingInterval)
+ state.heartState.delete(deviceTopicInfo.sn)
+ heartBeatSeq.value = 0
+ }
+ }, { immediate: true, deep: true })
+
+ function publishDrcPing (sn: string) {
+ const body = {
+ method: DRC_METHOD.HEART_BEAT,
+ data: {
+ ts: new Date().getTime(),
+ seq: heartBeatSeq.value,
+ },
+ }
+ const pingInterval = setInterval(() => {
+ if (!mqttState.value) return
+ heartBeatSeq.value += 1
+ body.data.ts = new Date().getTime()
+ body.data.seq = heartBeatSeq.value
+ publishMqtt(deviceTopicInfo.pubTopic, body, { qos: 0 })
+ }, 1000)
+ state.heartState.set(sn, {
+ pingInterval,
+ })
+ }
+
+ onUnmounted(() => {
+ unsubscribeDrc()
+ heartBeatSeq.value = 0
+ })
+
+ return {
+ mqttState,
+ publishMqtt,
+ subscribeMqtt,
+ }
+}
diff --git a/src/components/g-map/use-payload-control.ts b/src/components/g-map/use-payload-control.ts
new file mode 100644
index 0000000..d702c00
--- /dev/null
+++ b/src/components/g-map/use-payload-control.ts
@@ -0,0 +1,120 @@
+import { message } from 'ant-design-vue'
+import {
+ postPayloadAuth,
+ postPayloadCommands,
+ PayloadCommandsEnum,
+ PostCameraModeBody,
+ PostCameraFocalLengthBody,
+ PostGimbalResetBody,
+ PostCameraAimBody,
+} from '/@/api/drone-control/payload'
+import { ControlSource } from '/@/types/device'
+
+export function usePayloadControl () {
+ function checkPayloadAuth (controlSource?: ControlSource) {
+ if (controlSource !== ControlSource.A) {
+ message.error('Get Payload Control first')
+ return false
+ }
+ return true
+ }
+
+ async function authPayload (sn: string, payloadIndx: string) {
+ const { code } = await postPayloadAuth(sn, {
+ payload_index: payloadIndx
+ })
+ if (code === 0) {
+ message.success('Get Payload Control successfully')
+ return true
+ }
+ return false
+ }
+
+ async function resetGimbal (sn: string, data: PostGimbalResetBody) {
+ const { code } = await postPayloadCommands(sn, {
+ cmd: PayloadCommandsEnum.GimbalReset,
+ data: data
+ })
+ if (code === 0) {
+ message.success('Gimbal Reset successfully')
+ }
+ }
+
+ async function switchCameraMode (sn: string, data: PostCameraModeBody) {
+ const { code } = await postPayloadCommands(sn, {
+ cmd: PayloadCommandsEnum.CameraModeSwitch,
+ data: data
+ })
+ if (code === 0) {
+ message.success('Camera Mode Switch successfully')
+ }
+ }
+
+ async function takeCameraPhoto (sn: string, payloadIndx: string) {
+ const { code } = await postPayloadCommands(sn, {
+ cmd: PayloadCommandsEnum.CameraPhotoTake,
+ data: {
+ payload_index: payloadIndx
+ }
+ })
+ if (code === 0) {
+ message.success('Take Photo successfully')
+ }
+ }
+
+ async function startCameraRecording (sn: string, payloadIndx: string) {
+ const { code } = await postPayloadCommands(sn, {
+ cmd: PayloadCommandsEnum.CameraRecordingStart,
+ data: {
+ payload_index: payloadIndx
+ }
+ })
+ if (code === 0) {
+ message.success('Start Recording successfully')
+ }
+ }
+
+ async function stopCameraRecording (sn: string, payloadIndx: string) {
+ const { code } = await postPayloadCommands(sn, {
+ cmd: PayloadCommandsEnum.CameraRecordingStop,
+ data: {
+ payload_index: payloadIndx
+ }
+ })
+ if (code === 0) {
+ message.success('Stop Recording successfully')
+ }
+ }
+
+ async function changeCameraFocalLength (sn: string, data: PostCameraFocalLengthBody) {
+ const { code } = await postPayloadCommands(sn, {
+ cmd: PayloadCommandsEnum.CameraFocalLengthSet,
+ data: data,
+ })
+ if (code === 0) {
+ message.success('Zoom successfully')
+ }
+ }
+
+ async function cameraAim (sn: string, data: PostCameraAimBody) {
+ const { code } = await postPayloadCommands(sn, {
+ cmd: PayloadCommandsEnum.CameraAim,
+ data: data,
+ })
+ if (code === 0) {
+ message.success('Zoom Aim successfully')
+ }
+ }
+
+ return {
+ checkPayloadAuth,
+ authPayload,
+ resetGimbal,
+ switchCameraMode,
+ takeCameraPhoto,
+ startCameraRecording,
+ stopCameraRecording,
+ changeCameraFocalLength,
+ cameraAim,
+ }
+}
diff --git a/src/components/task/CreatePlan.vue b/src/components/task/CreatePlan.vue
index 37f0ae7..becc1be 100644
--- a/src/components/task/CreatePlan.vue
+++ b/src/components/task/CreatePlan.vue
@@ -182,7 +182,8 @@
disabled.value = true
const createPlanBody = { ...planBody } as unknown as CreatePlan
if (planBody.select_execute_time) {
- createPlanBody.execute_time = moment(planBody.select_execute_time).valueOf()
+ createPlanBody.task_days = [moment(planBody.select_execute_time).unix()]
+ createPlanBody.task_periods = [createPlanBody.task_days]
}
createPlanBody.rth_altitude = Number(createPlanBody.rth_altitude)
if (wayline.value && wayline.value.template_types && wayline.value.template_types.length > 0) {
diff --git a/src/components/task/TaskPanel.vue b/src/components/task/TaskPanel.vue
index e7874e5..fd6a204 100644
--- a/src/components/task/TaskPanel.vue
+++ b/src/components/task/TaskPanel.vue
@@ -5,7 +5,7 @@
:pagination="paginationProp" :scroll="{ x: '100%', y: 600 }" @change="refreshData">
<!-- 执行时间 -->
<template #duration="{ record }">
- <div class="flex-row">
+ <div class="flex-row" style="white-space: pre-wrap">
<div>
<div>{{ formatTaskTime(record.begin_time) }}</div>
<div>{{ formatTaskTime(record.end_time) }}</div>
@@ -62,7 +62,7 @@
</template>
<!-- 操作 -->
<template #action="{ record }">
- <span class="action-area">
+ <div class="action-area">
<a-popconfirm
v-if="record.status === TaskStatus.Wait"
title="Are you sure you want to delete flight task?"
@@ -72,7 +72,25 @@
>
<a-button type="primary" size="small">Delete</a-button>
</a-popconfirm>
- </span>
+ <a-popconfirm
+ v-if="record.status === TaskStatus.Carrying"
+ title="Are you sure you want to suspend?"
+ ok-text="Yes"
+ cancel-text="No"
+ @confirm="onSuspendTask(record.job_id)"
+ >
+ <a-button type="primary" size="small">Suspend</a-button>
+ </a-popconfirm>
+ <a-popconfirm
+ v-if="record.status === TaskStatus.Paused"
+ title="Are you sure you want to resume?"
+ ok-text="Yes"
+ cancel-text="No"
+ @confirm="onResumeTask(record.job_id)"
+ >
+ <a-button type="primary" size="small">Resume</a-button>
+ </a-popconfirm>
+ </div>
</template>
</a-table>
</div>
@@ -84,7 +102,7 @@
import { TableState } from 'ant-design-vue/lib/table/interface'
import { onMounted } from 'vue'
import { IPage } from '/@/api/http/type'
-import { deleteTask, getWaylineJobs, Task, uploadMediaFileNow } from '/@/api/wayline'
+import { deleteTask, updateTaskStatus, UpdateTaskStatus, getWaylineJobs, Task, uploadMediaFileNow } from '/@/api/wayline'
import { useMyStore } from '/@/store'
import { ELocalStorageKey } from '/@/types/enums'
import { useFormatTask } from './use-format-task'
@@ -272,6 +290,30 @@
}
}
+// 挂起任务
+async function onSuspendTask (jobId: string) {
+ const { code } = await updateTaskStatus(workspaceId, {
+ job_id: jobId,
+ status: UpdateTaskStatus.Suspend
+ })
+ if (code === 0) {
+ message.success('Suspended successfully')
+ getPlans()
+ }
+}
+
+// 解除挂起任务
+async function onResumeTask (jobId: string) {
+ const { code } = await updateTaskStatus(workspaceId, {
+ job_id: jobId,
+ status: UpdateTaskStatus.Resume
+ })
+ if (code === 0) {
+ message.success('Resumed successfully')
+ getPlans()
+ }
+}
+
// 立即上传媒体
async function onUploadMediaFileNow (jobId: string) {
const { code } = await uploadMediaFileNow(workspaceId, jobId)
@@ -291,8 +333,13 @@
margin-top: 10px;
}
.action-area {
- color: $primary;
- cursor: pointer;
+
+ &::v-deep {
+ .ant-btn {
+ margin-right: 10px;
+ margin-bottom: 10px;
+ }
+ }
}
.circle-icon {
diff --git a/src/event-bus/index.ts b/src/event-bus/index.ts
index 72feae5..fbe0933 100644
--- a/src/event-bus/index.ts
+++ b/src/event-bus/index.ts
@@ -4,6 +4,8 @@
deviceUpgrade: any; // 设备升级
deviceLogUploadProgress: any // 设备日志上传
flightTaskWs: any // 机场任务消息
+ droneControlWs: any // 飞行指令信息
+ droneControlMqttInfo: any // drc 链路通知
};
const emitter: Emitter<Events> = mitt<Events>()
diff --git a/src/hooks/use-g-map-tsa.ts b/src/hooks/use-g-map-tsa.ts
index c36779b..f71217c 100644
--- a/src/hooks/use-g-map-tsa.ts
+++ b/src/hooks/use-g-map-tsa.ts
@@ -1,12 +1,11 @@
import store from '/@/store'
import { getRoot } from '/@/root'
-import { ELocalStorageKey } from '/@/types'
+import { ELocalStorageKey, EDeviceTypeName } from '/@/types'
import { getDeviceBySn } from '/@/api/manage'
import { message } from 'ant-design-vue'
import dockIcon from '/@/assets/icons/dock.png'
import rcIcon from '/@/assets/icons/rc.png'
import droneIcon from '/@/assets/icons/drone.png'
-import { EDeviceTypeName } from '/@/types'
export function deviceTsaUpdate () {
const root = getRoot()
diff --git a/src/mqtt/config.ts b/src/mqtt/config.ts
new file mode 100644
index 0000000..1af7df6
--- /dev/null
+++ b/src/mqtt/config.ts
@@ -0,0 +1,12 @@
+
+import {
+ IClientOptions,
+} from 'mqtt'
+
+export const OPTIONS: IClientOptions = {
+ clean: true, // true: 清除会话, false: 保留会话
+ connectTimeout: 10000, // mqtt 超时时间
+ resubscribe: true, // 断开重连后,再次订阅原订阅
+ reconnectPeriod: 10000, // 重连间隔时间: 5s
+ keepalive: 1, // 心跳间隔时间:1s
+}
diff --git a/src/mqtt/index.ts b/src/mqtt/index.ts
new file mode 100644
index 0000000..f6570df
--- /dev/null
+++ b/src/mqtt/index.ts
@@ -0,0 +1,117 @@
+import EventEmitter from 'eventemitter3'
+import {
+ OPTIONS,
+} from './config'
+import {
+ connect,
+ MqttClient,
+ IClientPublishOptions,
+ IPublishPacket,
+ Packet,
+ ISubscriptionGrant,
+ IClientOptions,
+} from 'mqtt/dist/mqtt.min'
+
+export class UranusMqtt extends EventEmitter {
+ _url: string
+ _options?: IClientOptions
+ _client: MqttClient | null
+ _hasInit: boolean
+
+ constructor (url?: string, options?: IClientOptions) {
+ super()
+ this._url = url || ''
+ this._options = options
+ this._client = null
+ this._hasInit = false
+ }
+
+ initMqtt = () => {
+ // 仅初始化一次
+ if (this._hasInit) return
+ // 建立连接
+ this._client = connect(this._url, {
+ ...OPTIONS,
+ ...this._options,
+ })
+ this._hasInit = true
+ if (this._client) {
+ this._client.on('reconnect', this._onReconnect)
+
+ // 消息监听
+ this._client.on('message', this._onMessage)
+
+ // 连接关闭
+ this._client.on('close', this._onClose)
+
+ // 连接异常
+ this._client.on('error', this._onError)
+ }
+ }
+
+ // 发布
+ publishMqtt = (topic: string, body: string | Buffer, opts?: IClientPublishOptions) => {
+ if (!this._client?.connected) {
+ this.initMqtt()
+ }
+ this._client?.publish(topic, body, opts || {}, (error?: Error, packet?: Packet) => {
+ if (error) {
+ window.console.error('mqtt publish error,', error, packet)
+ }
+ })
+ }
+
+ // 订阅
+ subscribeMqtt = (topic: string) => {
+ if (!this._client?.connected) {
+ this.initMqtt()
+ }
+ window.console.log('subscribeMqtt>>>>>', topic)
+ this._client?.subscribe(topic, (error: Error, granted: ISubscriptionGrant[]) => {
+ window.console.log('mqtt subscribe,', error, granted)
+ })
+ }
+
+ // 取消订阅
+ unsubscribeMqtt = (topic: string) => {
+ window.console.log('mqtt unsubscribeMqtt,', topic)
+ this._client?.unsubscribe(topic)
+ }
+
+ // 关闭 mqtt 客户端
+ destroyed = () => {
+ window.console.log('mqtt destroyed')
+ this._client?.end()
+ }
+
+ _onReconnect = () => {
+ if (this._client) { window.console.error('mqtt reconnect,') }
+ }
+
+ _onMessage = (topic: string, payload: Buffer, packet: IPublishPacket) => {
+ this.emit('onMessageMqtt', { topic, payload, packet })
+ }
+
+ _onClose = () => {
+ // 连接异常关闭会自动重连
+ window.console.error('mqtt close,')
+ this.emit('onStatus', {
+ status: 'close',
+ })
+ }
+
+ _onError = (error: Error) => {
+ // 连接错误会自动重连
+ window.console.error('mqtt error,', error)
+ this.emit('onStatus', {
+ status: 'error',
+ data: error,
+ })
+ }
+}
+
+export {
+ IClientOptions,
+ IPublishPacket,
+ IClientPublishOptions,
+}
diff --git a/src/pages/page-web/projects/Firmwares.vue b/src/pages/page-web/projects/Firmwares.vue
index d3e6757..54fd590 100644
--- a/src/pages/page-web/projects/Firmwares.vue
+++ b/src/pages/page-web/projects/Firmwares.vue
@@ -242,7 +242,7 @@
if (fileList.value.length === 0) {
message.error('Please select at least one file.')
}
- const uploading: string = 'uploading'
+ let uploading: string
formRef.value.validate().then(async () => {
const file: FileItem = fileList.value[0]
const fileData = new FormData()
@@ -257,6 +257,8 @@
fileData.append(key, val.toString())
}
})
+ const timestamp = new Date().getTime()
+ uploading = (file.name ?? 'uploding') + timestamp
notification.open({
key: uploading,
message: `Uploading ${moment().format()}`,
@@ -267,7 +269,7 @@
if (res.code === 0) {
notification.success({
message: `Uploaded ${moment().format()}`,
- description: `[${file.name}] file uploaded successfully.`,
+ description: `[${file.name}] file uploaded successfully. Duration: ${moment.duration(new Date().getTime() - timestamp).asSeconds()}`,
duration: null
})
getAllFirmwares(pageParam)
diff --git a/src/pages/page-web/projects/devices.vue b/src/pages/page-web/projects/devices.vue
index 768e86f..07c722d 100644
--- a/src/pages/page-web/projects/devices.vue
+++ b/src/pages/page-web/projects/devices.vue
@@ -20,7 +20,9 @@
style="margin: -5px 0"
/>
<template v-else>
- {{ text }}
+ <a-tooltip :title="text">
+ {{ text }}
+ </a-tooltip>
</template>
</div>
</template>
@@ -127,7 +129,7 @@
import { DeviceCmdExecuteInfo, DeviceCmdExecuteStatus } from '/@/types/device-cmd'
import DeviceLogUploadRecordDrawer from '/@/components/devices/device-log/DeviceLogUploadRecordDrawer.vue'
import DeviceHmsDrawer from '/@/components/devices/device-hms/DeviceHmsDrawer.vue'
-import { message } from 'ant-design-vue'
+import { message, notification } from 'ant-design-vue'
interface DeviceData {
device: Device[]
@@ -268,13 +270,18 @@
for (let i = 0; i < devices.length; i++) {
if (devices[i].device_sn === payload.sn) {
if (!payload.output) return
- const { status, progress } = payload.output
+ const { status, progress, ext } = payload.output
if (status === DeviceCmdExecuteStatus.Sent || status === DeviceCmdExecuteStatus.InProgress) { // 升级中
+ const rate = ext?.rate ? (ext.rate / 1024).toFixed(2) + 'kb/s' : ''
devices[i].firmware_status = DeviceFirmwareStatusEnum.DuringUpgrade
- devices[i].firmware_progress = progress?.percent || 0
+ devices[i].firmware_progress = (progress?.percent || 0) + '% ' + rate
} else { // 终态:成功,失败,超时
if (status === DeviceCmdExecuteStatus.Failed || status === DeviceCmdExecuteStatus.Timeout) {
- message.error(`设备(${payload.sn}) 升级失败`)
+ notification.error({
+ message: `(${payload.sn}) Upgrade failed`,
+ description: `Error Code: ${payload.result}`,
+ duration: null
+ })
}
// 拉取列表
getDevices(current.value[0], true)
diff --git a/src/pages/page-web/projects/dock.vue b/src/pages/page-web/projects/dock.vue
index 6e4febf..e31c88c 100644
--- a/src/pages/page-web/projects/dock.vue
+++ b/src/pages/page-web/projects/dock.vue
@@ -58,7 +58,7 @@
getDocks()
const key = setInterval(() => {
const data = document.getElementById('data')?.lastElementChild as HTMLDivElement
- if (body.total === 0 || Math.ceil(body.total / body.page_size) <= body.page || scorllHeight.value <= data?.clientHeight + data?.offsetTop) {
+ if (body.total === 0 || Math.ceil(body.total / body.page_size) <= body.page || scorllHeight.value + 50 <= data?.clientHeight + data?.offsetTop) {
clearInterval(key)
return
}
diff --git a/src/pages/page-web/projects/livestream.vue b/src/pages/page-web/projects/livestream.vue
index ad9a9f9..f2c3414 100644
--- a/src/pages/page-web/projects/livestream.vue
+++ b/src/pages/page-web/projects/livestream.vue
@@ -31,8 +31,8 @@
import { getRoot } from '/@/root'
import { ERouterName } from '/@/types'
const root = getRoot()
-const routeName = ref<string>()
-const showLive = ref<boolean>(false)
+const routeName = ref<string>('LiveOthers')
+const showLive = ref<boolean>(root.$route.name === ERouterName.LIVING)
const options = [
{ key: 0, label: 'Agora Live', path: '/' + ERouterName.LIVESTREAM + '/' + ERouterName.LIVING, routeName: 'LiveAgora' },
@@ -40,6 +40,7 @@
]
const selectLivestream = (route: string) => {
+ showLive.value = root.$route.name === ERouterName.LIVING
routeName.value = route
}
diff --git a/src/pages/page-web/projects/tsa.vue b/src/pages/page-web/projects/tsa.vue
index 3668f68..9ab2216 100644
--- a/src/pages/page-web/projects/tsa.vue
+++ b/src/pages/page-web/projects/tsa.vue
@@ -20,15 +20,15 @@
<div style="float: left; padding: 0px 5px 8px 8px; width: 88%">
<div style="width: 80%; height: 30px; line-height: 30px; font-size: 16px;">
<a-tooltip :title="`${dock.gateway.callsign} - ${dock.callsign ?? 'No Drone'}`">
- <span class="text-hidden" style="max-width: 200px;">{{ dock.gateway.callsign }} - {{ dock.callsign ?? 'No Drone' }}</span>
+ <div class="text-hidden" style="max-width: 200px;">{{ dock.gateway.callsign }} - {{ dock.callsign ?? 'No Drone' }}</div>
</a-tooltip>
</div>
<div class="mt5 flex-align-center flex-row flex-justify-between" style="background: #595959;">
<div class="flex-align-center flex-row">
<span class="ml5 mr5"><RobotOutlined /></span>
- <span class="font-bold text-hidden" style="max-width: 80px;" :style="dockInfo[dock.gateway.sn] && dockInfo[dock.gateway.sn].basic_osd?.mode_code !== EDockModeCode.Disconnected ? 'color: #00ee8b' : 'color: red;'">
+ <div class="font-bold text-hidden" style="max-width: 80px;" :style="dockInfo[dock.gateway.sn] && dockInfo[dock.gateway.sn].basic_osd?.mode_code !== EDockModeCode.Disconnected ? 'color: #00ee8b' : 'color: red;'">
{{ dockInfo[dock.gateway.sn] ? EDockModeCode[dockInfo[dock.gateway.sn].basic_osd?.mode_code] : EDockModeCode[EDockModeCode.Disconnected] }}
- </span>
+ </div>
</div>
<div class="mr5 flex-align-center flex-row" style="width: 85px; margin-right: 0; height: 18px;">
<div v-if="hmsInfo[dock.gateway.sn]" class="flex-align-center flex-row">
@@ -75,11 +75,11 @@
</div>
</div>
<div class="mt5 flex-align-center flex-row flex-justify-between" style="background: #595959;">
- <div>
+ <div class="flex-row">
<span class="ml5 mr5"><RocketOutlined /></span>
- <span class="font-bold" :style="deviceInfo[dock.sn] && deviceInfo[dock.sn].mode_code !== EModeCode.Disconnected ? 'color: #00ee8b' : 'color: red;'">
+ <div class="font-bold text-hidden" style="max-width: 80px" :style="deviceInfo[dock.sn] && deviceInfo[dock.sn].mode_code !== EModeCode.Disconnected ? 'color: #00ee8b' : 'color: red;'">
{{ deviceInfo[dock.sn] ? EModeCode[deviceInfo[dock.sn].mode_code] : EModeCode[EModeCode.Disconnected] }}
- </span>
+ </div>
</div>
<div class="mr5 flex-align-center flex-row" style="width: 85px; margin-right: 0; height: 18px;">
<div v-if="hmsInfo[dock.sn]" class="flex-align-center flex-row">
@@ -173,11 +173,11 @@
</div>
</div>
<div class="flex-row flex-justify-center flex-align-center" style="height: 40px;">
- <div style="height: 20px; background: #595959; width: 94%;" >
+ <div class="flex-row" style="height: 20px; background: #595959; width: 94%;" >
<span class="mr5"><a-image style="margin-left: 2px; margin-top: -2px; height: 20px; width: 20px;" :src="rc" /></span>
<a-tooltip>
<template #title>{{ device.gateway.model }} - {{ device.gateway.callsign }} </template>
- <span class="text-hidden" style="max-width: 200px;">{{ device.gateway.model }} - {{ device.gateway.callsign }}</span>
+ <div class="text-hidden" style="max-width: 200px;">{{ device.gateway.model }} - {{ device.gateway.callsign }}</div>
</a-tooltip>
</div>
</div>
@@ -194,10 +194,9 @@
import { EDeviceTypeName, ELocalStorageKey } from '/@/types'
import noData from '/@/assets/icons/no-data.png'
import rc from '/@/assets/icons/rc.png'
-import { DeviceStatus, EModeCode, OSDVisible, EDockModeCode, DeviceOsd } from '/@/types/device'
+import { OnlineDevice, EModeCode, OSDVisible, EDockModeCode, DeviceOsd } from '/@/types/device'
import { useMyStore } from '/@/store'
import { getDeviceTopo, getUnreadDeviceHms, updateDeviceHms } from '/@/api/manage'
-import { message } from 'ant-design-vue'
import { RocketOutlined, EyeInvisibleOutlined, EyeOutlined, RobotOutlined, DoubleRightOutlined } from '@ant-design/icons-vue'
import { EHmsLevel } from '/@/types/enums'
@@ -207,22 +206,6 @@
const osdVisible = ref({} as OSDVisible)
const hmsVisible = new Map<string, boolean>()
const scorllHeight = ref()
-
-interface OnlineDevice {
- model: string,
- callsign: string,
- sn: string,
- mode: number,
- gateway: {
- model: string,
- callsign: string,
- sn: string,
- domain: string,
- },
- payload: {
- model: string
- }[]
-}
const onlineDevices = reactive({
data: [] as OnlineDevice[]
@@ -286,7 +269,12 @@
}
child?.payloads_list.forEach((payload: any) => {
device.payload.push({
- model: payload.payload_name
+ index: payload.index,
+ model: payload.model,
+ payload_name: payload.payload_name,
+ payload_sn: payload.payload_sn,
+ control_source: payload.control_source,
+ payload_index: payload.payload_index
})
})
if (EDeviceTypeName.Dock === gateway.domain) {
@@ -316,6 +304,7 @@
osdVisible.value.gateway_sn = device.gateway.sn
osdVisible.value.is_dock = isDock
osdVisible.value.gateway_callsign = device.gateway.callsign
+ osdVisible.value.payloads = device.payload
}
store.commit('SET_OSD_VISIBLE_INFO', osdVisible)
}
diff --git a/src/pages/page-web/projects/workspace.vue b/src/pages/page-web/projects/workspace.vue
index 4d965f0..d302112 100644
--- a/src/pages/page-web/projects/workspace.vue
+++ b/src/pages/page-web/projects/workspace.vue
@@ -100,6 +100,15 @@
})
break
}
+ case EBizCode.ControlSourceChange:
+ case EBizCode.FlyToPointProgress:
+ case EBizCode.TakeoffToPointProgress:
+ case EBizCode.JoystickInvalidNotify:
+ case EBizCode.DrcStatusNotify:
+ {
+ EventBus.emit('droneControlWs', payload)
+ break
+ }
default:
break
}
diff --git a/src/shims-mqtt.d.ts b/src/shims-mqtt.d.ts
new file mode 100644
index 0000000..45ab849
--- /dev/null
+++ b/src/shims-mqtt.d.ts
@@ -0,0 +1,4 @@
+declare module 'mqtt/dist/mqtt.min' {
+ import MQTT from 'mqtt'
+ export = MQTT
+}
diff --git a/src/store/index.ts b/src/store/index.ts
index d7f4673..6dbf7ba 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -67,13 +67,14 @@
currentSn: '',
currentType: -1
},
- osdVisible: {
+ osdVisible: { // osd 显示设备相关信息
sn: '',
callsign: '',
model: '',
visible: false,
gateway_sn: '',
is_dock: false,
+ payloads: null
} as OSDVisible,
waylineInfo: {
@@ -86,7 +87,9 @@
},
// 机场指令执行状态信息
devicesCmdExecuteInfo: {
- } as DevicesCmdExecuteInfo
+ } as DevicesCmdExecuteInfo,
+ mqttState: null as any, // mqtt 实例
+ clientId: '', // mqtt 连接 唯一客户端id
})
export type RootStateType = ReturnType<typeof initStateFunc>
@@ -117,15 +120,18 @@
state.deviceState.currentSn = info.sn
state.deviceState.currentType = EDeviceTypeName.Dock
const dock = state.deviceState.dockInfo[info.sn]
+ if (info.host.mode_code !== undefined) {
+ dock.basic_osd = info.host
+ return
+ }
if (info.host.sdr) {
dock.link_osd = info.host
return
}
- if (info.host.job_number) {
+ if (info.host.job_number !== undefined) {
dock.work_osd = info.host
return
}
- dock.basic_osd = info.host
},
SET_DRAW_VISIBLE_INFO (state, bool) {
state.drawVisible = bool
@@ -182,7 +188,13 @@
} else {
state.devicesCmdExecuteInfo[info.sn] = [info]
}
- }
+ },
+ SET_MQTT_STATE (state, mqttState) {
+ state.mqttState = mqttState
+ },
+ SET_CLIENT_ID (state, clientId) {
+ state.clientId = clientId
+ },
}
const actions: ActionTree<RootStateType, RootStateType> = {
diff --git a/src/types/device-cmd.ts b/src/types/device-cmd.ts
index d8804cd..c1e545d 100644
--- a/src/types/device-cmd.ts
+++ b/src/types/device-cmd.ts
@@ -39,6 +39,16 @@
loading: boolean // 按钮loading
disabled?: boolean // 按钮disabled
}
+export const noDebugCmdList: DeviceCmdItem[] = [
+ {
+ label: 'Return Home',
+ status: '--',
+ operateText: 'Return Home',
+ cmdKey: DeviceCmd.ReturnHome,
+ func: 'returnHome',
+ loading: false,
+ },
+]
// 机场指令
export const cmdList: DeviceCmdItem[] = [
@@ -88,14 +98,6 @@
cmdKey: DeviceCmd.ChargeOpen,
oppositeCmdKey: DeviceCmd.ChargeClose,
func: 'chargeStatus',
- loading: false,
- },
- {
- label: '一键返航',
- status: '--',
- operateText: '返航',
- cmdKey: DeviceCmd.ReturnHome,
- func: 'returnHome',
loading: false,
},
{
@@ -281,6 +283,9 @@
percent: number,
step_key: string,
step_result: number
+ },
+ ext?: {
+ rate?: number
}
}
result: number,
diff --git a/src/types/device.ts b/src/types/device.ts
index f23f27e..fdbeb67 100644
--- a/src/types/device.ts
+++ b/src/types/device.ts
@@ -1,6 +1,8 @@
import { commonColor } from '/@/utils/color'
import { NightLightsStateEnum, DistanceLimitStatus, ObstacleAvoidance } from './device-setting'
import { AlarmModeEnum, BatteryStoreModeEnum, DroneBatteryStateEnum, FourGLinkStateEnum, SdrLinkStateEnum, LinkWorkModeEnum } from './airport-tsa'
+import { CameraMode } from '/@/types/live-stream'
+
export interface DeviceValue {
key: string; // 'domain-type-subtype'
domain: string; // 表示一个领域,作为一个命名空间,暂时分 飞机类-0, 负载类-1,RC类-2,机场类-3 4种
@@ -20,10 +22,6 @@
export enum DRONE_TYPE {
M30 = 67,
M300 = 60,
- Phantom4 = 11,
- Phantom4Pro = 18,
- Phantom4RTK = 59,
- Phantom4Advanced = 27,
Mavic3EnterpriseAdvanced= 77,
}
@@ -76,10 +74,6 @@
M3T: `${DOMAIN.DRONE}-${DRONE_TYPE.Mavic3EnterpriseAdvanced}-${DEVICE_SUB_TYPE.ONE}`,
M300: `${DOMAIN.DRONE}-${DRONE_TYPE.M300}-${DEVICE_SUB_TYPE.ZERO}`,
- Phantom4: `${DOMAIN.DRONE}-${DRONE_TYPE.Phantom4}-${DEVICE_SUB_TYPE.ZERO}`,
- Phantom4Pro: `${DOMAIN.DRONE}-${DRONE_TYPE.Phantom4Pro}-${DEVICE_SUB_TYPE.ZERO}`,
- Phantom4RTK: `${DOMAIN.DRONE}-${DRONE_TYPE.Phantom4RTK}-${DEVICE_SUB_TYPE.ZERO}`,
- Phantom4Advanced: `${DOMAIN.DRONE}-${DRONE_TYPE.Phantom4Advanced}-${DEVICE_SUB_TYPE.ZERO}`,
FPV: `${DOMAIN.PAYLOAD}-${PAYLOAD_TYPE.FPV}-${DEVICE_SUB_TYPE.ZERO}`,
H20: `${DOMAIN.PAYLOAD}-${PAYLOAD_TYPE.H20}-${DEVICE_SUB_TYPE.ZERO}`,
@@ -113,10 +107,6 @@
[DEVICE_MODEL_KEY.M3T]: 'Mavic 3T',
// [DEVICE_MODEL_KEY.M3M]: 'Mavic 3M',
[DEVICE_MODEL_KEY.M300]: 'M300 RTK',
- [DEVICE_MODEL_KEY.Phantom4]: 'Phantom 4',
- [DEVICE_MODEL_KEY.Phantom4Pro]: 'Phantom 4 Pro',
- [DEVICE_MODEL_KEY.Phantom4RTK]: 'Phantom 4 RTK',
- [DEVICE_MODEL_KEY.Phantom4Advanced]: 'Phantom 4 Advanced',
// payload
[DEVICE_MODEL_KEY.FPV]: 'FPV',
@@ -141,6 +131,36 @@
// dock
[DEVICE_MODEL_KEY.Dock]: 'Dock',
+}
+
+// 控制权
+export enum ControlSource {
+ A = 'A',
+ B = 'B'
+}
+
+export interface PayloadInfo {
+ index: number,
+ model: string,
+ control_source?: ControlSource,
+ payload_sn?: string,
+ payload_index?: string,
+ payload_name?: string,
+}
+
+// 设备信息
+export interface OnlineDevice {
+ model: string,
+ callsign: string,
+ sn: string,
+ mode: number,
+ gateway: {
+ model: string,
+ callsign: string,
+ sn: string,
+ domain: string,
+ },
+ payload: PayloadInfo[]
}
// 固件升级类型
@@ -184,7 +204,7 @@
children?: Device[],
domain: number,
type: number,
- firmware_progress?: number, // 升级进度
+ firmware_progress?: string, // 升级进度
}
export interface DeviceStatus {
@@ -207,6 +227,7 @@
is_dock: boolean,
gateway_sn: string,
gateway_callsign: string,
+ payloads: null | PayloadInfo [],
}
export interface GatewayOsd {
@@ -215,6 +236,24 @@
longitude: number,
latitude: number,
}
+
+export interface OsdCameraLiveview {
+ bottom: number,
+ left: number,
+ right: number,
+ top: number,
+}
+export interface DeviceOsdCamera {
+ camera_mode: CameraMode,
+ payload_index: string,
+ photo_state: number,
+ record_time: number,
+ recording_state: number,
+ remain_photo_num: number,
+ remain_record_duration: number,
+ liveview_world_region: OsdCameraLiveview
+}
+
export interface DeviceOsd {
longitude: number,
latitude: number,
@@ -242,6 +281,7 @@
height_limit?: number;// 限高设置
distance_limit_status?: DistanceLimitStatus;// 限远开关
obstacle_avoidance?: ObstacleAvoidance;// 飞行器避障开关设置
+ cameras?: DeviceOsdCamera[]
}
export enum NetworkStateTypeEnum {
@@ -263,16 +303,16 @@
}
export enum DroneInDockEnum {
- INSIDE, OUTSIDE
+ OUTSIDE, INSIDE
}
export interface DockBasicOsd {
- network_state: {
+ network_state?: {
type: NetworkStateTypeEnum,
quality: number,
rate: number,
},
- drone_charge_state: {
+ drone_charge_state?: {
state: number,
capacity_percent: number,
},
@@ -285,7 +325,7 @@
latitude: number,
longitude: number,
height: number,
- alternate_land_point: {
+ alternate_land_point?: {
latitude: number,
longitude: number,
height: number,
@@ -293,14 +333,14 @@
is_configured: number
}
first_power_on: number,
- positionState: {
+ positionState?: {
gps_number: number,
is_fixed: number,
rtk_number: number,
is_calibration: number,
quality: number,
},
- storage: {
+ storage?: {
total: number,
used: number,
},
@@ -308,25 +348,32 @@
cover_state: number,
supplement_light_state: number,
emergency_stop_state: number,
- air_conditioner: {
+ air_conditioner?: {
air_conditioner_state: number,
switch_time: number,
}
battery_store_mode?: BatteryStoreModeEnum; // 电池保养(存储)模式
alarm_state?: AlarmModeEnum; // 机场声光报警状态
putter_state: number,
- sub_device: {
+ sub_device?: {
device_sn?: string,
device_model_key?: string,
device_online_status: number,
device_paired: number,
},
+ // live_capacity?: LiveCapacity; // 直播能力
+ // live_status?: Array<LiveStatus>; // 直播状态
}
-
+export enum DrcStateEnum {
+ DISCONNECT = 0,
+ CONNECTING = 1,
+ CONNECTED = 2
+}
export interface DockLinkOsd {
+ drc_state: DrcStateEnum,
flighttask_prepare_capacity: number,
flighttask_step_code: number,
- media_file_detail: {
+ media_file_detail?: {
remain_upload: number
},
sdr: {
@@ -334,7 +381,7 @@
down_quality: string,
frequency_band: number,
},
- wireless_link?:{
+ wireless_link?:{ // 图传链路<会包括4G和sdr信息
dongle_number: number, // dongle 数量
['4g_link_state']: FourGLinkStateEnum, // 4g_link_state
sdr_link_state: SdrLinkStateEnum, // sdr链路连接状态
@@ -359,13 +406,13 @@
job_number: number,
acc_time: number,
activation_time: number,
- maintain_status: {
+ maintain_status?: {
maintain_status_array: MaintainStatus[]
}
electric_supply_voltage: number,
working_voltage: string,
working_current: string,
- backup_battery: {
+ backup_battery?: {
voltage: number,
temperature: number,
switch: number,
@@ -379,7 +426,7 @@
export interface DockOsd {
basic_osd: DockBasicOsd,
link_osd: DockLinkOsd,
- work_osd: DockWorkOsd
+ work_osd: DockWorkOsd
}
export enum EModeCode {
@@ -460,7 +507,7 @@
}
// TODO: 设备拓扑管理优化
-// 设备信息
+// 设备osd信息
export interface DeviceInfoType {
gateway: GatewayOsd, // 遥控器
dock: DockOsd, // 机场
diff --git a/src/types/drc.ts b/src/types/drc.ts
new file mode 100644
index 0000000..e31b55f
--- /dev/null
+++ b/src/types/drc.ts
@@ -0,0 +1,71 @@
+export enum DRC_METHOD {
+ HEART_BEAT = 'heart_beat',
+ DRONE_CONTROL = 'drone_control', // 飞行控制-虚拟摇杆
+ DRONE_EMERGENCY_STOP = 'drone_emergency_stop', // 急停
+ OSD_INFO_PUSH = 'osd_info_push', // 高频osd信息上报
+ HSI_INFO_PUSH = 'hsi_info_push', // 避障信息上报
+ DELAY_TIME_INFO_PUSH = 'delay_info_push', // 图传链路延时信息上报
+}
+
+// 手动控制
+export interface DroneControlProtocol {
+ x?: number; // 水平方向速度,正值为A指令 负值为D指令 单位:m/s
+ y?: number; // 前进后退方向速度,正值为W指令 负值为S指令 单位:m/s
+ h?: number;// 上下高度值,正值为上升指令 负值为下降指令 单位:m
+ w?: number; // 机头角速度,正值为顺时针,负值为逆时针 单位:degree/s (web端暂无此设计)
+ step_x?: number; // 水平方向步长
+ step_y?: number; // 前后方向步长
+ step_h?: number; // 高度方向步长
+ step_w?: number; // 机头转向步长
+ seq?: number; // 从0计时
+ freq?: number; // 指令发送频率
+ delay_time?: number; // 指令从发送到设备端接收可容忍的时间 发送频率+链路传输时长
+}
+
+// 低延时osd
+export interface DRCOsdInfo {
+ attitude_head: number;// 飞机姿态head角,单位:度
+ latitude: number;// 飞机经纬度
+ longitude: number;
+ altitude: number;
+ speed_x: number;
+ speed_y: number;
+ speed_z: number;
+ gimbal_pitch: number;// 云台pitch角
+ gimbal_roll: number;// 云台roll角
+ gimbal_yaw: number;// 云台yaw角
+}
+
+// 态势感知-HSI
+export interface DRCHsiInfo {
+ up_distance: number;// 上方的障碍物距离,单位:mm
+ down_distance: number;// 下方的障碍物距离,单位:mm
+ around_distances: number[]; // 水平方向观察点,分布在[0,360)区间,表示障碍物与飞机距离,单位为mm。 0对应机头方向正前方,顺时针分布,例如0度为机头正前方,90度为飞机正右方
+ up_enable: boolean; // 上视避障开关状态,true:已开启 false:已关闭
+ up_work: boolean; // 上视避障工作状态,true:正常工作 false:异常或离线
+ down_enable: boolean; // 下视避障开关状态,true:已开启 false:已关闭
+ down_work: boolean; // 下视避障工作状态,true:正常工作 false:异常或离线
+ left_enable: boolean; // 左视避障开关状态,true:已开启 false:已关闭
+ left_work: boolean; // 左视避障工作状态,true:正常工作 false:异常或离线
+ right_enable: boolean; // 右视避障开关状态,true:已开启 false:已关闭
+ right_work: boolean; // 右视避障工作状态,true:正常工作 false:异常或离线
+ front_enable: boolean; // 前视避障开关状态,true:已开启 false:已关闭
+ front_work: boolean; // 前视避障工作状态,true:正常工作 false:异常或离线
+ back_enable: boolean; // 后视避障开关状态,true:已开启 false:已关闭
+ back_work: boolean; // 后视避障工作状态,true:正常工作 false:异常或离线
+ vertical_enable: boolean; // 垂直方向综合开关状态,当本协议中上、下视开关状态均为true时,输出true:已开启,否则输出false:已关闭
+ vertical_work: boolean; // 垂直方向避障工作状态,当本协议中上、下视工作均为true时,输出true:正常工作,否则输出false:异常或离线
+ horizontal_enable: boolean; // 水平方向综合开关状态,当本协议中前、后、左、右、开关状态均为true时,输出true:已开启,否则输出false:已关闭
+ horizontal_work: boolean; // 水平方向避障工作综合状态,当本协议中前、后、左、右视工作均为true时,输出true:正常工作,否则输出false:异常或离线
+}
+
+export interface LiveViewDelayItem {
+ video_id: string;
+ liveview_delay_time: number;
+}
+
+// 链路时延信息
+export interface DRCDelayTimeInfo {
+ sdr_cmd_delay: number; // sdr链路命令延时,单位:ms
+ liveview_delay_list: LiveViewDelayItem[];
+}
diff --git a/src/types/drone-control.ts b/src/types/drone-control.ts
new file mode 100644
index 0000000..4c16619
--- /dev/null
+++ b/src/types/drone-control.ts
@@ -0,0 +1,68 @@
+import { ControlSource } from './device'
+import { LostControlActionInCommandFLight, WaylineLostControlActionInCommandFlight } from '/@/api/drone-control/drone'
+
+export enum ControlSourceChangeType {
+ Flight = 1,
+ Payload = 2,
+}
+
+// 控制权变化消息
+export interface ControlSourceChangeInfo {
+ sn: string,
+ type: ControlSourceChangeType,
+ control_source: ControlSource
+}
+
+// 飞向目标点结果
+export interface FlyToPointMessage {
+ sn: string,
+ result: number,
+ message: string,
+}
+
+// 一键起飞结果
+export interface TakeoffToPointMessage {
+ sn: string,
+ result: number,
+ message: string,
+}
+
+// 设备端退出drc模式
+export interface DrcModeExitNotifyMessage {
+ sn: string,
+ result: number,
+ message: string,
+}
+
+// 飞行控制模式状态
+export interface DrcStatusNotifyMessage {
+ sn: string,
+ result: number,
+ message: string,
+}
+
+export const WaylineLostControlActionInCommandFlightOptions = [
+ { label: 'Continue', value: WaylineLostControlActionInCommandFlight.CONTINUE },
+ { label: 'Execute Lost Action', value: WaylineLostControlActionInCommandFlight.EXEC_LOST_ACTION }
+]
+
+export const LostControlActionInCommandFLightOptions = [
+ { label: 'Return Home', value: LostControlActionInCommandFLight.RETURN_HOME },
+ { label: 'Hover', value: LostControlActionInCommandFLight.HOVER },
+ { label: 'Landing', value: LostControlActionInCommandFLight.Land }
+]
+
+// 云台重置模式
+export enum GimbalResetMode {
+ Recenter = 0,
+ Down = 1,
+ RecenterGimbalPan = 2,
+ PitchDown = 3,
+}
+
+export const GimbalResetModeOptions = [
+ { label: 'Gimbal Recenter', value: GimbalResetMode.Recenter },
+ { label: 'Gimbal down', value: GimbalResetMode.Down },
+ { label: 'Recenter Gimbal Pan', value: GimbalResetMode.RecenterGimbalPan },
+ { label: 'Gimbal Pitch Down', value: GimbalResetMode.PitchDown }
+]
diff --git a/src/types/enums.ts b/src/types/enums.ts
index 9dc6365..43248fa 100644
--- a/src/types/enums.ts
+++ b/src/types/enums.ts
@@ -115,7 +115,14 @@
DeviceUpgrade = 'ota_progress', // 设备升级
// 设备日志
- DeviceLogUploadProgress = 'fileupload_progress' // 设备日志上传上传
+ DeviceLogUploadProgress = 'fileupload_progress', // 设备日志上传
+
+ // 飞行指令消息
+ ControlSourceChange = 'control_source_change', // 控制权更新
+ FlyToPointProgress = 'fly_to_point_progress', // 飞向目标点
+ TakeoffToPointProgress = 'takeoff_to_point_progress', // 一键起飞
+ JoystickInvalidNotify = 'joystick_invalid_notify', // 设备端退出drc模式
+ DrcStatusNotify = 'drc_status_notify', // 飞行控制模式状态
}
export enum EDeviceTypeName {
diff --git a/src/types/live-stream.ts b/src/types/live-stream.ts
index 2103910..4a02799 100644
--- a/src/types/live-stream.ts
+++ b/src/types/live-stream.ts
@@ -53,3 +53,74 @@
RTSP = 'RTSP',
GB28181 = 'GB28181'
}
+
+export enum CameraMode {
+ Photo = 0, // 拍照
+ Video = 1, // 录像
+}
+
+// 镜头类型
+export enum VideoType {
+ NORMAL = 'normal',
+ WIDE = 'wide',
+ ZOOM = 'zoom',
+ IR = 'ir'
+}
+
+// 镜头类型
+export enum CameraType {
+ WIDE = 'wide',
+ ZOOM = 'zoom',
+ IR = 'ir'
+}
+
+export const CameraTypeOptions = [
+ { label: CameraType.WIDE, value: CameraType.WIDE },
+ { label: CameraType.ZOOM, value: CameraType.ZOOM },
+ { label: CameraType.IR, value: CameraType.IR },
+]
+
+export const ZoomCameraTypeOptions = [
+ { label: CameraType.ZOOM, value: CameraType.ZOOM },
+ { label: CameraType.IR, value: CameraType.IR },
+]
+
+export interface VideoListItem {
+ video_index: string;
+ video_type: VideoType;
+ switchable_video_types?: Array<VideoType>;
+}
+
+export interface CameraListItem {
+ available_video_number: number;
+ camera_index: string;
+ camera_name: string;
+ coexist_video_number_max: number;
+ video_list: VideoListItem[];
+ // 自定义
+ switchCamera?: boolean;
+ content?: string;
+ // 该camera由哪个控上报的
+ camera_carrier_sns?: string[];
+}
+
+export interface DeviceListItem {
+ sn: string;
+ available_video_number: number;
+ coexist_video_number_max: number;
+ camera_list: CameraListItem[];
+}
+
+// export interface LiveCapacity {
+// available_video_number: number;
+// coexist_video_number_max: number;
+// device_list: DeviceListItem[];
+// }
+
+// export interface LiveStatus {
+// live_time: number; // 直播时间 该路码流已推流时间 unit: s
+// live_trendline: number; // 直播带宽的使用状态 代表直播性能趋势,0-4表示overuse,其中,数值越小,表示overuse程度越大,5表示normal状态,6~10表示underuse,其中,数值越大,表示有更多比例的带宽未能充分利用
+// video_id: string; // 直播码流标识符 某路在推视频码流的标识符,格式为 #{uav_sn}/#{camera_id}/#{video_index}
+// video_quality: number; // 直播码流的质量 0: 自动, 1: 流畅, 2: 高清, 3: 超清
+// error_status?: number; // 设备端当前状态,是错误码,需要匹配到文案上
+// }
diff --git a/src/types/task.ts b/src/types/task.ts
index cd5d97a..a37fe73 100644
--- a/src/types/task.ts
+++ b/src/types/task.ts
@@ -37,6 +37,7 @@
Success = 3, // 完成
CanCel = 4, // 取消
Fail = 5, // 失败
+ Paused = 6, // 暂停
}
export const TaskStatusMap = {
@@ -45,6 +46,8 @@
[TaskStatus.Success]: 'Task completed',
[TaskStatus.CanCel]: 'Task canceled',
[TaskStatus.Fail]: 'Task failed',
+ [TaskStatus.Paused]: 'Paused',
+
}
export const TaskStatusColor = {
@@ -53,6 +56,7 @@
[TaskStatus.Success]: commonColor.NORMAL,
[TaskStatus.CanCel]: commonColor.FAIL,
[TaskStatus.Fail]: commonColor.FAIL,
+ [TaskStatus.Paused]: commonColor.BLUE,
}
// 任务执行 ws 消息状态
@@ -93,7 +97,7 @@
[TaskProgressStatus.Failed]: TaskStatus.Fail,
[TaskProgressStatus.Canceled]: TaskStatus.CanCel,
[TaskProgressStatus.Timeout]: TaskStatus.Fail,
- [TaskProgressStatus.Paused]: TaskStatus.Wait,
+ [TaskProgressStatus.Paused]: TaskStatus.Paused,
}
// 根据媒体文件上传进度信息,前端自己判断出的状态
diff --git a/yarn.lock b/yarn.lock
index 9a9d2c5..5d27955 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -819,6 +819,11 @@
"mixin-deep" "^1.2.0"
"pascalcase" "^0.1.1"
+"base64-js@^1.3.1":
+ "integrity" "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+ "resolved" "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz"
+ "version" "1.5.1"
+
"big-integer@^1.6.17":
"integrity" "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg=="
"resolved" "https://registry.npmmirror.com/big-integer/download/big-integer-1.6.51.tgz"
@@ -841,6 +846,15 @@
dependencies:
"buffers" "~0.1.1"
"chainsaw" "~0.1.0"
+
+"bl@^4.0.2":
+ "integrity" "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="
+ "resolved" "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz"
+ "version" "4.1.0"
+ dependencies:
+ "buffer" "^5.5.0"
+ "inherits" "^2.0.4"
+ "readable-stream" "^3.4.0"
"bluebird@^3.5.0":
"integrity" "sha1-nyKcFb4nJFT/qXOs4NvueaGww28="
@@ -899,10 +913,23 @@
"node-releases" "^2.0.1"
"picocolors" "^1.0.0"
+"buffer-from@^1.0.0":
+ "integrity" "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
+ "resolved" "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz"
+ "version" "1.1.2"
+
"buffer-indexof-polyfill@~1.0.0":
"integrity" "sha1-0nMhNcWZnGSyd/z5savjSYJUcpw="
"resolved" "https://registry.npm.taobao.org/buffer-indexof-polyfill/download/buffer-indexof-polyfill-1.0.2.tgz"
"version" "1.0.2"
+
+"buffer@^5.5.0":
+ "integrity" "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="
+ "resolved" "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz"
+ "version" "5.7.1"
+ dependencies:
+ "base64-js" "^1.3.1"
+ "ieee754" "^1.1.13"
"buffers@~0.1.1":
"integrity" "sha1-skV5w77U1tOWru5tmorn9Ugqt7s="
@@ -1079,6 +1106,14 @@
"resolved" "https://registry.npmmirror.com/commander/download/commander-7.2.0.tgz"
"version" "7.2.0"
+"commist@^1.0.0":
+ "integrity" "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg=="
+ "resolved" "https://registry.npmmirror.com/commist/-/commist-1.1.0.tgz"
+ "version" "1.1.0"
+ dependencies:
+ "leven" "^2.1.0"
+ "minimist" "^1.1.0"
+
"component-emitter@^1.2.1":
"integrity" "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A="
"resolved" "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz"
@@ -1093,6 +1128,16 @@
"integrity" "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
"resolved" "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz"
"version" "0.0.1"
+
+"concat-stream@^2.0.0":
+ "integrity" "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A=="
+ "resolved" "https://registry.npmmirror.com/concat-stream/-/concat-stream-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "buffer-from" "^1.0.0"
+ "inherits" "^2.0.3"
+ "readable-stream" "^3.0.2"
+ "typedarray" "^0.0.6"
"constant-case@^3.0.4":
"integrity" "sha1-O4Sprq9M8x7EXmv13pG9+wWJ+vE="
@@ -1216,7 +1261,7 @@
dependencies:
"ms" "^2.1.1"
-"debug@^4.0.1", "debug@^4.1.0", "debug@^4.1.1", "debug@^4.3.2", "debug@^4.3.3":
+"debug@^4.0.1", "debug@^4.1.0", "debug@^4.1.1", "debug@^4.3.1", "debug@^4.3.2", "debug@^4.3.3":
"integrity" "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q=="
"resolved" "https://registry.npmmirror.com/debug/download/debug-4.3.3.tgz"
"version" "4.3.3"
@@ -1366,6 +1411,16 @@
dependencies:
"readable-stream" "^2.0.2"
+"duplexify@^4.1.1":
+ "integrity" "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw=="
+ "resolved" "https://registry.npmmirror.com/duplexify/-/duplexify-4.1.2.tgz"
+ "version" "4.1.2"
+ dependencies:
+ "end-of-stream" "^1.4.1"
+ "inherits" "^2.0.3"
+ "readable-stream" "^3.1.1"
+ "stream-shift" "^1.0.0"
+
"electron-to-chromium@^1.4.17":
"integrity" "sha512-PO3kEfcxPrti/4STbXvCkNIF4fgWvCKl2508e6UI7KomCDffpIfeBZLXsh5DK/XGsjUw3kwq6WEsi0MJTlGAdg=="
"resolved" "https://registry.npmmirror.com/electron-to-chromium/download/electron-to-chromium-1.4.43.tgz"
@@ -1380,6 +1435,13 @@
"integrity" "sha1-VXBmIEatKeLpFucariYKvf9Pang="
"resolved" "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz"
"version" "3.0.0"
+
+"end-of-stream@^1.1.0", "end-of-stream@^1.4.1":
+ "integrity" "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="
+ "resolved" "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz"
+ "version" "1.4.4"
+ dependencies:
+ "once" "^1.4.0"
"enquirer@^2.3.5":
"integrity" "sha1-Kn/l3WNKHkElqXXsmU/1RW3Dc00="
@@ -1728,6 +1790,11 @@
"resolved" "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz"
"version" "1.8.1"
+"eventemitter3@^5.0.0":
+ "integrity" "sha512-riuVbElZZNXLeLEoprfNYoDSwTBRR44X3mnhdI1YcnENpWTCsTTVZ2zFuqQcpoyqPQIUXdiPEU0ECAq0KQRaHg=="
+ "resolved" "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.0.tgz"
+ "version" "5.0.0"
+
"expand-brackets@^2.1.4":
"integrity" "sha1-t3c14xXOMPa27/D4OwQVGiJEliI="
"resolved" "https://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz"
@@ -1950,7 +2017,7 @@
dependencies:
"is-glob" "^4.0.1"
-"glob@^7.1.3":
+"glob@^7.1.3", "glob@^7.1.6":
"integrity" "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q=="
"resolved" "https://registry.npmmirror.com/glob/download/glob-7.2.0.tgz"
"version" "7.2.0"
@@ -2081,6 +2148,14 @@
"capital-case" "^1.0.4"
"tslib" "^2.0.3"
+"help-me@^3.0.0":
+ "integrity" "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ=="
+ "resolved" "https://registry.npmmirror.com/help-me/-/help-me-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "glob" "^7.1.6"
+ "readable-stream" "^3.6.0"
+
"htmlparser2@^3.8.3":
"integrity" "sha1-vWedw/WYl7ajS7EHSchVu1OpOS8="
"resolved" "https://registry.npmmirror.com/htmlparser2/download/htmlparser2-3.10.1.tgz?cache=0&sync_timestamp=1636640933377&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-3.10.1.tgz"
@@ -2092,6 +2167,11 @@
"entities" "^1.1.1"
"inherits" "^2.0.1"
"readable-stream" "^3.1.1"
+
+"ieee754@^1.1.13":
+ "integrity" "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+ "resolved" "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz"
+ "version" "1.2.1"
"ignore@^4.0.6":
"integrity" "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
@@ -2134,7 +2214,7 @@
"once" "^1.3.0"
"wrappy" "1"
-"inherits@^2.0.1", "inherits@^2.0.3", "inherits@~2.0.0", "inherits@~2.0.3", "inherits@2":
+"inherits@^2.0.1", "inherits@^2.0.3", "inherits@^2.0.4", "inherits@~2.0.0", "inherits@~2.0.3", "inherits@2":
"integrity" "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w="
"resolved" "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz"
"version" "2.0.4"
@@ -2402,6 +2482,11 @@
"resolved" "https://registry.npmmirror.com/js-base64/download/js-base64-2.6.4.tgz"
"version" "2.6.4"
+"js-sdsl@4.3.0":
+ "integrity" "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ=="
+ "resolved" "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.3.0.tgz"
+ "version" "4.3.0"
+
"js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0":
"integrity" "sha1-GSA/tZmR35jjoocFDUZHzerzJJk="
"resolved" "https://registry.nlark.com/js-tokens/download/js-tokens-4.0.0.tgz?cache=0&sync_timestamp=1619345098261&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fjs-tokens%2Fdownload%2Fjs-tokens-4.0.0.tgz"
@@ -2493,6 +2578,11 @@
"integrity" "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0="
"resolved" "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz"
"version" "6.0.3"
+
+"leven@^2.1.0":
+ "integrity" "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA=="
+ "resolved" "https://registry.npmmirror.com/leven/-/leven-2.1.0.tgz"
+ "version" "2.1.0"
"levn@^0.4.1":
"integrity" "sha1-rkViwAdHO5MqYgDUAyaN0v/8at4="
@@ -2635,7 +2725,7 @@
dependencies:
"brace-expansion" "^1.1.7"
-"minimist@^1.2.0", "minimist@^1.2.5":
+"minimist@^1.1.0", "minimist@^1.2.0", "minimist@^1.2.5":
"integrity" "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI="
"resolved" "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz"
"version" "1.2.5"
@@ -2664,6 +2754,38 @@
"integrity" "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
"resolved" "https://registry.npmmirror.com/moment/download/moment-2.29.1.tgz"
"version" "2.29.1"
+
+"mqtt-packet@^6.8.0":
+ "integrity" "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA=="
+ "resolved" "https://registry.npmmirror.com/mqtt-packet/-/mqtt-packet-6.10.0.tgz"
+ "version" "6.10.0"
+ dependencies:
+ "bl" "^4.0.2"
+ "debug" "^4.1.1"
+ "process-nextick-args" "^2.0.1"
+
+"mqtt@^4.3.7":
+ "integrity" "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw=="
+ "resolved" "https://registry.npmmirror.com/mqtt/-/mqtt-4.3.7.tgz"
+ "version" "4.3.7"
+ dependencies:
+ "commist" "^1.0.0"
+ "concat-stream" "^2.0.0"
+ "debug" "^4.1.1"
+ "duplexify" "^4.1.1"
+ "help-me" "^3.0.0"
+ "inherits" "^2.0.3"
+ "lru-cache" "^6.0.0"
+ "minimist" "^1.2.5"
+ "mqtt-packet" "^6.8.0"
+ "number-allocator" "^1.0.9"
+ "pump" "^3.0.0"
+ "readable-stream" "^3.6.0"
+ "reinterval" "^1.1.0"
+ "rfdc" "^1.3.0"
+ "split2" "^3.1.0"
+ "ws" "^7.5.5"
+ "xtend" "^4.0.2"
"ms@^2.1.1", "ms@2.1.2":
"integrity" "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
@@ -2737,6 +2859,14 @@
dependencies:
"boolbase" "^1.0.0"
+"number-allocator@^1.0.9":
+ "integrity" "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA=="
+ "resolved" "https://registry.npmmirror.com/number-allocator/-/number-allocator-1.0.14.tgz"
+ "version" "1.0.14"
+ dependencies:
+ "debug" "^4.3.1"
+ "js-sdsl" "4.3.0"
+
"object-assign@^4", "object-assign@^4.1.0":
"integrity" "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
"resolved" "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz"
@@ -2799,7 +2929,7 @@
"resolved" "https://registry.npm.taobao.org/omit.js/download/omit.js-2.0.2.tgz"
"version" "2.0.2"
-"once@^1.3.0":
+"once@^1.3.0", "once@^1.3.1", "once@^1.4.0":
"integrity" "sha1-WDsap3WWHUsROsF9nFC6753Xa9E="
"resolved" "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz"
"version" "1.4.0"
@@ -2980,7 +3110,7 @@
"resolved" "https://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.2.1.tgz"
"version" "1.2.1"
-"process-nextick-args@~2.0.0":
+"process-nextick-args@^2.0.1", "process-nextick-args@~2.0.0":
"integrity" "sha1-eCDZsWEgzFXKmud5JoCufbptf+I="
"resolved" "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz"
"version" "2.0.1"
@@ -2989,6 +3119,14 @@
"integrity" "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
"resolved" "https://registry.npmmirror.com/progress/download/progress-2.0.3.tgz"
"version" "2.0.3"
+
+"pump@^3.0.0":
+ "integrity" "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww=="
+ "resolved" "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "end-of-stream" "^1.1.0"
+ "once" "^1.3.1"
"punycode@^2.1.0":
"integrity" "sha1-tYsBCsQMIsVldhbI0sLALHv0eew="
@@ -3031,7 +3169,7 @@
"string_decoder" "~1.1.1"
"util-deprecate" "~1.0.1"
-"readable-stream@^3.1.1":
+"readable-stream@^3.0.0", "readable-stream@^3.0.2", "readable-stream@^3.1.1", "readable-stream@^3.4.0", "readable-stream@^3.6.0":
"integrity" "sha1-M3u9o63AcGvT4CRCaihtS0sskZg="
"resolved" "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz"
"version" "3.6.0"
@@ -3083,6 +3221,11 @@
"resolved" "https://registry.nlark.com/regexpp/download/regexpp-3.2.0.tgz"
"version" "3.2.0"
+"reinterval@^1.1.0":
+ "integrity" "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ=="
+ "resolved" "https://registry.npmmirror.com/reinterval/-/reinterval-1.1.0.tgz"
+ "version" "1.1.0"
+
"repeat-element@^1.1.2":
"integrity" "sha1-vmgVIIR6tYx1aKx1+/rSjtQtOek="
"resolved" "https://registry.nlark.com/repeat-element/download/repeat-element-1.1.4.tgz"
@@ -3131,6 +3274,11 @@
"integrity" "sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY="
"resolved" "https://registry.npm.taobao.org/reusify/download/reusify-1.0.4.tgz"
"version" "1.0.4"
+
+"rfdc@^1.3.0":
+ "integrity" "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
+ "resolved" "https://registry.npmmirror.com/rfdc/-/rfdc-1.3.0.tgz"
+ "version" "1.3.0"
"rimraf@^3.0.2":
"integrity" "sha1-8aVAK6YiCtUswSgrrBrjqkn9Bho="
@@ -3375,6 +3523,13 @@
dependencies:
"extend-shallow" "^3.0.0"
+"split2@^3.1.0":
+ "integrity" "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg=="
+ "resolved" "https://registry.npmmirror.com/split2/-/split2-3.2.2.tgz"
+ "version" "3.2.2"
+ dependencies:
+ "readable-stream" "^3.0.0"
+
"sprintf-js@~1.0.2":
"integrity" "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
"resolved" "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz"
@@ -3392,6 +3547,11 @@
dependencies:
"define-property" "^0.2.5"
"object-copy" "^0.1.0"
+
+"stream-shift@^1.0.0":
+ "integrity" "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
+ "resolved" "https://registry.npmmirror.com/stream-shift/-/stream-shift-1.0.1.tgz"
+ "version" "1.0.1"
"strict-uri-encode@^1.0.0":
"integrity" "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
@@ -3635,6 +3795,11 @@
"integrity" "sha1-G/IH9LKPkVg2ZstfvTJ4hzAc1fQ="
"resolved" "https://registry.npmmirror.com/type-fest/download/type-fest-0.20.2.tgz"
"version" "0.20.2"
+
+"typedarray@^0.0.6":
+ "integrity" "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
+ "resolved" "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz"
+ "version" "0.0.6"
"typescript@^4.5.4", "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta":
"integrity" "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg=="
@@ -3933,6 +4098,16 @@
"resolved" "https://registry.nlark.com/wrappy/download/wrappy-1.0.2.tgz?cache=0&sync_timestamp=1619133505879&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwrappy%2Fdownload%2Fwrappy-1.0.2.tgz"
"version" "1.0.2"
+"ws@^7.5.5":
+ "integrity" "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q=="
+ "resolved" "https://registry.npmmirror.com/ws/-/ws-7.5.9.tgz"
+ "version" "7.5.9"
+
+"xtend@^4.0.2":
+ "integrity" "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
+ "resolved" "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz"
+ "version" "4.0.2"
+
"yallist@^4.0.0":
"integrity" "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI="
"resolved" "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz"
--
Gitblit v1.9.3