mapDrag.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. <!--
  2. 描述:拖放地图组件,默认尺寸是 500 * 300
  3. 接收属性参数:
  4. lat: 纬度
  5. lng: 经度
  6. 自定义事件:
  7. drag: 拖放完成事件
  8. 示例:
  9. <mapDrag @drag="dragMap" lat="22.574405" lng="114.095388"></mapDrag>
  10. -->
  11. <template>
  12. <div class="m-map" :style="{ height: curheight + 'px' }">
  13. <div id="js-container" class="map">
  14. <h5 style="text-align: center">{{$t("Loading data")}} ...</h5>
  15. </div>
  16. </div>
  17. </template>
  18. <script>
  19. import remoteLoad from '../utils/remoteLoad.js'
  20. import {MapKey, MapCityName} from '../tools/map'
  21. let qs = require('qs');
  22. import axios from 'axios';
  23. import Global from '../../src/Global.js'
  24. export default {
  25. data() {
  26. return {
  27. searchKey: '',
  28. placeSearch: null,
  29. dragStatus: false,
  30. AMapUI: null,
  31. AMap: null,
  32. }
  33. },
  34. props: {
  35. curheight: {
  36. default: 310,
  37. type: Number
  38. }
  39. },
  40. watch: {
  41. searchKey() {
  42. if (this.searchKey === '') {
  43. this.placeSearch.clear()
  44. }
  45. },
  46. },
  47. beforeDestroy() {
  48. clearInterval(this.getPoint);
  49. },
  50. methods: {
  51. // 实例化地图
  52. initMap() {
  53. let AMapUI = this.AMapUI = window.AMapUI;
  54. let AMap = this.AMap = window.AMap;
  55. let timeInterval = 5000;
  56. let lang = localStorage.language == 'zh' ? 'zh' : 'en';
  57. AMapUI.loadUI(['misc/PositionPicker'], PositionPicker => {
  58. let mapConfig = {
  59. resizeEnable: true, //是否监控地图容器尺寸变化
  60. // mapStyle: mapStyle,//地图颜色风格
  61. zoom: 16,
  62. cityName: MapCityName,
  63. lang: lang
  64. };
  65. let map = new AMap.Map('js-container', mapConfig);
  66. // 获取点位置
  67. this.getPoint(map);
  68. setInterval(this.getPoint(map), 5000);
  69. // 获取围栏信息
  70. this.getFenceInfo(map);
  71. // 启用工具条
  72. AMap.plugin(['AMap.ToolBar'], function () {
  73. map.addControl(new AMap.ToolBar({
  74. position: 'RB'
  75. }))
  76. });
  77. })
  78. },
  79. // 实例化点标记
  80. addMarker(map, lng, lat, content, imgState) {
  81. let marker = new AMap.Marker({
  82. position: [lng, lat],
  83. offset: new AMap.Pixel(-13, -30),
  84. content: imgState,
  85. });
  86. marker.setMap(map);
  87. // 弹窗偏移度
  88. let infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(14, -20)});
  89. marker.on('click', function (e) {
  90. infoWindow.setContent(content);
  91. infoWindow.open(map, e.target.getPosition());
  92. });
  93. },
  94. // 获取所有的点位置
  95. getPoint(map) {
  96. const that = this;
  97. let lnglats = [];
  98. let url = '';
  99. if (localStorage.userLevel == this.$t('单位管理员')) {
  100. url = headapi + 'v1/Company/GetRegionMapinfo';//获取 单个企业获取
  101. } else {
  102. url = headapi + 'v1/Company/GetMapinfo';//获取
  103. }
  104. let param = {
  105. token: localStorage.token
  106. };
  107. let postdata = qs.stringify(param);
  108. axios.post(url, postdata).then(function (data) {
  109. let json = data.data;
  110. if (json) {
  111. // 单个企业
  112. map.setCenter([json.Rs[0].Lng, json.Rs[0].Lat]);
  113. // todo 使用数学中心计算显示点中心
  114. localStorage.lnglats = JSON.stringify(json.Rs);
  115. if (localStorage.lnglats != JSON.stringify(lnglats)) {
  116. that.wirtePoint(map, json);
  117. }
  118. map.setFitView();
  119. }
  120. }, function (response) {
  121. console.info(response);
  122. })
  123. },
  124. // 画点
  125. wirtePoint(map, json) {
  126. let that = this;
  127. let markers = [];
  128. let curPointName = '';
  129. let lnglats = json.Rs;
  130. map.remove(markers);
  131. // 根据状态判断图标显示颜色
  132. for (var i = 0; i < lnglats.length; i++) {
  133. let imgState = '';
  134. curPointName = !lnglats[i].RegionName ? lnglats[i].ComName : lnglats[i].RegionName;
  135. switch (parseInt(lnglats[i].Detstatus)) {
  136. // 0 safe 1 warning 2 danger
  137. case 0:
  138. imgState = '<i class="green_point"></i> <span class="point_name">' + curPointName + '</span>';
  139. break;
  140. case 1:
  141. imgState = '<i class="green_point"></i> <span class="point_name">' + curPointName + '</span>';
  142. break;
  143. case 2:
  144. imgState = '<i class="red_point"></i> <span class="point_name">' + curPointName + '</span>';
  145. break;
  146. }
  147. var position;
  148. position = [json.Rs[i].Lng, json.Rs[i].Lat];
  149. let content = '';
  150. var state = '';
  151. switch (parseInt(lnglats[i].Detstatus)) {
  152. // 0 safe 1 warning 2 danger
  153. case 0:
  154. state = this.$t('normal');
  155. break;
  156. case 1:
  157. state = '<span style="color:#ffe943">' + this.$t('abnormal') + '</span>';
  158. break;
  159. case 2:
  160. state = '<span style="color:#ff0000">' + this.$t('danger') + '</span>';
  161. break;
  162. }
  163. let DecList = !json.Rs[i].DecList ? that.$t('not found') : json.Rs[i].DecList;
  164. content =
  165. '<span class="map_a" href="profile.html?hotelid=' + localStorage.comId + '&Regionid=' + json.Rs[i].Regionid + '">' +
  166. this.$t('region') + json.Rs[i].RegionName
  167. + '<br>' + this.$t('state') + ':' + state
  168. + '<br>' + this.$t('Detection') + ':' + json.Rs[i].DectorNum
  169. + '<br>' + this.$t('phone signal') + ':' + DecList
  170. + '<br>' + json.Rs[i].Wifiname + ':' + json.Rs[i].CamNum
  171. + '<br>' + this.$t('Suspicious') + json.Rs[i].Wifiname + ':' + json.Rs[i].DancapNum
  172. + '</span><em class="jumper" Regionid=' + json.Rs[i].Regionid + '>' +
  173. '<i class="icon iconProfile" href="profile.html?hotelid=' + localStorage.comId + '&Regionid=' + json.Rs[i].Regionid + '"></i>' +
  174. '<i class="icon iconPlane" href="plane.html?hotelid=' + localStorage.comId + '&Regionid=' + json.Rs[i].Regionid + '"></i></em>';
  175. that.addMarker(map, json.Rs[i].Lng, json.Rs[i].Lat, content, imgState);
  176. }
  177. },
  178. // 获取围栏信息
  179. getFenceInfo(map) {
  180. const that = this;
  181. let url = headapi + 'v1/Company/GetComfencelist';
  182. let param = {
  183. token: localStorage.token,
  184. comid: localStorage.comId
  185. };
  186. let postdata = qs.stringify(param);
  187. axios.post(url, postdata).then(function (data) {
  188. let json = data.data;
  189. if (json.Code == 0) {
  190. let fence = json.Rs.Fence;
  191. let fenceArr = fence.split(",");
  192. let path = [];
  193. for (var i = 0; i < fenceArr.length; i++) {
  194. if (i % 2 == 0) {
  195. path.push([fenceArr[i], fenceArr[i + 1]]);
  196. }
  197. }
  198. let polygon = new AMap.Polygon({
  199. path: path,
  200. strokeColor: "#6496FF",
  201. strokeWeight: 6,
  202. strokeOpacity: 0.15,
  203. fillOpacity: 0.4,
  204. fillColor: '#6496FF',
  205. zIndex: 50,
  206. });
  207. map.add(polygon);
  208. // 缩放地图到合适的视野级别
  209. map.setFitView([polygon]);
  210. }
  211. }, function (response) {
  212. console.info(response);
  213. })
  214. },
  215. // 计算点中心
  216. calcCenterBySingle(data) {
  217. var total = data.length;
  218. var lat = 0, lon = 0;
  219. for (var i = 0; i < total; i++) {
  220. lat += data[i].Lat * Math.PI / 180;
  221. lon += data[i].Lng * Math.PI / 180;
  222. }
  223. lat /= total;
  224. lon /= total;
  225. return [lon * 180 / Math.PI, lat * 180 / Math.PI];
  226. },
  227. // 计算多点的数学圆心
  228. calcCenter(data) {
  229. var total = data.length;
  230. var lat = 0, lon = 0;
  231. for (var i = 0; i < total; i++) {
  232. lat += data[i][0] * Math.PI / 180;
  233. lon += data[i][1] * Math.PI / 180;
  234. }
  235. lat /= total;
  236. lon /= total;
  237. return [lat * 180 / Math.PI, lon * 180 / Math.PI];
  238. }
  239. },
  240. async created() {
  241. // 已载入高德地图API,则直接初始化地图
  242. if (window.AMap && window.AMapUI) {
  243. this.initMap()
  244. // 未载入高德地图API,则先载入API再初始化
  245. } else {
  246. await remoteLoad(`http://webapi.amap.com/maps?v=1.3&key=${MapKey}`);
  247. await remoteLoad('http://webapi.amap.com/ui/1.0/main.js');
  248. this.initMap()
  249. }
  250. }
  251. }
  252. </script>
  253. <style scoped>
  254. .m-map {
  255. width: 100%;
  256. /*max-height: 317px;*/
  257. /*height: 317px;*/
  258. position: relative;
  259. }
  260. .m-map .map {
  261. width: 100%;
  262. height: 100%;
  263. }
  264. .m-map .search {
  265. position: absolute;
  266. top: 10px;
  267. left: 10px;
  268. width: 285px;
  269. z-index: 1;
  270. }
  271. .m-map .search input {
  272. width: 180px;
  273. border: 1px solid #ccc;
  274. line-height: 20px;
  275. padding: 5px;
  276. outline: none;
  277. }
  278. .m-map .search button {
  279. line-height: 26px;
  280. background: #fff;
  281. border: 1px solid #ccc;
  282. width: 50px;
  283. text-align: center;
  284. }
  285. .m-map .result {
  286. max-height: 300px;
  287. overflow: auto;
  288. margin-top: 10px;
  289. }
  290. /deep/ .green_point {
  291. margin: 16px;
  292. height: 16px;
  293. width: 16px;
  294. border-radius: 50% !important;
  295. display: inline-block;
  296. background-color: #1eff30;
  297. }
  298. /deep/ .yellow_point {
  299. margin: 16px;
  300. height: 16px;
  301. width: 16px;
  302. border-radius: 50% !important;
  303. display: inline-block;
  304. background-color: #f2ff24;
  305. }
  306. /deep/ .red_point {
  307. margin: 16px;
  308. height: 16px;
  309. width: 16px;
  310. border-radius: 50% !important;
  311. display: inline-block;
  312. transform: scale(0.5);
  313. animation: bulge 2s infinite ease-in-out;
  314. background-color: #ff0000;
  315. animation-delay: 0s;
  316. }
  317. /deep/ .red_point::after {
  318. position: absolute;
  319. display: inline-block;
  320. content: '';
  321. height: 100%;
  322. width: 100%;
  323. border-radius: 50%;
  324. background-color: inherit;
  325. top: 0;
  326. left: 0;
  327. z-index: -1;
  328. transform: scale(1);
  329. animation: blow 2s infinite ease-in-out;
  330. }
  331. /deep/ .point_name {
  332. position: relative;
  333. left: -30px;
  334. top: -15px;
  335. width: 100%;
  336. min-width: 90px;
  337. padding: 1px;
  338. text-align: center;
  339. background-color: rgb(26, 34, 41);
  340. border: 1px solid #060D16;
  341. border-radius: 10px !important;
  342. color: #eeeeee;
  343. display: block;
  344. overflow: hidden;
  345. opacity: 0.9;
  346. font-size: 12px;
  347. }
  348. @keyframes bulge {
  349. 50% {
  350. transform: scale(1);
  351. }
  352. }
  353. @keyframes blow {
  354. 25% {
  355. opacity: 0.4;
  356. }
  357. 50% {
  358. opacity: 0.1;
  359. }
  360. 90% {
  361. opacity: 0;
  362. }
  363. 100% {
  364. transform: scale(9);
  365. opacity: 0;
  366. }
  367. }
  368. </style>