index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. <template>
  2. <div ref="containerRef" class="map-container">
  3. <div
  4. ref="mapRef"
  5. id="YztMap"
  6. class="map-container"
  7. :style="{
  8. width: width,
  9. height: height
  10. }"
  11. />
  12. </div>
  13. </template>
  14. <script setup lang="ts">
  15. import mmJson from '@/assets/json/mm2.json';
  16. import { olMap } from '@/utils/olMap/olMap';
  17. import { PointType } from '@/api/globalMap/type';
  18. import { ScaleLine } from 'ol/control';
  19. import { getPointInfoList } from '@/api/globalMap';
  20. import { getDictLabel } from '@/utils/dict';
  21. import { methodList, titleList } from '../data';
  22. import { pointDetailTemplate } from '../mapData';
  23. interface Props {
  24. activeMap: string;
  25. pointType: PointType[];
  26. }
  27. const containerScale = inject('containerScale');
  28. const props = withDefaults(defineProps<Props>(), {});
  29. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  30. const { point_type } = toRefs<any>(proxy?.useDict('point_type'));
  31. const emits = defineEmits(['update:drawing', 'selectGraphics', 'handleShowWarehouse', 'handleShowVideo', 'handleShowPeople']);
  32. const mapRef = ref(null);
  33. const mapState = reactive({
  34. center: [110.925175, 21.678955],
  35. zoom: 7.9,
  36. minZoom: 6,
  37. maxZoom: 16,
  38. isThreeDimensional: false,
  39. // 是否显示比例尺
  40. showScale: true
  41. });
  42. const containerRef = ref();
  43. const width = ref('100%');
  44. const height = ref('100%');
  45. let map, mapUtils;
  46. // 监听是否开启绘制
  47. watch(
  48. () => props.drawing,
  49. (value) => {
  50. if (value) {
  51. mapUtils.drawGraphics(props.graphicsType);
  52. } else {
  53. mapUtils.closeDraw();
  54. }
  55. }
  56. );
  57. const mapList = reactive({
  58. satellite2: [
  59. { layer: 'map', code: 'YZT1712111943104', zIndex: '-99', visible: true },
  60. { layer: 'annotation', code: 'YZT1695608158269', zIndex: '-98', visible: true }
  61. ],
  62. satellite3: [
  63. { layer: 'map', code: 'YZT1708679726700', zIndex: '-99', visible: true },
  64. { layer: 'annotation', code: 'YZT1695608158269', zIndex: '-98', visible: true }
  65. ],
  66. imageMap: [
  67. { layer: 'map', code: 'YZT1640925052482', zIndex: '-99' },
  68. { layer: 'annotation', code: 'YZT1695608158269', zIndex: '-98', visible: true }
  69. ],
  70. imageMap2: [
  71. { layer: 'map', code: 'YZT1640925052482', zIndex: '-99', visible: true },
  72. { layer: 'annotation', code: 'YZT1695608158269', zIndex: '-98', visible: true }
  73. ]
  74. });
  75. // 监听地图类型变化
  76. watch(
  77. () => props.activeMap,
  78. () => {
  79. if (!mapUtils) return;
  80. mapUtils.replaceLayers(mapList[props.activeMap]);
  81. }
  82. );
  83. let scale;
  84. const init = () => {
  85. mapUtils = new olMap({
  86. dom: mapRef.value,
  87. id: mapList[props.activeMap],
  88. center: mapState.center,
  89. zoom: mapState.zoom,
  90. minZoom: mapState.minZoom,
  91. maxZoom: mapState.maxZoom,
  92. drawTool: {
  93. use: true,
  94. color: props.color,
  95. drawType: props.drawType,
  96. graphicsType: props.graphicsType,
  97. // 绘制完成事件
  98. onDrawCompleted: (data, overlaysData, obj) => {
  99. emits('selectGraphics', data, overlaysData.length.toString());
  100. // 点击空间分析
  101. obj.on('click', function () {
  102. // 没在编辑时
  103. if (!props.drawing) {
  104. emits('selectGraphics', data);
  105. }
  106. });
  107. }
  108. },
  109. // 加载完成事件
  110. onLoadCompleted: (YztMap) => {
  111. map = YztMap;
  112. // initMouseTool(mapUtils);
  113. scale = new ScaleLine();
  114. map.addControl(scale);
  115. map.getView().on('change:resolution', () => {
  116. mapState.zoom = map.getView().getZoom().toFixed(2);
  117. });
  118. handleResize();
  119. },
  120. onMarkerClick: (data) => {
  121. // 多点位
  122. if (data.type === '1') {
  123. let path = [];
  124. props.pointType.forEach((item) => {
  125. path.push(item.component);
  126. });
  127. getPointInfoList({
  128. option: path.toString(),
  129. longitude: data.longitude.toString(),
  130. latitude: data.latitude.toString()
  131. }).then((res) => {
  132. const data2 = res.data.list;
  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.longitude = data.longitude;
  150. item.latitude = data.latitude;
  151. const div = document.createElement('div');
  152. div.className = 'point-item point-item-hover';
  153. div.innerHTML =
  154. '<div class="td4">' + getDictLabel(point_type.value, item.dataType.toString()) + '</div><div class="td4">' + item.name + '</div>';
  155. div.addEventListener('click', () => {
  156. handlePointDetails(item);
  157. });
  158. table.appendChild(div);
  159. });
  160. tableBox.appendChild(table);
  161. content.appendChild(tableBox);
  162. let closeBtn = document.createElement('div');
  163. closeBtn.className = 'close';
  164. closeBtn.onclick = () => mapUtils.hideInfo(true);
  165. content.appendChild(closeBtn);
  166. mapUtils.showInfo(content, [data.longitude, data.latitude], true);
  167. });
  168. } else {
  169. handlePointDetails(data);
  170. }
  171. }
  172. });
  173. };
  174. const handlePointDetails = (data) => {
  175. let method = methodList[data.dataType];
  176. let title = !!titleList[data.dataType] ? titleList[data.dataType] : '信息';
  177. if (!method) return;
  178. method(data.id).then((res) => {
  179. if (!!pointDetailTemplate[data.dataType]) {
  180. let div = document.createElement('div');
  181. // div.style.cssText = 'transform: scale(' + containerScale().scaleX + ');';
  182. div.className = 'point-info';
  183. let titleDom = document.createElement('div');
  184. titleDom.className = 'title-box';
  185. titleDom.innerHTML = '<div class="gradient-text">' + title + '</div></div>';
  186. div.appendChild(titleDom);
  187. if (data.dataType === 2) {
  188. let btnBox = document.createElement('div');
  189. let btn = document.createElement('div');
  190. btnBox.className = 'flex';
  191. btn.className = 'btn';
  192. btn.innerHTML = '<div class="video-icon"></div><div>物资详情</div>';
  193. btn.onclick = () => {
  194. emits('handleShowWarehouse', data);
  195. };
  196. btnBox.appendChild(btn);
  197. div.appendChild(btnBox);
  198. } else if (data.dataType === 4) {
  199. let btnBox = document.createElement('div');
  200. let btn = document.createElement('div');
  201. btnBox.className = 'flex';
  202. btn.className = 'btn';
  203. btn.innerHTML = '<div class="video-icon"></div><div>附近视频</div>';
  204. btn.onclick = () => {
  205. emits('handleShowVideo', data);
  206. };
  207. btnBox.appendChild(btn);
  208. div.appendChild(btnBox);
  209. } else if (data.dataType === 41) {
  210. let btnBox = document.createElement('div');
  211. let btn = document.createElement('div');
  212. btnBox.className = 'flex';
  213. btn.className = 'btn';
  214. btn.innerHTML = '<div class="video-icon"></div><div>人员列表</div>';
  215. btn.onclick = () => {
  216. emits('handleShowPeople', data);
  217. };
  218. btnBox.appendChild(btn);
  219. div.appendChild(btnBox);
  220. }
  221. let icon1 = document.createElement('div');
  222. icon1.className = 'icon1';
  223. let icon2 = document.createElement('div');
  224. icon2.className = 'icon2';
  225. let icon3 = document.createElement('div');
  226. icon3.className = 'icon3';
  227. let icon4 = document.createElement('div');
  228. icon4.className = 'icon4';
  229. div.appendChild(icon1);
  230. div.appendChild(icon2);
  231. div.appendChild(icon3);
  232. div.appendChild(icon4);
  233. let table = document.createElement('div');
  234. table.className = 'table-box';
  235. let content = '';
  236. content += '<div class="table">';
  237. const newData = filterTd(res.rows[0], data.dataType);
  238. newData.forEach((item) => {
  239. if (item.type === 'shortText') {
  240. content += '<div class="tr">';
  241. item.data.forEach((item2) => {
  242. content += '<div class="point-item">';
  243. content += '<div class="td1">' + item2.label + '</div><div class="td2">' + item2.value + '</div>';
  244. content += '</div>';
  245. });
  246. content += '</div>';
  247. } else {
  248. content += '<div class="point-item2">';
  249. content += '<div class="td1">' + item.data[0].label + '</div><div class="td2">' + item.data[0].value + '</div>';
  250. content += '</div>';
  251. }
  252. });
  253. content += '</div>';
  254. table.innerHTML = content;
  255. div.appendChild(table);
  256. let closeBtn = document.createElement('div');
  257. closeBtn.className = 'close';
  258. closeBtn.onclick = () => mapUtils.hideInfo(true);
  259. div.appendChild(closeBtn);
  260. mapUtils.showInfo(div, [data.longitude, data.latitude], true);
  261. }
  262. });
  263. };
  264. const filterTd = (obj, dataType) => {
  265. let data = [];
  266. let tempData = {};
  267. let i = 0;
  268. for (let key in obj) {
  269. let keyLabel = pointDetailTemplate[dataType][key];
  270. if (!!keyLabel) {
  271. if (i === 2) {
  272. i = 0;
  273. }
  274. const value = !!obj[key] ? obj[key] : '';
  275. if (value && value.length > 8) {
  276. if (i === 0) {
  277. data.push({ type: 'longText', data: [{ label: keyLabel, value: value }] });
  278. i = 0;
  279. } else {
  280. tempData = { type: 'longText', data: [{ label: keyLabel, value: value }] };
  281. }
  282. } else {
  283. if (i === 0) {
  284. data.push({ type: 'shortText', data: [{ label: keyLabel, value: value }] });
  285. } else {
  286. data[data.length - 1].data.push({ label: keyLabel, value: value });
  287. }
  288. i++;
  289. if (!!tempData && JSON.stringify(tempData) !== '{}') {
  290. data.push(tempData);
  291. tempData = {};
  292. i = 0;
  293. }
  294. }
  295. }
  296. }
  297. if (!!tempData && JSON.stringify(tempData) !== '{}') {
  298. data.push(tempData);
  299. }
  300. if (data[data.length - 1].data && data[data.length - 1].data.length === 1 && data[data.length - 1].type === 'shortText') {
  301. data[data.length - 1].type = 'longText';
  302. }
  303. return data;
  304. };
  305. const addMarker = (points) => {
  306. mapUtils.addMarker(points);
  307. };
  308. const clearMarker = () => {
  309. mapUtils.clearMarker();
  310. };
  311. const handleResize = () => {
  312. const containerWidth = containerRef.value.clientWidth * containerScale().scaleX;
  313. const containerHeight = containerRef.value.clientHeight * containerScale().scaleY;
  314. width.value = containerWidth + 'px';
  315. height.value = containerHeight + 'px';
  316. map.updateSize();
  317. };
  318. const getMap = () => {
  319. return map;
  320. };
  321. const getScale = () => {
  322. return scale;
  323. };
  324. const getMapUtils = () => {
  325. return mapUtils;
  326. };
  327. // 加载事件
  328. onMounted(() => {
  329. init();
  330. window.addEventListener('resize', handleResize);
  331. });
  332. // 卸载事件
  333. onUnmounted(() => {
  334. window.removeEventListener('resize', handleResize);
  335. });
  336. provide('getMapUtils', getMapUtils);
  337. provide('getMap', getMap);
  338. provide('getScale', getScale);
  339. defineExpose({ getMapUtils, addMarker, clearMarker });
  340. </script>
  341. <style scoped>
  342. @import '../map.scss';
  343. .map-container {
  344. width: 100%;
  345. height: 100%;
  346. position: relative;
  347. .zoom-text {
  348. position: absolute;
  349. bottom: 8px;
  350. right: 75px;
  351. font-size: 14px;
  352. }
  353. .right-tool {
  354. position: absolute;
  355. bottom: 50px;
  356. right: 5px;
  357. }
  358. .model-btn {
  359. background-color: #022577;
  360. font-size: 14px;
  361. color: #889ee9;
  362. cursor: pointer;
  363. padding: 3px 3px;
  364. border-radius: 5px;
  365. }
  366. :deep(.amap-scalecontrol) {
  367. left: unset !important;
  368. background-color: unset !important;
  369. right: 74px;
  370. }
  371. :deep(.amap-scale-text) {
  372. width: 230px !important;
  373. text-align: left !important;
  374. font-size: 14px;
  375. padding-left: 20px;
  376. }
  377. :deep(.amap-scale-middle) {
  378. width: 228px !important;
  379. }
  380. :deep(.amap-scale-edgeright) {
  381. left: 228px !important;
  382. }
  383. :deep(.amap-logo),
  384. :deep(.amap-copyright) {
  385. display: none !important;
  386. }
  387. /* 自定义测距工具样式 */
  388. :deep(.amap-ranger) {
  389. background-color: #ffffff;
  390. border: 1px solid #888888;
  391. border-radius: 5px;
  392. padding: 5px;
  393. }
  394. :deep(.amap-ranger .amap-toolbar) {
  395. color: #333;
  396. font-size: 12px;
  397. padding: 5px;
  398. }
  399. :deep(.amap-ranger .amap-toolbar button) {
  400. background-color: #022577;
  401. color: #fff;
  402. border: none;
  403. border-radius: 4px;
  404. padding: 5px;
  405. margin-right: 5px;
  406. cursor: pointer;
  407. }
  408. :deep(.amap-ranger .amap-toolbar button:hover) {
  409. background-color: #1a3c75;
  410. }
  411. :deep(.amap-ranger .amap-toolbar .amap-toolbar-text) {
  412. color: #444;
  413. font-size: 14px;
  414. }
  415. }
  416. </style>