GMap.vue 48 KB

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