index.vue 12 KB

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