index.vue 13 KB

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