index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. <template>
  2. <div id="globalMap">
  3. <div class="global-map">
  4. <MapLogical v-if="activeMap === 'logical'" :map-data="mapData" />
  5. <YztMap
  6. v-else-if="['satellite2', 'satellite3', 'imageMap', 'imageMap2'].includes(activeMap)"
  7. ref="map2Ref"
  8. :active-map="activeMap"
  9. :point-type="pointType"
  10. v-model:showMask="showMask"
  11. />
  12. <Map
  13. v-else
  14. ref="mapRef"
  15. :active-map="activeMap"
  16. :point-type="pointType"
  17. v-model:showMask="showMask"
  18. @handle-show-video="handleShowVideo"
  19. @handle-show-warehouse="handleShowWarehouse"
  20. @handleShowPeople="handleShowPeople"
  21. />
  22. <!--左侧菜单-->
  23. <LeftMenu
  24. ref="leftMenuRef"
  25. style="position: absolute; top: 20px; left: 20px"
  26. @click-menu="clickMenu"
  27. @select-search-marker="selectSearchMarker"
  28. />
  29. <!--右侧菜单-->
  30. <RightMenu ref="rightMenuRef" :point-type="pointType" />
  31. <!--更换地图类型-->
  32. <SwitchMapTool :active-map="activeMap" class="tool-box" @switch-map="switchMap" />
  33. <!--时间轴-->
  34. <TimeAxis />
  35. <DrawTools v-if="showDrawTools" @handle-analysis-data="handleAnalysisData" />
  36. <NearbyVideos v-if="showNearbyVideos" v-model="showNearbyVideos" :location="location" />
  37. <GridPointRainfall v-if="showRainfall" v-model="showRainfall" :location="location" />
  38. <MaterialDetail v-if="showWarehouse" v-model="showWarehouse" :warehouse-data="warehouseData" />
  39. <CommunicationSupport v-if="communicationSupport.show" @close="handleHideCommunicationSupport" />
  40. <EmergencyCrew v-if="showPeople" v-model="showPeople" :id="teamId" />
  41. </div>
  42. </div>
  43. </template>
  44. <script lang="ts" setup name="globalMap">
  45. import Map from '@/components/Map/index.vue';
  46. import YztMap from '@/components/Map/YztMap/index.vue';
  47. import { iconList, logicalData } from './data/mapData';
  48. import SwitchMapTool from '@/views/globalMap/SwitchMapTool.vue';
  49. import LeftMenu from './LeftMenu.vue';
  50. import MaterialDetail from './MaterialDetail.vue';
  51. import TimeAxis from '@/components/TimeAxis/index.vue';
  52. import { deepClone } from '@/utils';
  53. import { getPointInfo } from '@/api/globalMap';
  54. import RightMenu from './RightMenu/index.vue';
  55. import { PointType } from '@/api/globalMap/type';
  56. import DrawTools from '@/views/globalMap/RightMenu/DrawTools.vue';
  57. import CommunicationSupport from '@/views/globalMap/RightMenu/CommunicationSupport.vue';
  58. import GridPointRainfall from '@/views/globalMap/RightMenu/GridPointRainfall.vue';
  59. import NearbyVideos from '@/components/NearbyVideos/index.vue';
  60. import EmergencyCrew from '@/views/globalMap/RightMenu/EmergencyCrew.vue';
  61. const rightMenuRef = ref(null);
  62. const mapData = reactive(logicalData);
  63. let map;
  64. let mapRef = ref(null);
  65. let map2Ref = ref(null);
  66. let leftMenuRef = ref(null);
  67. let showMask = ref(true);
  68. // vectorgraph satellite imageMap 废弃:logical satellite2 satellite3
  69. let activeMap = ref('satellite');
  70. // 附近视频菜单数据
  71. let tempMenu = ref({
  72. name: '',
  73. checked: false
  74. });
  75. const communicationSupport = reactive({
  76. show: false,
  77. data: {}
  78. });
  79. const switchMap = (key) => {
  80. activeMap.value = key;
  81. };
  82. let pointType = ref<PointType[]>([]);
  83. let markerList = ref([]);
  84. const addMarkers = (item) => {
  85. const dom = activeMap.value === 'imageMap' ? map2Ref.value : mapRef.value;
  86. if (dom) {
  87. if (!item.checked) {
  88. let index = pointType.value.findIndex((item2) => item.component === item2.component);
  89. if (index > -1) {
  90. pointType.value.splice(index, 1);
  91. }
  92. if (pointType.value && pointType.value.length === 0) {
  93. dom.clearMarker('point');
  94. return;
  95. }
  96. } else {
  97. // 右侧图层分析状态
  98. item.checked2 = true;
  99. pointType.value.push(item);
  100. }
  101. let path = [];
  102. pointType.value.forEach((item) => {
  103. path.push(item.component);
  104. });
  105. getPointInfo(path.toString()).then((res) => {
  106. const data = res.data && res.data.list ? res.data?.list : [];
  107. markerList.value = data;
  108. data.forEach((item2) => {
  109. // 获取图标
  110. if (iconList[item2.dataType]) {
  111. item2.icon = iconList[item2.dataType].image;
  112. item2.image = iconList[item2.dataType].image;
  113. item2.imageHover = iconList[item2.dataType].imageHover;
  114. item2.size = iconList[item2.dataType].size;
  115. } else {
  116. item2.icon = iconList['common'].image;
  117. item2.image = iconList['common'].image;
  118. item2.imageHover = iconList['common'].imageHover;
  119. item2.size = iconList['common'].size;
  120. }
  121. if (item2.materia_name) {
  122. item2.name = item2.materia_name;
  123. }
  124. item2.parentId = item.component;
  125. item2.lnglat = [item2.longitude, item2.latitude];
  126. });
  127. dom.addMarker(data);
  128. });
  129. }
  130. };
  131. // 跳转指定地点
  132. const toAddress = (item) => {
  133. const dom = activeMap.value === 'imageMap' ? map2Ref.value : mapRef.value;
  134. dom.setCenter(item);
  135. };
  136. let showDrawTools = ref(false);
  137. // 右侧菜单
  138. // 点击菜单
  139. const clickMenu = (item, dataList) => {
  140. if (item.path === '1') {
  141. // 空间分析
  142. if (item.component === 'spatial') {
  143. showDrawTools.value = !showDrawTools.value;
  144. }
  145. rightMenuRef.value.updateMenu(item.checked ? '1' : '2', item);
  146. } else if (item.path === '2') {
  147. let checked = item.checked ? '1' : '2';
  148. // 打点信息
  149. addMarkers(item);
  150. if (
  151. [
  152. '易涝隐患点',
  153. '无人机',
  154. '铁塔运行监测',
  155. '物资与装备',
  156. '通讯保障',
  157. '路网视频',
  158. '江湖河库',
  159. '防溺水',
  160. '森林防火',
  161. '防灾救援',
  162. '救援队伍'
  163. ].includes(item.name)
  164. ) {
  165. rightMenuRef.value.updateMenu(checked, item);
  166. } else {
  167. let index = findChecked(dataList, item.name);
  168. if (item.checked && index > 0) {
  169. // 已有图层分析直接切换到该index
  170. rightMenuRef.value.showIndexMenu('图层分析');
  171. } else if (item.checked || (!item.checked && index === 0)) {
  172. rightMenuRef.value.updateMenu(checked, { name: '图层分析', meta: { icon: 'icon1' } });
  173. }
  174. }
  175. } else if (item.path === '3') {
  176. // 通讯保障
  177. communicationSupport.show = !communicationSupport.show;
  178. communicationSupport.data = item;
  179. } else if (item.path === '4') {
  180. if (!item.checked) {
  181. rightMenuRef.value.updateMenu('2', item);
  182. } else {
  183. tempMenu.value = item;
  184. // 附近视频
  185. map = getMap();
  186. //为地图注册click事件获取鼠标点击出的经纬度坐标
  187. map.on('click', handleClickMap);
  188. }
  189. }
  190. };
  191. const handleHideCommunicationSupport = () => {
  192. communicationSupport.show = false;
  193. leftMenuRef.value.setMenuChange(communicationSupport.data, false);
  194. };
  195. const findChecked = (dataList, name) => {
  196. let index = 0;
  197. dataList.forEach((item) => {
  198. if (item.name !== name && item.path === '2' && !!item.checked) {
  199. index++;
  200. }
  201. if (item.children && item.children.length > 0) {
  202. let res = findChecked(item.children, name);
  203. index += res;
  204. }
  205. });
  206. return index;
  207. };
  208. // 点击搜索结果,添加标注
  209. const selectSearchMarker = (item) => {
  210. const dom = activeMap.value === 'imageMap' ? map2Ref.value : mapRef.value;
  211. let item2 = deepClone(item);
  212. // 获取图标
  213. if (iconList[item2.dataType]) {
  214. item2.icon = iconList[item2.dataType].imageHover;
  215. item2.image = iconList[item2.dataType].image;
  216. item2.imageHover = iconList[item2.dataType].imageHover;
  217. item2.size = iconList[item2.dataType].size;
  218. } else {
  219. item2.icon = iconList['common'].imageHover;
  220. item2.image = iconList['common'].image;
  221. item2.imageHover = iconList['common'].imageHover;
  222. item2.size = iconList['common'].size;
  223. }
  224. item2.lnglat = [item2.longitude, item2.latitude];
  225. dom.addSearchMarker(item2);
  226. };
  227. const handleAnalysisData = (data) => {
  228. rightMenuRef.value.handleMenu('空间分析', data);
  229. };
  230. // 获取地图元素操作
  231. const getMap = () => {
  232. if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
  233. return map2Ref.value.getMap();
  234. } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
  235. return mapRef.value.getMap();
  236. }
  237. return {};
  238. };
  239. const getMapUtils = () => {
  240. if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
  241. return map2Ref.value.getMap();
  242. } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
  243. return mapRef.value.getMapUtils();
  244. }
  245. return {};
  246. };
  247. const showDetail = (data, dataType) => {
  248. if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
  249. return map2Ref.value.handleHover(data, dataType);
  250. } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
  251. return mapRef.value.handleHover(data, dataType);
  252. }
  253. return {};
  254. };
  255. const getDrawTool = () => {
  256. if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
  257. return map2Ref.value.drawTool;
  258. } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
  259. return mapRef.value.drawTool;
  260. }
  261. return {};
  262. };
  263. const getMarkers = () => {
  264. if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
  265. return map2Ref.value.getMarkers();
  266. } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
  267. return mapRef.value.getMarkers();
  268. }
  269. return {};
  270. };
  271. const getPlaceSearch = () => {
  272. if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
  273. return map2Ref.value.getPlaceSearch();
  274. } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
  275. return mapRef.value.getPlaceSearch();
  276. }
  277. return {};
  278. };
  279. const trackPlayback = (data) => {
  280. if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
  281. return map2Ref.value.trackPlayback(data);
  282. } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
  283. return mapRef.value.trackPlayback(data);
  284. }
  285. return {};
  286. };
  287. let showNearbyVideos = ref(false);
  288. let showRainfall = ref(false);
  289. let location = ref([]);
  290. watch(showNearbyVideos, () => {
  291. if (!showNearbyVideos.value) {
  292. location.value = [];
  293. if (!!tempMenu.value && !!tempMenu.value.name) {
  294. leftMenuRef.value.setMenuChange(tempMenu.value, false);
  295. tempMenu.value = {};
  296. map.off('click', handleClickMap);
  297. }
  298. }
  299. });
  300. watch(showRainfall, () => {
  301. if (!showRainfall.value) {
  302. location.value = [];
  303. if (!!tempMenu.value && !!tempMenu.value.name) {
  304. leftMenuRef.value.setMenuChange(tempMenu.value, false);
  305. tempMenu.value = {};
  306. map.off('click', handleClickMap);
  307. }
  308. }
  309. });
  310. // 显示附近视频
  311. const handleShowVideo = (data) => {
  312. location.value = [data.longitude, data.latitude];
  313. showNearbyVideos.value = true;
  314. };
  315. const handleClickMap = (e) => {
  316. location.value = [e.lnglat.getLng(), e.lnglat.getLat()];
  317. if (!!tempMenu.value && tempMenu.value.name === '附近视频') {
  318. showNearbyVideos.value = true;
  319. } else if (!!tempMenu.value && tempMenu.value.name === '格点雨量') {
  320. showRainfall.value = true;
  321. } else if (!!tempMenu.value && tempMenu.value.name === '定点分析') {
  322. const item = deepClone(tempMenu.value);
  323. const nowLocation = deepClone(location.value);
  324. tempMenu.value = {};
  325. map.off('click', handleClickMap);
  326. rightMenuRef.value.updateMenu(item.checked ? '1' : '2', item, nowLocation);
  327. }
  328. };
  329. let showWarehouse = ref(false);
  330. let warehouseData = ref('');
  331. const handleShowWarehouse = (data) => {
  332. warehouseData.value = data;
  333. showWarehouse.value = true;
  334. };
  335. // 救援队伍人员列表
  336. let showPeople = ref(false);
  337. let teamId = ref('');
  338. const handleShowPeople = (data) => {
  339. teamId.value = data.id;
  340. showPeople.value = true;
  341. };
  342. // onMounted(() => {
  343. // mapRef.value.addEventListener('resize', handleResize);
  344. // })
  345. onBeforeUnmount(() => {
  346. if (!!map) {
  347. map.off('click', handleClickMap);
  348. }
  349. });
  350. provide('getMap', getMap);
  351. provide('getMapUtils', getMapUtils);
  352. provide('trackPlayback', trackPlayback);
  353. provide('showDetail', showDetail);
  354. provide('getDrawTool', getDrawTool);
  355. provide('getMarkers', getMarkers);
  356. provide('getPlaceSearch', getPlaceSearch);
  357. </script>
  358. <style lang="scss" scoped>
  359. #globalMap {
  360. width: 100%;
  361. height: 100%;
  362. }
  363. .global-map {
  364. width: 100%;
  365. height: 100%;
  366. position: relative;
  367. //overflow: hidden;
  368. .tool-box {
  369. position: absolute;
  370. right: 85px;
  371. bottom: 90px;
  372. z-index: 10;
  373. color: #fff;
  374. }
  375. }
  376. .box {
  377. position: absolute;
  378. top: 20px;
  379. right: 20px;
  380. width: 300px;
  381. background-color: #041d55;
  382. display: flex;
  383. flex-direction: column;
  384. padding: 20px;
  385. color: #fff;
  386. font-size: 16px;
  387. height: 500px;
  388. max-height: 90%;
  389. div {
  390. line-height: 30px;
  391. cursor: pointer;
  392. }
  393. }
  394. .fixed {
  395. position: fixed !important;
  396. }
  397. </style>