GMap.vue 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263
  1. <template>
  2. <div class="g-map-wrapper">
  3. <!-- 地图区域 -->
  4. <div id="g-container" :style="{ width: '100%', height: '100%' }" />
  5. <!-- 绘制面板 -->
  6. <div class="g-action-panel" :style="{ right: drawVisible ? '316px' : '16px' }">
  7. <div :class="state.currentType === 'pin' ? 'g-action-item selection' : 'g-action-item'"
  8. @click="draw('pin', true)">
  9. <a><a-image :src="pin" :preview="false" /></a>
  10. </div>
  11. <div :class="state.currentType === 'polyline' ? 'g-action-item selection' : 'g-action-item'"
  12. @click="draw('polyline', true)">
  13. <a>
  14. <LineOutlined :rotate="135" class="fz20" />
  15. </a>
  16. </div>
  17. <div :class="state.currentType === 'polygon' && !state.isFlightArea ? 'g-action-item selection' : 'g-action-item'"
  18. @click="draw('polygon', true)">
  19. <a>
  20. <BorderOutlined class="fz18" />
  21. </a>
  22. </div>
  23. <!-- <FlightAreaActionIcon class="g-action-item mt10" :class="{'selection': mouseMode && state.isFlightArea}" @select-action="selectFlightAreaAction" @click="selectFlightAreaAction"/> -->
  24. <div v-if="mouseMode" class="g-action-item" @click="draw('off', false)">
  25. <a style="color: red;">
  26. <CloseOutlined />
  27. </a>
  28. </div>
  29. </div>
  30. <!-- 地图类型切换控件 -->
  31. <div class="g-mapType" :style="{ right: drawVisible ? '316px' : '16px' }">
  32. <img :src="planeSrc" v-if="state.mapType === 0" @click="onClickSwitchMapType" />
  33. <img :src="satelliteSrc" v-else @click="onClickSwitchMapType" />
  34. </div>
  35. <!-- 最下方信息区域 -->
  36. <div class="g-info">
  37. <AimOutlined style="margin-right: 10px;" />
  38. <div>
  39. WGS 84
  40. </div>
  41. </div>
  42. <!-- 飞机OSD -->
  43. <div v-if="osdVisible.visible && !osdVisible.is_dock" v-drag-window class="osd-panel fz12">
  44. <div class="pl5 pr5 flex-align-center flex-row flex-justify-between"
  45. style="border-bottom: 1px solid #515151; height: 18%;">
  46. <div class="drag-title">
  47. <span>{{ osdVisible.callsign }}</span>
  48. </div>
  49. <a class="fz16" style="color: white;" @click="() => osdVisible.visible = false">
  50. <CloseOutlined />
  51. </a>
  52. </div>
  53. <div style="height: 82%;">
  54. <div class="osd">
  55. <a-row>
  56. <a-col span="4">
  57. <a-tooltip :title="osdVisible.model">
  58. <div style="width: 90%;" class="flex-column flex-align-center flex-justify-center">
  59. <span><a-image :src="M30" :preview="false" /></span>
  60. <span>{{ osdVisible.model }}</span>
  61. </div>
  62. </a-tooltip>
  63. </a-col>
  64. <a-col span="20">
  65. <span
  66. :style="deviceInfo.device.mode_code === EModeCode.Disconnected ? 'color: red; font-weight: 700;' : 'color: rgb(25,190,107)'">
  67. {{ EModeCode[deviceInfo.device.mode_code] }}
  68. </span>
  69. <span>
  70. 飞行状态
  71. </span>
  72. <div class="openLiveButton" @click="state.deviceLiveStatus = true" v-if="!state.deviceLiveStatus">
  73. 开启直播
  74. </div>
  75. <div class="openLiveButton" @click="state.deviceLiveStatus = false" v-else>
  76. 关闭直播
  77. </div>
  78. </a-col>
  79. </a-row>
  80. <DeviceLive :sn="osdVisible.sn" v-if="state.deviceLiveStatus" />
  81. <a-row>
  82. <a-col span="6">
  83. <a-tooltip title="GPS卫星数">
  84. <span>
  85. GPS
  86. <WifiOutlined />
  87. </span>
  88. <span class="ml10">{{ deviceInfo.device.position_state.gps_number }}</span>
  89. </a-tooltip>
  90. </a-col>
  91. <a-col span="6">
  92. <a-tooltip title="RTK">
  93. <span>
  94. RTK
  95. </span>
  96. <span class="ml10">{{ deviceInfo.device.position_state.rtk_number }}</span>
  97. </a-tooltip>
  98. </a-col>
  99. <a-col span="6">
  100. <a-tooltip title="电量">
  101. <span>电量</span>
  102. <span class="ml10">
  103. {{ deviceInfo.device.battery.capacity_percent + '%' }}
  104. </span>
  105. </a-tooltip>
  106. </a-col>
  107. <a-col span="6">
  108. <a-tooltip title="风向速度">
  109. <span>W.S</span>
  110. <span class="ml10">{{ deviceInfo.device.wind_speed === str ? str : (deviceInfo.device.wind_speed /
  111. 10).toFixed(2) + ' m/s' }}</span>
  112. </a-tooltip>
  113. </a-col>
  114. </a-row>
  115. <a-row>
  116. <a-col span="6">
  117. <a-tooltip title="海拔高度">
  118. <span>ASL</span>
  119. <span class="ml10">
  120. {{ deviceInfo.device.height === str ? str : deviceInfo.device.height.toFixed(2) + ' m' }}
  121. </span>
  122. </a-tooltip>
  123. </a-col>
  124. <a-col span="6">
  125. <a-tooltip title="离地高度">
  126. <span>ALT</span>
  127. <span class="ml10">
  128. {{ deviceInfo.device.elevation === str ? str : deviceInfo.device.elevation.toFixed(2) + ' m' }}
  129. </span>
  130. </a-tooltip>
  131. </a-col>
  132. <a-col span="6">
  133. <a-tooltip title="水平速度">
  134. <span>H.S</span>
  135. <span class="ml10">
  136. {{ deviceInfo.device.horizontal_speed === str ? str :
  137. deviceInfo.device.horizontal_speed.toFixed(2) + ' m/s' }}
  138. </span>
  139. </a-tooltip>
  140. </a-col>
  141. <a-col span="6">
  142. <a-tooltip title="当前高度">
  143. <span>H</span>
  144. <span class="ml10">
  145. {{ deviceInfo.device.home_distance === str ? str : deviceInfo.device.home_distance.toFixed(2) + ' m'
  146. }}
  147. </span>
  148. </a-tooltip>
  149. </a-col>
  150. </a-row>
  151. </div>
  152. </div>
  153. <div class="battery-slide" v-if="deviceInfo.device.battery.remain_flight_time !== 0">
  154. <div style="background: #535759;" class="width-100"></div>
  155. <div class="capacity-percent" :style="{ width: deviceInfo.device.battery.capacity_percent + '%' }"></div>
  156. <div class="return-home" :style="{ width: deviceInfo.device.battery.return_home_power + '%' }"></div>
  157. <div class="landing" :style="{ width: deviceInfo.device.battery.landing_power + '%' }"></div>
  158. <div class="white-point" :style="{ left: deviceInfo.device.battery.landing_power + '%' }"></div>
  159. <div class="battery" :style="{ left: deviceInfo.device.battery.capacity_percent + '%' }">
  160. {{ Math.floor(deviceInfo.device.battery.remain_flight_time / 60) }}:
  161. {{ 10 > (deviceInfo.device.battery.remain_flight_time % 60) ? '0' :
  162. '' }}{{ deviceInfo.device.battery.remain_flight_time % 60 }}
  163. </div>
  164. </div>
  165. </div>
  166. <!-- 机场OSD -->
  167. <div v-if="osdVisible.visible && osdVisible.is_dock" v-drag-window class="osd-panel fz12">
  168. <div class="drag-title fz16 pl5 pr5 flex-align-center flex-row flex-justify-between"
  169. style="border-bottom: 1px solid #515151; height: 10%;">
  170. <span>{{ osdVisible.gateway_callsign }}</span>
  171. </div>
  172. <span><a style="color: white; position: absolute; top: 5px; right: 5px;"
  173. @click="() => osdVisible.visible = false">
  174. <CloseOutlined />
  175. </a></span>
  176. <!-- 机场 -->
  177. <div class="flex-display" style="border-bottom: 1px solid #515151;">
  178. <div class="flex-column flex-align-stretch flex-justify-center" style="width: 60px; background: #2d2d2d;">
  179. <a-tooltip :title="osdVisible.model">
  180. <div class="flex-column flex-align-center flex-justify-center" style="width: 90%;">
  181. <span>
  182. <RobotFilled style="font-size: 48px;" />
  183. </span>
  184. <span class="mt10">Dock</span>
  185. </div>
  186. </a-tooltip>
  187. </div>
  188. <div class="osd flex-1" style="flex: 1">
  189. <a-row>
  190. <a-col span="16"
  191. :style="deviceInfo.dock.basic_osd?.mode_code === EDockModeCode.Disconnected ? 'color: red; font-weight: 700;' : 'color: rgb(25,190,107)'">
  192. {{ EDockModeCode[deviceInfo.dock.basic_osd?.mode_code] }}</a-col>
  193. </a-row>
  194. <a-row>
  195. <a-col span="12">
  196. <a-tooltip title="Accumulated Running Time">
  197. <span>
  198. <HistoryOutlined />
  199. </span>
  200. <span class="ml10">
  201. <span v-if="deviceInfo.dock.work_osd?.acc_time >= 2592000"> {{
  202. Math.floor(deviceInfo.dock.work_osd?.acc_time / 2592000) }}m </span>
  203. <span v-if="(deviceInfo.dock.work_osd?.acc_time % 2592000) >= 86400"> {{
  204. Math.floor((deviceInfo.dock.work_osd?.acc_time % 2592000) / 86400) }}d </span>
  205. <span v-if="(deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400) >= 3600"> {{
  206. Math.floor((deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400) / 3600) }}h </span>
  207. <span v-if="(deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400 % 3600) >= 60"> {{
  208. Math.floor((deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400 % 3600) / 60) }}min </span>
  209. <span>{{ Math.floor(deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400 % 3600 % 60) }} s</span>
  210. </span>
  211. </a-tooltip>
  212. </a-col>
  213. <a-col span="12">
  214. <a-tooltip title="Activation time">
  215. <span>
  216. <FieldTimeOutlined />
  217. </span>
  218. <span class="ml10">{{ new Date((deviceInfo.dock.work_osd?.activation_time ?? 0) * 1000).toLocaleString()
  219. }}
  220. </span>
  221. </a-tooltip>
  222. </a-col>
  223. </a-row>
  224. <a-row>
  225. <a-col span="6">
  226. <a-tooltip title="Network State">
  227. <span :style="qualityStyle">
  228. <span v-if="deviceInfo.dock.basic_osd?.network_state?.type === NetworkStateTypeEnum.FOUR_G">
  229. <SignalFilled />
  230. </span>
  231. <span v-else>
  232. <GlobalOutlined />
  233. </span>
  234. </span>
  235. <span class="ml10">{{ deviceInfo.dock.basic_osd?.network_state?.rate }} kb/s</span>
  236. </a-tooltip>
  237. </a-col>
  238. <a-col span="6">
  239. <a-tooltip title="The total number of times the dock has performed missions.">
  240. <span>
  241. <CarryOutOutlined />
  242. </span>
  243. <span class="ml10">{{ deviceInfo.dock.work_osd?.job_number }} </span>
  244. </a-tooltip>
  245. </a-col>
  246. <a-col span="6">
  247. <a-tooltip title="Media File Remain Upload">
  248. <span>
  249. <CloudUploadOutlined class="fz14" />
  250. </span>
  251. <span class="ml10">{{ deviceInfo.dock.link_osd?.media_file_detail?.remain_upload }}</span>
  252. </a-tooltip>
  253. </a-col>
  254. <a-col span="6">
  255. <a-tooltip>
  256. <template #title>
  257. <p>total: {{ deviceInfo.dock.basic_osd?.storage?.total }}</p>
  258. <p>used: {{ deviceInfo.dock.basic_osd?.storage?.used }}</p>
  259. </template>
  260. <span>
  261. <FolderOpenOutlined />
  262. </span>
  263. <span class="ml10" v-if="deviceInfo.dock.basic_osd?.storage?.total > 0">
  264. <a-progress type="circle" :width="20"
  265. :percent="deviceInfo.dock.basic_osd?.storage?.used * 100 / deviceInfo.dock.basic_osd?.storage?.total"
  266. :strokeWidth="20" :showInfo="false"
  267. :strokeColor="deviceInfo.dock.basic_osd?.storage?.used * 100 / deviceInfo.dock.basic_osd?.storage?.total > 80 ? 'red' : '#00ee8b'" />
  268. </span>
  269. </a-tooltip>
  270. </a-col>
  271. </a-row>
  272. <a-row>
  273. <a-col span="6">
  274. <a-tooltip title="Wind Speed">
  275. <span>W.S</span>
  276. <span class="ml10">{{ (deviceInfo.dock.basic_osd?.wind_speed ?? str) + ' m/s' }}</span>
  277. </a-tooltip>
  278. </a-col>
  279. <a-col span="6">
  280. <a-tooltip title="Rainfall">
  281. <span>🌧</span>
  282. <span class="ml10">{{ RainfallEnum[deviceInfo.dock.basic_osd?.rainfall] }}</span>
  283. </a-tooltip>
  284. </a-col>
  285. <a-col span="6">
  286. <a-tooltip title="Environment Temperature">
  287. <span>°C</span>
  288. <span class="ml10">{{ deviceInfo.dock.basic_osd?.environment_temperature }}</span>
  289. </a-tooltip>
  290. </a-col>
  291. <a-col span="6">
  292. <a-tooltip title="Dock Temperature">
  293. <span>°C</span>
  294. <span class="ml10">{{ deviceInfo.dock.basic_osd?.temperature }}</span>
  295. </a-tooltip>
  296. </a-col>
  297. </a-row>
  298. <a-row>
  299. <a-col span="6">
  300. <a-tooltip title="Dock Humidity">
  301. <span>💦</span>
  302. <span class="ml10">{{ deviceInfo.dock.basic_osd?.humidity }}</span>
  303. </a-tooltip>
  304. </a-col>
  305. <a-col span="6">
  306. <a-tooltip title="Working Voltage">
  307. <span
  308. style="border: 1px solid; border-radius: 50%; width: 18px; height: 18px; line-height: 16px; text-align: center; float: left;">V</span>
  309. <span class="ml10">{{ (deviceInfo.dock.work_osd?.working_voltage ?? str) + ' mV' }}</span>
  310. </a-tooltip>
  311. </a-col>
  312. <a-col span="6">
  313. <a-tooltip title="Working Current">
  314. <span
  315. style="border: 1px solid; border-radius: 50%; width: 18px; height: 18px; line-height: 15px; text-align: center; float: left;">A</span>
  316. <span class="ml10">{{ (deviceInfo.dock.work_osd?.working_current ?? str) + ' mA' }}</span>
  317. </a-tooltip>
  318. </a-col>
  319. <a-col span="6">
  320. <a-tooltip title="Drone in dock">
  321. <span>
  322. <RocketOutlined />
  323. </span>
  324. <span class="ml10">{{ deviceInfo.dock.basic_osd?.drone_in_dock }}</span>
  325. </a-tooltip>
  326. </a-col>
  327. </a-row>
  328. <a-row class="p5">
  329. <a-col span="24">
  330. <a-button type="primary" :disabled="dockControlPanelVisible" size="small"
  331. @click="setDockControlPanelVisible(true)">
  332. Actions
  333. </a-button>
  334. </a-col>
  335. </a-row>
  336. <!-- 机场控制面板 -->
  337. <DockControlPanel v-if="dockControlPanelVisible" :sn="osdVisible.gateway_sn" :deviceInfo="deviceInfo"
  338. @close-control-panel="onCloseControlPanel">
  339. </DockControlPanel>
  340. </div>
  341. </div>
  342. <!-- 飞机-->
  343. <div class="flex-display">
  344. <div class="flex-column flex-align-stretch flex-justify-center" style="width: 60px; background: #2d2d2d;">
  345. <a-tooltip :title="osdVisible.model">
  346. <div style="width: 90%;" class="flex-column flex-align-center flex-justify-center">
  347. <span><a-image :src="M30" :preview="false" /></span>
  348. <span>M30</span>
  349. </div>
  350. </a-tooltip>
  351. </div>
  352. <div class="osd flex-1">
  353. <a-row>
  354. <a-col span="16"
  355. :style="!deviceInfo.device || deviceInfo.device?.mode_code === EModeCode.Disconnected ? 'color: red; font-weight: 700;' : 'color: rgb(25,190,107)'">
  356. {{ !deviceInfo.device ? EModeCode[EModeCode.Disconnected] : EModeCode[deviceInfo.device?.mode_code] }}
  357. </a-col>
  358. </a-row>
  359. <a-row>
  360. <a-col span="6">
  361. <a-tooltip title="Upward Quality">
  362. <span>
  363. <SignalFilled />
  364. <ArrowUpOutlined style="font-size: 9px; vertical-align: top;" />
  365. </span>
  366. <span class="ml10">{{ deviceInfo.dock.link_osd?.sdr?.up_quality }}</span>
  367. </a-tooltip>
  368. </a-col>
  369. <a-col span="6">
  370. <a-tooltip title="Downward Quality">
  371. <span>
  372. <SignalFilled />
  373. <ArrowDownOutlined style="font-size: 9px; vertical-align: top;" />
  374. </span>
  375. <span class="ml10">{{ deviceInfo.dock.link_osd?.sdr?.down_quality }}</span>
  376. </a-tooltip>
  377. </a-col>
  378. <a-col span="6">
  379. <a-tooltip title="Drone Battery Level">
  380. <span>
  381. <ThunderboltOutlined class="fz14" />
  382. </span>
  383. <span class="ml10">{{ deviceInfo.device && deviceInfo.device.battery.capacity_percent !== str ?
  384. deviceInfo.device?.battery.capacity_percent + ' %' : str }}</span>
  385. </a-tooltip>
  386. </a-col>
  387. <a-col span="6">
  388. <a-tooltip>
  389. <template #title>
  390. <p>total: {{ deviceInfo.device?.storage?.total }}</p>
  391. <p>used: {{ deviceInfo.device?.storage?.used }}</p>
  392. </template>
  393. <span>
  394. <FolderOpenOutlined />
  395. </span>
  396. <span class="ml10" v-if="deviceInfo.device?.storage?.total > 0">
  397. <a-progress type="circle" :width="20"
  398. :percent="deviceInfo.device?.storage?.used * 100 / deviceInfo.device?.storage?.total"
  399. :strokeWidth="20" :showInfo="false"
  400. :strokeColor="deviceInfo.device?.storage?.used * 100 / deviceInfo.device?.storage?.total > 80 ? 'red' : '#00ee8b'" />
  401. </span>
  402. </a-tooltip>
  403. </a-col>
  404. </a-row>
  405. <a-row>
  406. <a-tooltip title="RTK Fixed">
  407. <a-col span="6" class="flex-row flex-align-center flex-justify-start">
  408. <span>Fixed</span>
  409. <span class="ml10 circle"
  410. :style="deviceInfo.device?.position_state.is_fixed === 1 ? 'backgroud: rgb(25,190,107);' : ' background: red;'"></span>
  411. </a-col>
  412. </a-tooltip>
  413. <a-col span="6">
  414. <a-tooltip title="GPS">
  415. <span>GPS</span>
  416. <span class="ml10">{{ deviceInfo.device ? deviceInfo.device.position_state.gps_number : str }}</span>
  417. </a-tooltip>
  418. </a-col>
  419. <a-col span="6">
  420. <a-tooltip title="RTK">
  421. <span>
  422. <TrademarkOutlined class="fz14" />
  423. </span>
  424. <span class="ml10">{{ deviceInfo.device ? deviceInfo.device.position_state.rtk_number : str }}</span>
  425. </a-tooltip>
  426. </a-col>
  427. </a-row>
  428. <a-row>
  429. <a-col span="6">
  430. <a-tooltip title="Flight Mode">
  431. <span>
  432. <ControlOutlined class="fz16" />
  433. </span>
  434. <span class="ml10">{{ deviceInfo.device ? EGear[deviceInfo.device?.gear] : str }}</span>
  435. </a-tooltip>
  436. </a-col>
  437. <a-col span="6">
  438. <a-tooltip title="Altitude above sea level">
  439. <span>ASL</span>
  440. <span class="ml10">{{ !deviceInfo.device || deviceInfo.device.height === str ? str :
  441. deviceInfo.device?.height.toFixed(2) + ' m' }}</span>
  442. </a-tooltip>
  443. </a-col>
  444. <a-col span="6">
  445. <a-tooltip title="Altitude above takeoff level">
  446. <span>ALT</span>
  447. <span class="ml10">{{ !deviceInfo.device || deviceInfo.device.elevation === str ? str :
  448. deviceInfo.device?.elevation.toFixed(2) + ' m' }}</span>
  449. </a-tooltip>
  450. </a-col>
  451. <a-col span="6">
  452. <a-tooltip title="Distance to Home Point">
  453. <span
  454. style="border: 1px solid; border-radius: 50%; width: 18px; height: 18px; line-height: 15px; text-align: center; display: block; float: left;">H</span>
  455. <span class="ml10">{{ !deviceInfo.device || deviceInfo.device.home_distance === str ? str :
  456. deviceInfo.device?.home_distance.toFixed(2) + ' m' }}</span>
  457. </a-tooltip>
  458. </a-col>
  459. </a-row>
  460. <a-row>
  461. <a-col span="6">
  462. <a-tooltip title="Horizontal Speed">
  463. <span>H.S</span>
  464. <span class="ml10">{{ !deviceInfo.device || deviceInfo.device?.horizontal_speed === str ? str :
  465. deviceInfo.device?.horizontal_speed.toFixed(2) + ' m/s' }}</span>
  466. </a-tooltip>
  467. </a-col>
  468. <a-col span="6">
  469. <a-tooltip title="Vertical Speed">
  470. <span>V.S</span>
  471. <span class="ml10">{{ !deviceInfo.device || deviceInfo.device.vertical_speed === str ? str :
  472. deviceInfo.device?.vertical_speed.toFixed(2) + ' m/s' }}</span>
  473. </a-tooltip>
  474. </a-col>
  475. <a-col span="6">
  476. <a-tooltip title="Wind Speed">
  477. <span>W.S</span>
  478. <span class="ml10">{{ !deviceInfo.device || deviceInfo.device.wind_speed === str ? str :
  479. (deviceInfo.device?.wind_speed / 10).toFixed(2) + ' m/s' }}</span>
  480. </a-tooltip>
  481. </a-col>
  482. </a-row>
  483. </div>
  484. </div>
  485. <div class="battery-slide" v-if="deviceInfo.device && deviceInfo.device.battery.remain_flight_time !== 0"
  486. style="border: 1px solid red">
  487. <div style="background: #535759;" class="width-100"></div>
  488. <div class="capacity-percent" :style="{ width: deviceInfo.device.battery.capacity_percent + '%' }"></div>
  489. <div class="return-home" :style="{ width: deviceInfo.device.battery.return_home_power + '%' }"></div>
  490. <div class="landing" :style="{ width: deviceInfo.device.battery.landing_power + '%' }"></div>
  491. <div class="white-point" :style="{ left: deviceInfo.device.battery.landing_power + '%' }"></div>
  492. <div class="battery" :style="{ left: deviceInfo.device.battery.capacity_percent + '%' }">
  493. {{ Math.floor(deviceInfo.device.battery.remain_flight_time / 60) }}:
  494. {{ 10 > (deviceInfo.device.battery.remain_flight_time % 60) ? '0' :
  495. '' }}{{ deviceInfo.device.battery.remain_flight_time % 60 }}
  496. </div>
  497. </div>
  498. <!-- 飞行指令 -->
  499. <DroneControlPanel :sn="osdVisible.gateway_sn" :deviceInfo="deviceInfo" :payloads="osdVisible.payloads">
  500. </DroneControlPanel>
  501. </div>
  502. <!-- liveview -->
  503. <div class="liveview" v-if="livestreamOthersVisible" v-drag-window>
  504. <div style="height: 40px; width: 100%" class="drag-title"></div>
  505. <a style="position: absolute; right: 10px; top: 10px; font-size: 16px; color: white;"
  506. @click="closeLivestreamOthers">
  507. <CloseOutlined />
  508. </a>
  509. <LivestreamOthers />
  510. </div>
  511. <div class="liveview" v-if="livestreamAgoraVisible" v-drag-window>
  512. <div style="height: 40px; width: 100%" class="drag-title"></div>
  513. <a style="position: absolute; right: 10px; top: 10px; font-size: 16px; color: white;"
  514. @click="closeLivestreamAgora">
  515. <CloseOutlined />
  516. </a>
  517. <LivestreamAgora />
  518. </div>
  519. </div>
  520. </template>
  521. <script lang="ts">
  522. import { computed, defineComponent, onMounted, reactive, ref, watch, onUnmounted } from 'vue'
  523. import {
  524. generateLineContent,
  525. generatePointContent,
  526. generatePolyContent
  527. } from '../utils/map-layer-utils'
  528. import { postElementsReq } from '/@/api/layer'
  529. import { MapDoodleType, MapElementEnum } from '/@/constants/map'
  530. import { useGMapManage } from '/@/hooks/use-g-map'
  531. import { useGMapCover } from '/@/hooks/use-g-map-cover'
  532. import { useMouseTool } from '/@/hooks/use-mouse-tool'
  533. import { useGMapTrajectory } from '/@/hooks/use-g-map-trajectory'
  534. import { getApp, getRoot } from '/@/root'
  535. import { useMyStore } from '/@/store'
  536. import { GeojsonCoordinate } from '/@/types/map'
  537. import { MapDoodleEnum } from '/@/types/map-enum'
  538. import { PostElementsBody } from '/@/types/mapLayer'
  539. import { uuidv4 } from '/@/utils/uuid'
  540. import { gcj02towgs84, wgs84togcj02 } from '/@/vendors/coordtransform'
  541. import { deviceTsaUpdate } from '/@/hooks/use-g-map-tsa'
  542. import {
  543. DeviceOsd, DeviceStatus, DockOsd, EGear, EModeCode, GatewayOsd, EDockModeCode,
  544. NetworkStateQualityEnum, NetworkStateTypeEnum, RainfallEnum, DroneInDockEnum
  545. } from '/@/types/device'
  546. import pin from '/@/assets/icons/pin-2d8cf0.svg'
  547. import M30 from '/@/assets/icons/m30.png'
  548. import planeSrc from '/@/assets/icons/plane.png'
  549. import satelliteSrc from '/@/assets/icons/satellite.png'
  550. import {
  551. BorderOutlined, LineOutlined, CloseOutlined, AimOutlined, ControlOutlined, TrademarkOutlined, ArrowDownOutlined,
  552. ThunderboltOutlined, SignalFilled, GlobalOutlined, HistoryOutlined, CloudUploadOutlined, RocketOutlined,
  553. FieldTimeOutlined, CloudOutlined, CloudFilled, FolderOpenOutlined, RobotFilled, ArrowUpOutlined, CarryOutOutlined
  554. } from '@ant-design/icons-vue'
  555. import { EDeviceTypeName, ELocalStorageKey } from '../types'
  556. import DockControlPanel from './g-map/DockControlPanel.vue'
  557. import DeviceLive from './deviceLive/index.vue'
  558. import { useDockControl } from './g-map/use-dock-control'
  559. import DroneControlPanel from './g-map/DroneControlPanel.vue'
  560. import { useConnectMqtt } from './g-map/use-connect-mqtt'
  561. import LivestreamOthers from './livestream-others.vue'
  562. import FlightAreaActionIcon from './flight-area/FlightAreaActionIcon.vue'
  563. import { EFlightAreaType } from '../types/flight-area'
  564. import { useFlightArea } from './flight-area/use-flight-area'
  565. import { useFlightAreaDroneLocationEvent } from './flight-area/use-flight-area-drone-location-event'
  566. export default defineComponent({
  567. components: {
  568. BorderOutlined,
  569. LineOutlined,
  570. CloseOutlined,
  571. AimOutlined,
  572. ControlOutlined,
  573. TrademarkOutlined,
  574. ThunderboltOutlined,
  575. SignalFilled,
  576. GlobalOutlined,
  577. HistoryOutlined,
  578. CloudUploadOutlined,
  579. FieldTimeOutlined,
  580. CloudOutlined,
  581. CloudFilled,
  582. FolderOpenOutlined,
  583. RobotFilled,
  584. ArrowUpOutlined,
  585. ArrowDownOutlined,
  586. DockControlPanel,
  587. DroneControlPanel,
  588. DeviceLive,
  589. CarryOutOutlined,
  590. RocketOutlined,
  591. LivestreamOthers,
  592. FlightAreaActionIcon,
  593. },
  594. name: 'GMap',
  595. props: {},
  596. setup() {
  597. const useMouseToolHook = useMouseTool()
  598. const useGMapManageHook = useGMapManage()
  599. const deviceTsaUpdateHook = deviceTsaUpdate()
  600. const root = getRoot()
  601. const mouseMode = ref(false)
  602. const store = useMyStore()
  603. const state = reactive({
  604. mapType: 0,// 地图类型 0-普通 1-卫星
  605. currentType: '',
  606. coverIndex: 0,
  607. isFlightArea: false,
  608. deviceLiveStatus: false,// 设备直播状态
  609. })
  610. // 点击切换地图类型
  611. const onClickSwitchMapType = () => {
  612. const mapType = state.mapType === 0 ? 1 : 0;
  613. state.mapType = mapType;
  614. useMouseToolHook.onChangeMapType(mapType);
  615. }
  616. const str: string = '--'
  617. const deviceInfo: any = reactive({
  618. gateway: {
  619. capacity_percent: str,
  620. transmission_signal_quality: str,
  621. } as GatewayOsd,
  622. dock: {
  623. } as DockOsd,
  624. device: {
  625. gear: -1,
  626. mode_code: EModeCode.Disconnected,
  627. height: str,
  628. home_distance: str,
  629. horizontal_speed: str,
  630. vertical_speed: str,
  631. wind_speed: str,
  632. wind_direction: str,
  633. elevation: str,
  634. position_state: {
  635. gps_number: str,
  636. is_fixed: 0,
  637. rtk_number: str
  638. },
  639. battery: {
  640. capacity_percent: str,
  641. landing_power: str,
  642. remain_flight_time: 0,
  643. return_home_power: str,
  644. },
  645. latitude: 0,
  646. longitude: 0,
  647. } as DeviceOsd
  648. })
  649. const shareId = computed(() => {
  650. return store.state.layerBaseInfo.share
  651. })
  652. const drawVisible = computed(() => {
  653. return store.state.drawVisible
  654. })
  655. const livestreamOthersVisible = computed(() => {
  656. return store.state.livestreamOthersVisible
  657. })
  658. const livestreamAgoraVisible = computed(() => {
  659. return store.state.livestreamAgoraVisible
  660. })
  661. const osdVisible = computed(() => {
  662. return store.state.osdVisible
  663. })
  664. const qualityStyle = computed(() => {
  665. if (deviceInfo.dock.basic_osd?.network_state?.type === NetworkStateTypeEnum.ETHERNET ||
  666. (deviceInfo.dock.basic_osd?.network_state?.quality || 0) > NetworkStateQualityEnum.FAIR) {
  667. return 'color: #00ee8b'
  668. }
  669. if ((deviceInfo.dock.basic_osd?.network_state?.quality || 0) === NetworkStateQualityEnum.FAIR) {
  670. return 'color: yellow'
  671. }
  672. return 'color: red'
  673. })
  674. watch(() => store.state.trajectoryList, (list: any) => {
  675. setTimeout(() => {
  676. if (list.length >= 2) {// 至少要有起点终点两个坐标才可以绘制轨迹
  677. const trajectoryHook = useGMapTrajectory()
  678. trajectoryHook.drawTrajectory(list);
  679. }
  680. }, 1000)
  681. }, { deep: true })
  682. watch(() => store.state.deviceStatusEvent, (data: any) => {
  683. if (Object.keys(data.deviceOnline).length !== 0) {
  684. deviceTsaUpdateHook.initMarker(data.deviceOnline.domain, data.deviceOnline.device_callsign, data.deviceOnline.sn)
  685. store.state.deviceStatusEvent.deviceOnline = {} as DeviceStatus
  686. }
  687. if (Object.keys(data.deviceOffline).length !== 0) {
  688. deviceTsaUpdateHook.removeMarker(data.deviceOffline.sn)
  689. if ((data.deviceOffline.sn === osdVisible.value.sn) || (osdVisible.value.is_dock && data.deviceOffline.sn === osdVisible.value.gateway_sn)) {
  690. osdVisible.value.visible = false
  691. store.commit('SET_OSD_VISIBLE_INFO', osdVisible)
  692. }
  693. store.state.deviceStatusEvent.deviceOffline = {}
  694. }
  695. }, { deep: true })
  696. watch(() => store.state.deviceState, data => {
  697. if (data.currentType === EDeviceTypeName.Gateway && data.gatewayInfo[data.currentSn]) {
  698. const coordinate = wgs84togcj02(data.gatewayInfo[data.currentSn].longitude, data.gatewayInfo[data.currentSn].latitude)
  699. deviceTsaUpdateHook.moveTo(data.currentSn, coordinate[0], coordinate[1])
  700. if (osdVisible.value.visible && osdVisible.value.gateway_sn !== '') {
  701. deviceInfo.gateway = data.gatewayInfo[osdVisible.value.gateway_sn]
  702. }
  703. }
  704. if (data.currentType === EDeviceTypeName.Aircraft && data.deviceInfo[data.currentSn]) {
  705. const coordinate = wgs84togcj02(data.deviceInfo[data.currentSn].longitude, data.deviceInfo[data.currentSn].latitude)
  706. deviceTsaUpdateHook.moveTo(data.currentSn, coordinate[0], coordinate[1])
  707. if (osdVisible.value.visible && osdVisible.value.sn !== '') {
  708. deviceInfo.device = data.deviceInfo[osdVisible.value.sn]
  709. }
  710. }
  711. if (data.currentType === EDeviceTypeName.Dock && data.dockInfo[data.currentSn]) {
  712. const coordinate = wgs84togcj02(data.dockInfo[data.currentSn].basic_osd?.longitude, data.dockInfo[data.currentSn].basic_osd?.latitude)
  713. deviceTsaUpdateHook.initMarker(EDeviceTypeName.Dock, EDeviceTypeName[EDeviceTypeName.Dock], data.currentSn, coordinate[0], coordinate[1])
  714. if (osdVisible.value.visible && osdVisible.value.is_dock && osdVisible.value.gateway_sn !== '') {
  715. deviceInfo.dock = data.dockInfo[osdVisible.value.gateway_sn]
  716. deviceInfo.device = data.deviceInfo[deviceInfo.dock.basic_osd.sub_device?.device_sn ?? osdVisible.value.sn]
  717. }
  718. }
  719. }, {
  720. deep: true
  721. })
  722. watch(() => store.state.wsEvent, newData => {
  723. const useGMapCoverHook = useGMapCover()
  724. const event = newData
  725. let exist = false
  726. if (Object.keys(event.mapElementCreat).length !== 0) {
  727. const ele: any = event.mapElementCreat
  728. store.state.Layers.forEach((layer: any) => {
  729. layer.elements.forEach((e: any) => {
  730. if (e.id === ele.id) {
  731. exist = true
  732. }
  733. })
  734. })
  735. if (exist === false) {
  736. setLayers({
  737. id: ele.id,
  738. name: ele.name,
  739. resource: ele.resource
  740. })
  741. updateCoordinates('wgs84-gcj02', ele)
  742. const data = { id: ele.id, name: ele.name }
  743. if (MapElementEnum.PIN === ele.resource?.type) {
  744. useGMapCoverHook.init2DPin(
  745. ele.name,
  746. ele.resource.content.geometry.coordinates,
  747. ele.resource.content.properties.color,
  748. data
  749. )
  750. } else if (MapElementEnum.LINE === ele.resource?.type) {
  751. useGMapCoverHook.initPolyline(
  752. ele.name,
  753. ele.resource.content.geometry.coordinates,
  754. ele.resource.content.properties.color,
  755. data
  756. )
  757. } else if (MapElementEnum.POLY === ele.resource?.type) {
  758. useGMapCoverHook.initPolygon(
  759. ele.name,
  760. ele.resource.content.geometry.coordinates,
  761. ele.resource.content.properties.color,
  762. data
  763. )
  764. }
  765. }
  766. store.state.wsEvent.mapElementCreat = {}
  767. }
  768. if (Object.keys(event.mapElementUpdate).length !== 0) {
  769. console.log(event.mapElementUpdate)
  770. console.log('该功能还未实现,请开发商自己增加')
  771. store.state.wsEvent.mapElementUpdate = {}
  772. }
  773. if (Object.keys(event.mapElementDelete).length !== 0) {
  774. console.log(event.mapElementDelete)
  775. console.log('该功能还未实现,请开发商自己增加')
  776. store.state.wsEvent.mapElementDelete = {}
  777. }
  778. }, { deep: true })
  779. function draw(type: MapDoodleType, bool: boolean, flightAreaType?: EFlightAreaType) {
  780. state.currentType = type
  781. mouseMode.value = bool
  782. state.isFlightArea = !!flightAreaType
  783. useMouseToolHook.mouseTool(type, getDrawCallback, flightAreaType)
  784. }
  785. // dock 控制面板
  786. const {
  787. dockControlPanelVisible,
  788. setDockControlPanelVisible,
  789. onCloseControlPanel,
  790. } = useDockControl()
  791. // 连接或断开drc
  792. useConnectMqtt()
  793. onMounted(() => {
  794. const app = getApp()
  795. useGMapManageHook.globalPropertiesConfig(app)
  796. })
  797. onUnmounted(() => {
  798. root.$map.destroy()
  799. })
  800. const { getDrawFlightAreaCallback, onFlightAreaDroneLocationWs } = useFlightArea()
  801. useFlightAreaDroneLocationEvent(onFlightAreaDroneLocationWs)
  802. function selectFlightAreaAction({ type, isCircle }: { type: EFlightAreaType, isCircle: boolean }) {
  803. draw(isCircle ? MapDoodleEnum.CIRCLE : MapDoodleEnum.POLYGON, true, type)
  804. }
  805. function getDrawCallback({ obj }: { obj: any }) {
  806. if (state.isFlightArea) {
  807. getDrawFlightAreaCallback(obj)
  808. return
  809. }
  810. switch (state.currentType) {
  811. case MapDoodleEnum.PIN:
  812. postPinPositionResource(obj)
  813. break
  814. case MapDoodleEnum.POLYLINE:
  815. postPolylineResource(obj)
  816. break
  817. case MapDoodleEnum.POLYGON:
  818. postPolygonResource(obj)
  819. break
  820. default:
  821. break
  822. }
  823. draw('off', false)
  824. }
  825. async function postPinPositionResource(obj: any) {
  826. const req: any = getPinPositionResource(obj)
  827. const userName = localStorage.getItem(ELocalStorageKey.Username) || ''
  828. req.element_from = 1
  829. req.resource.user_name = userName
  830. setLayers(req)
  831. const coordinates = req.resource.content.geometry.coordinates
  832. updateCoordinates('gcj02-wgs84', req);
  833. (req.resource.content.geometry.coordinates as GeojsonCoordinate).push((coordinates as GeojsonCoordinate)[2])
  834. await postElementsReq(shareId.value, req)
  835. obj.setExtData({ id: req.id, name: req.name })
  836. store.state.coverMap[req.id] = [obj]
  837. const map = root.$map
  838. const AMap = root.$aMap
  839. const text = new AMap.Text({
  840. position: new AMap.LngLat(coordinates[0], coordinates[1]),
  841. offset: new AMap.Pixel(30, 0),
  842. text: req.name,
  843. style: {
  844. fontSize: 12,
  845. padding: 0,
  846. backgroundColor: 'transparent',
  847. borderColor: 'transparent',
  848. }
  849. })
  850. map.add(text);
  851. store.state.coverMap[req.id + '_text'] = [text]
  852. obj.on('click', function () {
  853. const id = req.id;
  854. store.commit('SET_MAP_CLICK_ID', id);
  855. });
  856. }
  857. async function postPolylineResource(obj: any) {
  858. const req: any = getPolylineResource(obj)
  859. const userName = localStorage.getItem(ELocalStorageKey.Username) || ''
  860. req.element_from = 1
  861. req.resource.user_name = userName
  862. setLayers(req)
  863. const coordinatesList = req.resource.content.geometry.coordinates
  864. updateCoordinates('gcj02-wgs84', req)
  865. await postElementsReq(shareId.value, req)
  866. obj.setExtData({ id: req.id, name: req.name })
  867. store.state.coverMap[req.id] = [obj]
  868. const map = root.$map
  869. const AMap = root.$aMap
  870. if (coordinatesList.length < 2) {
  871. return
  872. }
  873. const coordinates = coordinatesList[0];
  874. const text = new AMap.Text({
  875. position: new AMap.LngLat(coordinates[0], coordinates[1]),
  876. offset: new AMap.Pixel(-30, -30),
  877. text: req.name,
  878. style: {
  879. fontSize: 12,
  880. padding: 0,
  881. backgroundColor: 'transparent',
  882. borderColor: 'transparent',
  883. }
  884. })
  885. map.add(text);
  886. store.state.coverMap[req.id + '_text'] = [text]
  887. obj.on('click', function () {
  888. const id = req.id;
  889. store.commit('SET_MAP_CLICK_ID', id);
  890. });
  891. }
  892. async function postPolygonResource(obj: any) {
  893. const req: any = getPoygonResource(obj)
  894. const userName = localStorage.getItem(ELocalStorageKey.Username) || ''
  895. req.element_from = 1
  896. req.resource.user_name = userName
  897. setLayers(req)
  898. const coordinatesList = req.resource.content.geometry.coordinates[0]
  899. updateCoordinates('gcj02-wgs84', req)
  900. await postElementsReq(shareId.value, req)
  901. obj.setExtData({ id: req.id, name: req.name })
  902. store.state.coverMap[req.id] = [obj]
  903. const map = root.$map
  904. const AMap = root.$aMap
  905. if (coordinatesList.length < 3) {
  906. return
  907. }
  908. const coordinates = coordinatesList[0];
  909. const text = new AMap.Text({
  910. position: new AMap.LngLat(coordinates[0], coordinates[1]),
  911. offset: new AMap.Pixel(0, -30),
  912. text: req.name,
  913. style: {
  914. fontSize: 12,
  915. padding: 0,
  916. backgroundColor: 'transparent',
  917. borderColor: 'transparent',
  918. }
  919. })
  920. map.add(text);
  921. store.state.coverMap[req.id + '_text'] = [text]
  922. obj.on('click', function () {
  923. const id = req.id;
  924. store.commit('SET_MAP_CLICK_ID', id);
  925. });
  926. }
  927. function getPinPositionResource(obj: any) {
  928. const position = obj.getPosition()
  929. const resource = generatePointContent(position)
  930. const name = obj._originOpts.title
  931. const id = uuidv4()
  932. return {
  933. id,
  934. name,
  935. resource
  936. }
  937. }
  938. function getPolylineResource(obj: any) {
  939. const path = obj.getPath()
  940. const resource = generateLineContent(path)
  941. const { name, id } = getBaseInfo(obj._opts)
  942. return {
  943. id,
  944. name,
  945. resource
  946. }
  947. }
  948. function getPoygonResource(obj: any) {
  949. const path = obj.getPath()
  950. const resource = generatePolyContent(path)
  951. const { name, id } = getBaseInfo(obj._opts)
  952. return {
  953. id,
  954. name,
  955. resource
  956. }
  957. }
  958. function getBaseInfo(obj: any) {
  959. const name = obj.title
  960. const id = uuidv4()
  961. return { name, id }
  962. }
  963. function setLayers(resource: PostElementsBody) {
  964. const layers = store.state.Layers
  965. const layer: any = layers.find((item: any) => item.id.includes(shareId.value))
  966. // layer.id = 'private_layer' + uuidv4()
  967. // layer?.elements.push(resource)
  968. if (layer?.elements) {
  969. (layer?.elements as any[]).push(resource)
  970. }
  971. store.commit('SET_LAYER_INFO', layers)
  972. }
  973. function closeLivestreamOthers() {
  974. store.commit('SET_LIVESTREAM_OTHERS_VISIBLE', false)
  975. }
  976. function closeLivestreamAgora() {
  977. store.commit('SET_LIVESTREAM_AGORA_VISIBLE', false)
  978. }
  979. function updateCoordinates(transformType: string, element: any) {
  980. const geoType = element.resource?.content.geometry.type
  981. const type = element.resource?.type as number
  982. if (element.resource) {
  983. if (MapElementEnum.PIN === type) {
  984. const coordinates = element.resource?.content.geometry
  985. .coordinates as GeojsonCoordinate
  986. if (transformType === 'wgs84-gcj02') {
  987. const transResult = wgs84togcj02(
  988. coordinates[0],
  989. coordinates[1]
  990. ) as GeojsonCoordinate
  991. element.resource.content.geometry.coordinates = transResult
  992. } else if (transformType === 'gcj02-wgs84') {
  993. const transResult = gcj02towgs84(
  994. coordinates[0],
  995. coordinates[1]
  996. ) as GeojsonCoordinate
  997. element.resource.content.geometry.coordinates = transResult
  998. }
  999. } else if (MapElementEnum.LINE === type) {
  1000. const coordinates = element.resource?.content.geometry
  1001. .coordinates as GeojsonCoordinate[]
  1002. if (transformType === 'wgs84-gcj02') {
  1003. coordinates.forEach((coordinate, i, arr) => {
  1004. arr[i] = wgs84togcj02(
  1005. coordinate[0],
  1006. coordinate[1]
  1007. ) as GeojsonCoordinate
  1008. })
  1009. } else if (transformType === 'gcj02-wgs84') {
  1010. coordinates.forEach((coordinate, i, arr) => {
  1011. arr[i] = gcj02towgs84(
  1012. coordinate[0],
  1013. coordinate[1]
  1014. ) as GeojsonCoordinate
  1015. })
  1016. }
  1017. element.resource.content.geometry.coordinates = coordinates
  1018. } else if (MapElementEnum.POLY === type) {
  1019. const coordinates = element.resource?.content.geometry
  1020. .coordinates[0] as GeojsonCoordinate[]
  1021. if (transformType === 'wgs84-gcj02') {
  1022. coordinates.forEach((coordinate, i, arr) => {
  1023. arr[i] = wgs84togcj02(
  1024. coordinate[0],
  1025. coordinate[1]
  1026. ) as GeojsonCoordinate
  1027. })
  1028. } else if (transformType === 'gcj02-wgs84') {
  1029. coordinates.forEach((coordinate, i, arr) => {
  1030. arr[i] = gcj02towgs84(
  1031. coordinate[0],
  1032. coordinate[1]
  1033. ) as GeojsonCoordinate
  1034. })
  1035. }
  1036. element.resource.content.geometry.coordinates = [coordinates]
  1037. }
  1038. }
  1039. }
  1040. return {
  1041. draw,
  1042. mouseMode,
  1043. drawVisible,
  1044. livestreamOthersVisible,
  1045. livestreamAgoraVisible,
  1046. osdVisible,
  1047. pin,
  1048. state,
  1049. M30,
  1050. planeSrc,
  1051. satelliteSrc,
  1052. deviceInfo,
  1053. onClickSwitchMapType,
  1054. EGear,
  1055. EModeCode,
  1056. str,
  1057. EDockModeCode,
  1058. dockControlPanelVisible,
  1059. setDockControlPanelVisible,
  1060. onCloseControlPanel,
  1061. NetworkStateTypeEnum,
  1062. NetworkStateQualityEnum,
  1063. RainfallEnum,
  1064. DroneInDockEnum,
  1065. closeLivestreamOthers,
  1066. closeLivestreamAgora,
  1067. qualityStyle,
  1068. selectFlightAreaAction,
  1069. }
  1070. }
  1071. })
  1072. </script>
  1073. <style lang="scss" scoped>
  1074. .g-map-wrapper {
  1075. height: 100%;
  1076. width: 100%;
  1077. .g-action-panel {
  1078. position: absolute;
  1079. top: 16px;
  1080. right: 16px;
  1081. .g-action-item {
  1082. width: 28px;
  1083. height: 28px;
  1084. background: white;
  1085. color: $primary;
  1086. border-radius: 2px;
  1087. line-height: 28px;
  1088. text-align: center;
  1089. margin-bottom: 2px;
  1090. }
  1091. .g-action-item:hover {
  1092. border: 1px solid $primary;
  1093. border-radius: 2px;
  1094. }
  1095. }
  1096. .selection {
  1097. border: 1px solid $primary;
  1098. border-radius: 2px;
  1099. }
  1100. // antd button 光晕
  1101. &:deep(.ant-btn) {
  1102. &::after {
  1103. display: none;
  1104. }
  1105. }
  1106. }
  1107. .g-mapType {
  1108. width: 28px;
  1109. height: 28px;
  1110. background: white;
  1111. border-radius: 2px;
  1112. line-height: 28px;
  1113. text-align: center;
  1114. position: absolute;
  1115. bottom: 50px;
  1116. right: 16px;
  1117. cursor: pointer;
  1118. img {
  1119. width: 18px;
  1120. height: 18px;
  1121. }
  1122. }
  1123. .g-info {
  1124. width: 100%;
  1125. height: 26px;
  1126. padding: 0 16px;
  1127. background: rgba(255, 255, 255, 0.7);
  1128. border-radius: 2px;
  1129. line-height: 28px;
  1130. text-align: center;
  1131. position: absolute;
  1132. bottom: 0;
  1133. right: 0;
  1134. display: flex;
  1135. justify-content: flex-end;
  1136. align-items: center;
  1137. }
  1138. .osd-panel {
  1139. position: absolute;
  1140. margin-left: 10px;
  1141. left: 0;
  1142. top: 10px;
  1143. width: 480px;
  1144. background: #000;
  1145. color: #fff;
  1146. border-radius: 2px;
  1147. background-color: rgba(0, 0, 0, 0.8);
  1148. }
  1149. .openLiveButton {
  1150. padding: 5px;
  1151. border: 1px solid #5c5c5c;
  1152. cursor: pointer;
  1153. }
  1154. .osd>div:not(.dock-control-panel) {
  1155. margin-top: 5px;
  1156. padding: 5px;
  1157. }
  1158. .circle {
  1159. border-radius: 50%;
  1160. width: 10px;
  1161. height: 10px;
  1162. }
  1163. .battery-slide {
  1164. .capacity-percent {
  1165. background: #00ee8b;
  1166. }
  1167. .return-home {
  1168. background: #ff9f0a;
  1169. }
  1170. .landing {
  1171. background: #f5222d;
  1172. }
  1173. .white-point {
  1174. width: 4px;
  1175. height: 4px;
  1176. border-radius: 50%;
  1177. background: white;
  1178. bottom: -0.5px;
  1179. }
  1180. .battery {
  1181. background: #141414;
  1182. color: #00ee8b;
  1183. margin-top: -10px;
  1184. height: 20px;
  1185. width: auto;
  1186. border-left: 1px solid #00ee8b;
  1187. padding: 0 5px;
  1188. }
  1189. }
  1190. .battery-slide>div {
  1191. position: absolute;
  1192. min-height: 2px;
  1193. border-radius: 2px;
  1194. }
  1195. .liveview {
  1196. position: absolute;
  1197. color: #fff;
  1198. z-index: 1;
  1199. left: 0;
  1200. margin-left: 10px;
  1201. top: 10px;
  1202. text-align: center;
  1203. width: 800px;
  1204. height: 660px;
  1205. background: #232323;
  1206. }
  1207. </style>
  1208. <style lang="scss">
  1209. .amap-logo {
  1210. display: none !important;
  1211. }
  1212. .amap-copyright {
  1213. display: none !important;
  1214. }
  1215. </style>