index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. <template>
  2. <div ref="containerRef" class="map-container">
  3. <div
  4. ref="mapRef"
  5. id="YztMap"
  6. class="map-container"
  7. :class="{ 'custom-cursor': mapStore.isMapSelect }"
  8. :style="{
  9. width: width,
  10. height: height,
  11. transform: 'scale(' + inverseScale.inverseScaleX + ', ' + inverseScale.inverseScaleY + ')',
  12. transformOrigin: '0 0'
  13. }"
  14. />
  15. </div>
  16. </template>
  17. <script setup lang="ts">
  18. import 'ol/ol.css';
  19. import mmJson from '@/assets/json/mm2.json';
  20. import { olMap } from '@/utils/olMap/olMap';
  21. import { getPointInfoList2 } from '@/api/globalMap';
  22. import { getDictLabel } from '@/utils/dict';
  23. import { methodList, titleList } from '../data';
  24. import { pointDetailTemplate } from '@/views/globalMap/data/mapData';
  25. import useAppStore from '@/store/modules/app';
  26. import useMapStore from '@/store/modules/map';
  27. const containerScale = inject('containerScale');
  28. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  29. const { point_type } = toRefs<any>(proxy?.useDict('point_type'));
  30. const appStore = useAppStore();
  31. const mapStore = useMapStore();
  32. const emits = defineEmits(['handleShowWarehouse', 'handleShowVideo', 'handleShowPeople', 'closeDetailDialog', 'resize']);
  33. const mapRef = ref(null);
  34. const containerRef = ref();
  35. const width = ref('100%');
  36. const height = ref('100%');
  37. let map, mapUtils;
  38. watch(
  39. () => appStore.showLeftSection,
  40. () => {
  41. nextTick(() => {
  42. handleResize();
  43. });
  44. }
  45. );
  46. watch(
  47. () => appStore.showRightSection,
  48. () => {
  49. nextTick(() => {
  50. handleResize();
  51. });
  52. }
  53. );
  54. const mapList = reactive({
  55. satellite2: [
  56. { layer: 'map', layerType: 'WMTS', code: 'YZT1708679726700', zIndex: '-100', visible: true },
  57. { layer: 'map', layerType: 'WFS', code: 'YZT1712111943104', zIndex: '-99', visible: true },
  58. { layer: 'annotation', layerType: 'WMTS', code: 'YZT1695608158269', zIndex: '-98', visible: true }
  59. ],
  60. satellite3: [
  61. { layer: 'map', layerType: 'WMTS', code: 'YZT1708679726700', zIndex: '-99', visible: true },
  62. { layer: 'annotation', layerType: 'WMTS', code: 'YZT1695608158269', zIndex: '-98', visible: true }
  63. ],
  64. imageMap: [
  65. { layer: 'map', layerType: 'WMTS', code: 'YZT1640925052482', zIndex: '-99' },
  66. { layer: 'annotation', layerType: 'WMTS', code: 'YZT1695608158269', zIndex: '-98', visible: true }
  67. ],
  68. imageMap2: [
  69. { layer: 'map', layerType: 'JSON', code: 'gd', zIndex: '-99', visible: true },
  70. { layer: 'annotation', layerType: 'WMTS', code: 'YZT1695608158269', zIndex: '-98', visible: true }
  71. ]
  72. });
  73. // 监听地图类型变化
  74. watch(
  75. () => mapStore.activeMap,
  76. () => {
  77. if (!mapUtils) return;
  78. mapUtils.replaceLayers(mapList[mapStore.activeMap]);
  79. }
  80. );
  81. watch(
  82. () => mapStore.showMask,
  83. () => {
  84. if (mapStore.showMask) {
  85. mapUtils.createVecByJson2(mmJson, { strokeWeight: 2 });
  86. } else {
  87. mapUtils.removeMask3(true);
  88. }
  89. }
  90. );
  91. const init = () => {
  92. mapStore.setMapLoaded(false);
  93. mapUtils = new olMap({
  94. dom: mapRef.value,
  95. id: mapList[mapStore.activeMap],
  96. center: mapStore.mapState.center,
  97. zoom: mapStore.mapState.zoom,
  98. minZoom: mapStore.mapState.minZoom,
  99. maxZoom: mapStore.mapState.maxZoom,
  100. showScale: true,
  101. drawTool: {
  102. use: true
  103. },
  104. // 加载完成事件
  105. onLoadCompleted: (YztMap) => {
  106. map = YztMap;
  107. mapStore.setMapLoaded(true);
  108. map.getView().on('change:resolution', () => {
  109. mapStore.setZoom(map.getView().getZoom().toFixed(2));
  110. });
  111. if (mapStore.showMask) {
  112. mapUtils.createVecByJson2(mmJson, { strokeWeight: 2 });
  113. }
  114. // let drawTool = new DrawTool({ mapUtils, map });
  115. handleResize();
  116. },
  117. onMarkerClick: (data, flag) => {
  118. let title = titleList[data.dataType];
  119. if (flag && !!title) {
  120. data.title = title;
  121. emits('closeDetailDialog', data);
  122. }
  123. // 多点位
  124. if (data.type === '1') {
  125. getPointInfoList2({
  126. option: mapStore.pointParams.option,
  127. dict_value: mapStore.pointParams.dict_value.toString(),
  128. zoom_level: mapStore.mapState.zoom,
  129. longitude: data.longitude.toString(),
  130. latitude: data.latitude.toString()
  131. }).then((res) => {
  132. const data2 = res.data;
  133. let content = document.createElement('div');
  134. // content.style.cssText = 'transform: scale(' + containerScale().scaleX + ');';
  135. content.className = 'point-info';
  136. let content2 = '';
  137. content2 += '<div class="title-box"><div class="gradient-text">多点位信息</div></div>';
  138. content2 += '<div class="icon1"></div>';
  139. content2 += '<div class="icon2"></div>';
  140. content2 += '<div class="icon3"></div>';
  141. content2 += '<div class="icon4"></div>';
  142. content.innerHTML = content2;
  143. let tableBox = document.createElement('div');
  144. tableBox.className = 'table-box';
  145. let table = document.createElement('div');
  146. table.className = 'table';
  147. table.innerHTML = '<div class="point-item"><div class="td3">主题</div><div class="td3">名称</div></div>';
  148. data2.forEach((item) => {
  149. item.image = data.image;
  150. item.imageHover = data.imageHover;
  151. item.size = data.size;
  152. item.scale = data.scale;
  153. const div = document.createElement('div');
  154. div.className = 'point-item point-item-hover';
  155. div.innerHTML =
  156. '<div class="td4">' + getDictLabel(point_type.value, item.dataType.toString()) + '</div><div class="td4">' + item.name + '</div>';
  157. div.addEventListener('click', () => {
  158. handlePointDetails(item);
  159. });
  160. table.appendChild(div);
  161. });
  162. tableBox.appendChild(table);
  163. content.appendChild(tableBox);
  164. let closeBtn = document.createElement('div');
  165. closeBtn.className = 'close';
  166. closeBtn.onclick = () => {
  167. mapUtils.hideInfo(true);
  168. emits('closeDetailDialog', data);
  169. };
  170. content.appendChild(closeBtn);
  171. mapUtils.showInfo(content, [data.longitude, data.latitude], -data.scale * data.size[1], true);
  172. });
  173. } else {
  174. handlePointDetails(data);
  175. }
  176. }
  177. });
  178. };
  179. const handlePointDetails = (data) => {
  180. let method = methodList[data.dataType];
  181. let title = !!titleList[data.dataType] ? titleList[data.dataType] : '信息';
  182. if (!method) return;
  183. method(data.id).then((res) => {
  184. if (!!pointDetailTemplate[data.dataType]) {
  185. let div = document.createElement('div');
  186. // div.style.cssText = 'transform: scale(' + containerScale().scaleX + ');';
  187. div.className = 'point-info';
  188. let titleDom = document.createElement('div');
  189. titleDom.className = 'title-box';
  190. titleDom.innerHTML = '<div class="gradient-text">' + title + '</div></div>';
  191. div.appendChild(titleDom);
  192. const objs = {
  193. '2': {
  194. title: '物资详情',
  195. method: 'handleShowWarehouse'
  196. },
  197. '41': {
  198. title: '人员列表',
  199. method: 'handleShowPeople'
  200. },
  201. '43': {
  202. title: '历史轨迹',
  203. method: 'handleShowTrack'
  204. }
  205. };
  206. let obj = objs[data.dataType];
  207. if ([4, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58].includes(data.dataType)) {
  208. obj = {
  209. title: '附近视频',
  210. method: 'handleShowVideo'
  211. };
  212. }
  213. if (!!obj) {
  214. let btnBox = document.createElement('div');
  215. let btn = document.createElement('div');
  216. btnBox.className = 'flex';
  217. btn.className = 'btn';
  218. btn.innerHTML = '<div class="video-icon"></div>' + obj.title + '<div></div>';
  219. btn.onclick = () => {
  220. emits(obj.method, data);
  221. };
  222. btnBox.appendChild(btn);
  223. div.appendChild(btnBox);
  224. }
  225. let icon1 = document.createElement('div');
  226. icon1.className = 'icon1';
  227. let icon2 = document.createElement('div');
  228. icon2.className = 'icon2';
  229. let icon3 = document.createElement('div');
  230. icon3.className = 'icon3';
  231. let icon4 = document.createElement('div');
  232. icon4.className = 'icon4';
  233. div.appendChild(icon1);
  234. div.appendChild(icon2);
  235. div.appendChild(icon3);
  236. div.appendChild(icon4);
  237. let table = document.createElement('div');
  238. table.className = 'table-box';
  239. let content = '';
  240. content += '<div class="table">';
  241. const newData = filterTd(res.rows[0], data.dataType);
  242. newData.forEach((item) => {
  243. if (item.type === 'shortText') {
  244. content += '<div class="tr">';
  245. item.data.forEach((item2) => {
  246. content += '<div class="point-item">';
  247. content += '<div class="td1">' + item2.label + '</div><div class="td2">' + item2.value + '</div>';
  248. content += '</div>';
  249. });
  250. content += '</div>';
  251. } else {
  252. content += '<div class="point-item2">';
  253. content += '<div class="td1">' + item.data[0].label + '</div><div class="td2">' + item.data[0].value + '</div>';
  254. content += '</div>';
  255. }
  256. });
  257. content += '</div>';
  258. table.innerHTML = content;
  259. div.appendChild(table);
  260. let closeBtn = document.createElement('div');
  261. closeBtn.className = 'close';
  262. closeBtn.onclick = () => {
  263. mapUtils.hideInfo(true);
  264. emits('closeDetailDialog', data);
  265. };
  266. div.appendChild(closeBtn);
  267. mapUtils.showInfo(div, [data.longitude, data.latitude], -data.scale * data.size[1], true);
  268. } else if (data.dataType === 'video') {
  269. emits('handleShowVideoDetail', res.data, true);
  270. }
  271. });
  272. };
  273. const filterTd = (obj, dataType) => {
  274. let data = [];
  275. let tempData = {};
  276. let i = 0;
  277. const pointDetailTemplateObj = pointDetailTemplate[dataType];
  278. Object.keys(pointDetailTemplateObj).forEach((key) => {
  279. let keyLabel = pointDetailTemplateObj[key];
  280. if (!!keyLabel) {
  281. if (i === 2) {
  282. i = 0;
  283. }
  284. const value = !!obj && !!obj[key] ? obj[key] : '';
  285. if (value && value.length > 8) {
  286. if (i === 0) {
  287. data.push({ type: 'longText', data: [{ label: keyLabel, value: value }] });
  288. i = 0;
  289. } else {
  290. tempData = { type: 'longText', data: [{ label: keyLabel, value: value }] };
  291. }
  292. } else {
  293. if (i === 0) {
  294. data.push({ type: 'shortText', data: [{ label: keyLabel, value: value }] });
  295. } else {
  296. data[data.length - 1].data.push({ label: keyLabel, value: value });
  297. }
  298. i++;
  299. if (!!tempData && JSON.stringify(tempData) !== '{}') {
  300. data.push(tempData);
  301. tempData = {};
  302. i = 0;
  303. }
  304. }
  305. }
  306. });
  307. if (!!tempData && JSON.stringify(tempData) !== '{}') {
  308. data.push(tempData);
  309. }
  310. if (data[data.length - 1].data && data[data.length - 1].data.length === 1 && data[data.length - 1].type === 'shortText') {
  311. data[data.length - 1].type = 'longText';
  312. }
  313. return data;
  314. };
  315. const addMarker = (points) => {
  316. mapUtils.addMarker(points);
  317. };
  318. const clearMarker = () => {
  319. mapUtils.clearMarker();
  320. };
  321. let inverseScale = ref({
  322. inverseScaleX: 1,
  323. inverseScaleY: 1
  324. });
  325. const handleResize = () => {
  326. if (!containerRef.value) return;
  327. inverseScale.value.inverseScaleX = 1 / containerScale().scaleX;
  328. inverseScale.value.inverseScaleY = 1 / containerScale().scaleY;
  329. const containerWidth = containerRef.value.clientWidth * containerScale().scaleX;
  330. const containerHeight = containerRef.value.clientHeight * containerScale().scaleY;
  331. width.value = containerWidth + 'px';
  332. height.value = containerHeight + 'px';
  333. map.updateSize();
  334. nextTick(() => {
  335. emits('resize');
  336. });
  337. };
  338. const getMap = () => {
  339. return map;
  340. };
  341. const getMapUtils = () => {
  342. return mapUtils;
  343. };
  344. const getDrawTool = () => {
  345. return mapUtils.getDrawTool();
  346. };
  347. const addSearchMarker = (item) => {
  348. return mapUtils.addSearchMarker(item);
  349. };
  350. // 加载事件
  351. onMounted(() => {
  352. init();
  353. window.addEventListener('resize', handleResize);
  354. });
  355. // 卸载事件
  356. onUnmounted(() => {
  357. window.removeEventListener('resize', handleResize);
  358. });
  359. defineExpose({ getMap, getMapUtils, addSearchMarker, getDrawTool, addMarker, clearMarker });
  360. </script>
  361. <style scoped>
  362. @import '../map.scss';
  363. .map-container {
  364. width: 100%;
  365. height: 100%;
  366. position: relative;
  367. :deep(.ol-scale-line) {
  368. left: unset;
  369. bottom: 16px;
  370. right: 48px;
  371. background-color: transparent;
  372. }
  373. :deep(.ol-scale-line-inner) {
  374. color: #ffffff;
  375. border: 1px solid #fff;
  376. border-top: none;
  377. }
  378. }
  379. .custom-cursor {
  380. cursor:
  381. url('@/assets/images/map/mark.png') 13 31,
  382. auto !important;
  383. }
  384. </style>