Map.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. <!-- eslint-disable indent -->
  2. <script setup lang="ts">
  3. import { ref, onMounted, withDefaults } from "vue"
  4. import { getAssetPath } from "@/core/helpers/assets"
  5. //import DynamicTreeSelect from "@/components/select/DynamicTreeSelect.vue"
  6. import DySelectTree from "@/components/select/DySelectTree.vue"
  7. import AMapLoader from "@amap/amap-jsapi-loader"
  8. import { shallowRef } from "vue"
  9. import Rs from "@/core/services/RequestService"
  10. import { useRouter } from "vue-router"
  11. const router = useRouter()
  12. const props = withDefaults(defineProps<{ themeClass?: string }>(), {
  13. themeClass: "",
  14. })
  15. const map: any = shallowRef(null)
  16. const org_id = ref<string | null>(null)
  17. const name = ref("")
  18. const showCompanyList = ref(false)
  19. const companyList: any = ref([])
  20. const companyTotal = ref(0)
  21. const clist_loading = ref(false)
  22. const companySearch: {
  23. pageIndex: number
  24. pageSize: number
  25. params?: any
  26. } = {
  27. pageIndex: 1,
  28. pageSize: 100000,
  29. params: {
  30. org_id: "",
  31. name: "",
  32. },
  33. }
  34. const pagination = ref({
  35. curPage: 1,
  36. curPageSize: 10,
  37. curPageSizes: [10],
  38. curPagerCount: 10,
  39. })
  40. const mapMarkers: any = []
  41. let isInit = true
  42. let searchTimer: any = null
  43. const companyAreaChange = (data: any) => {
  44. org_id.value = data.id
  45. console.log("change")
  46. refreshCompany(1)
  47. }
  48. const companyNameChange = () => {
  49. refreshCompany(1)
  50. }
  51. const refreshCompany = (pageIndex: number, pageSize?: number) => {
  52. clearTimeout(Number(searchTimer))
  53. if (pageIndex) {
  54. //console.log("pageIndexChange", pageSize)
  55. pagination.value.curPage = pageIndex
  56. }
  57. if (pageSize) {
  58. //console.log("pageSizeChange", pageSize)
  59. pagination.value.curPageSize = pageSize
  60. }
  61. clist_loading.value = true
  62. searchTimer = setTimeout(getCompany, 200)
  63. }
  64. const getCompany = () => {
  65. if (org_id.value) {
  66. companySearch.params.org_id = org_id.value
  67. } else {
  68. delete companySearch.params.org_id
  69. }
  70. if (name.value) {
  71. companySearch.params.name = name.value
  72. } else {
  73. delete companySearch.params.name
  74. }
  75. companySearch.pageSize = pagination.value.curPageSize || 10
  76. companySearch.pageIndex = pagination.value.curPage || 1
  77. // Rs.post("sys/companyGis/getData", { data: companySearch }).then((res: any) => {
  78. // companyList.value = res.data
  79. // companyTotal.value = Number(res.total)
  80. // //console.log("companyList=====>", companyTotal.value, companyList.value)
  81. // renderMap()
  82. // })
  83. Rs.post("sys/query/getCompany", { data: companySearch, successAlert: false }).then((res: any) => {
  84. companyList.value = res.data
  85. companyTotal.value = Number(res.total)
  86. renderMap()
  87. clist_loading.value = false
  88. })
  89. setTimeout(() => {
  90. clist_loading.value = false
  91. }, 300)
  92. //Rs.get("sys/dict/getOrgList?type=1")
  93. }
  94. function initMap() {
  95. window._AMapSecurityConfig = {
  96. securityJsCode: "b815cb3bb6aa8516fcfe8c506abe9da2",
  97. }
  98. AMapLoader.load({
  99. key: "0da67b4ef98b3975eed48e8f8d42f9cd", // 申请好的Web端开发者Key,首次调用 load 时必填
  100. version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
  101. plugins: ["AMap.Scale", "AMap.HawkEye", "AMap.ToolBar", "AMap.ControlBar"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
  102. })
  103. .then((AMap: any) => {
  104. const _map = new AMap.Map("map-container", {
  105. //设置地图容器id
  106. viewMode: "3D", //是否为3D地图模式
  107. rotation: 45,
  108. pitch: 65,
  109. zoom: 10, //初始化地图级别
  110. })
  111. const scale = new AMap.Scale(),
  112. toolBar = new AMap.ToolBar({
  113. position: {
  114. top: "110px",
  115. right: "40px",
  116. },
  117. }),
  118. controlBar = new AMap.ControlBar({
  119. position: {
  120. top: "10px",
  121. right: "10px",
  122. },
  123. }),
  124. overView = new AMap.HawkEye({
  125. opened: false,
  126. })
  127. _map.addControl(scale)
  128. _map.addControl(toolBar)
  129. _map.addControl(controlBar)
  130. _map.addControl(overView)
  131. overView.hide()
  132. if (props.themeClass == "dark") {
  133. _map.setMapStyle("amap://styles/1f1485e5beb2382bd068587d161155a2")
  134. }
  135. map.value = _map
  136. getCompany()
  137. })
  138. .catch((e) => {
  139. console.log(e)
  140. })
  141. }
  142. const renderMap = () => {
  143. if (companyList.value && companyList.value.length) {
  144. companyList.value.forEach((item: any) => {
  145. renderMark(item)
  146. })
  147. if (isInit) {
  148. const { latitude, longitude } = companyList.value[0]
  149. if (latitude || longitude) {
  150. map.value.setZoomAndCenter(13, [longitude, latitude])
  151. }
  152. //document.getElementById("map-container").style.height = "100%";
  153. isInit = false
  154. }
  155. }
  156. //this.map.setFitView();
  157. }
  158. const renderMark = (item: any) => {
  159. const { latitude, longitude } = item
  160. if (!latitude && !longitude) {
  161. return
  162. }
  163. const infoWindow = new window.AMap.InfoWindow({
  164. isCustom: true,
  165. //anchor: "top-center",
  166. offset: new window.AMap.Pixel(0, -25),
  167. //content: "2", //getInfoBoxHtml(item), //传入 dom 对象,或者 html 字符串
  168. })
  169. infoWindow.on("open", function () {
  170. console.log("====>1")
  171. document.querySelector(".close-btn_info-box_20220615")?.addEventListener("click", function () {
  172. console.log("====>2")
  173. infoWindow.close()
  174. })
  175. })
  176. const oldMark = mapMarkers.find((a: any) => a.companyId == item.company_id)
  177. if (oldMark) {
  178. if (item.run_state == oldMark.state) {
  179. oldMark.infoWindow = infoWindow
  180. return
  181. }
  182. //删除状态变更的marker
  183. map.value.remove(oldMark.marker)
  184. mapMarkers.splice(
  185. mapMarkers.findIndex((a: any) => a.companyId == item.company_id),
  186. 1
  187. )
  188. // var allOverlay = this.map.getOverlays();
  189. // allOverlay.forEach((v) => {
  190. // if (v.id == item.company_id) {
  191. // this.map.removeOverlay(v);
  192. // }
  193. // });
  194. }
  195. const mkIcon = new window.AMap.Icon({
  196. size: new window.AMap.Size(35, 35),
  197. image: getAssetPath(
  198. item.run_state == 0 ? "media/screen/map/blue-location.png" : "media/screen/map/red-location.png"
  199. ),
  200. imageOffset: new window.AMap.Pixel(0, 0),
  201. imageSize: new window.AMap.Size(35, 35),
  202. })
  203. const marker = new window.AMap.Marker({
  204. position: new window.AMap.LngLat(item.longitude, item.latitude),
  205. offset: new window.AMap.Pixel(0, 1),
  206. icon: mkIcon, // 添加 Icon 实例
  207. anchor: "bottom-center",
  208. })
  209. marker.id = item.company_id
  210. map.value.add(marker)
  211. let timer: any
  212. marker.on("click", () => {
  213. clearTimeout(Number(timer))
  214. companyMarkOpen(item, false)
  215. })
  216. marker.on("mouseover", () => {
  217. clearTimeout(Number(timer))
  218. timer = setTimeout(() => {
  219. companyMarkOpen(item, false)
  220. }, 800)
  221. })
  222. marker.on("mouseout", () => {
  223. clearTimeout(timer)
  224. })
  225. mapMarkers.push({
  226. companyId: item.company_id,
  227. marker,
  228. infoWindow,
  229. state: item.run_state,
  230. })
  231. }
  232. const companyMarkOpen = (item: any, moveCenter?: boolean) => {
  233. mapMarkers.forEach((v: any) => {
  234. if (item && v.companyId == item.company_id) {
  235. Rs.post(`sys/query/getPurAndFanMonitor/${item.company_id}`).then((res: any) => {
  236. const content = getInfoBoxHtml(item, res.data)
  237. v.infoWindow.setContent(content)
  238. v.infoWindow.open(map.value, [item.longitude, item.latitude])
  239. if (moveCenter || moveCenter == undefined) {
  240. map.value.setZoomAndCenter(13, [item.longitude, Number(item.latitude) + 0.01])
  241. }
  242. })
  243. } else {
  244. v.infoWindow.close()
  245. }
  246. })
  247. }
  248. const getInfoBoxHtml = (item: any, monitorVo: any) => {
  249. console.log("monitorVo", monitorVo)
  250. console.log("item", item)
  251. function monitor() {
  252. let str = ""
  253. if (monitorVo.monitor1 && monitorVo.monitor1.length) {
  254. let i = 0
  255. monitorVo.monitor1.forEach((v: any) => {
  256. const vv = monitorVo.monitor2.length > i ? monitorVo.monitor2[i] : { statue: "未运行", time: "0" }
  257. str += `<div class="monitor monitor_${i + 1}" style="display:${i == 0 ? "flex" : "none"};">
  258. <div class="name" >
  259. <span style="width:100%;">${v.name}</span>
  260. </div>
  261. <div class="text" >
  262. <span style="width:100%;">净化器状态:${v.status}</span>
  263. <span style="width:100%;">运行时长:${v.time}</span>
  264. </div>
  265. <div class="splite" ></div>
  266. <div class="name" >
  267. <span style="width:100%;">${vv.name}</span>
  268. </div>
  269. <div class="text" >
  270. <span style="width:100%;">风机状态:${vv.status}</span>
  271. <span style="width:100%;">运行时长:${vv.time}</span>
  272. </div>
  273. </div>`
  274. i++
  275. })
  276. }
  277. return str
  278. }
  279. return `<div class="map-company-box">
  280. <div class="close-btn close-btn_info-box_20220615"></div>
  281. <div class="title-box">
  282. <div class="name" >
  283. <span>${item.name}</span>
  284. </div>
  285. <div class="address" >
  286. <span style="">详细地址:${item.address}</span>
  287. <span style="">企业负责人:${item.corporation_name}</span>
  288. </div>
  289. </div>
  290. <div class="monitor-box">
  291. ${monitor()}
  292. </div>
  293. <div class="page-box" data-page="1">
  294. <button class="left el-button el-button--default" type="button" disabled onclick="onCompanyMonitorScorl(this,0,${
  295. monitorVo.monitor1?.length
  296. })"><</button>
  297. <div class="mid" style=""><span class="cur-page">1</span><span style="marging:0 3px;">/</span>${
  298. monitorVo.monitor1.length
  299. }</div>
  300. <button class="right el-button el-button--default" type="button" style="" ${
  301. monitorVo.monitor1.length == 1 ? "disabled" : ""
  302. } onclick="onCompanyMonitorScorl(this,1,${monitorVo.monitor1.length})">></button>
  303. </div>
  304. <div class="btn-box" >
  305. <button type="button" class="el-button el-button--default" onclick="onCompanyDetail('${item.name}','${
  306. item.company_id
  307. }')">查看详情</button>
  308. </div>
  309. <div>
  310. </div>
  311. </div> `
  312. }
  313. const jumpCompanyDetail = (item: any) => {
  314. router.push({
  315. path: "/goLineData/oilFumeConcentration",
  316. query: {
  317. comName: item.name,
  318. company_id: item.company_id,
  319. back: 1,
  320. },
  321. })
  322. }
  323. onMounted(() => {
  324. initMap()
  325. window.onCompanyMonitorScorl = function (that: any, type: any, max: number) {
  326. const $this = that,
  327. $page = $this.closest(".page-box")
  328. const page = Number($page.dataset.page)
  329. const page2 = type ? page + 1 : page - 1
  330. if (page2 > max || page2 < 1) {
  331. return
  332. }
  333. $page.dataset.page = page2
  334. $page.querySelector(".cur-page").innerHTML = page2
  335. const $monitor = $page.previousElementSibling
  336. $monitor.querySelector(".monitor_" + page).style.display = "none"
  337. $monitor.querySelector(".monitor_" + page2).style.display = "flex"
  338. $page.querySelector(".left").disabled = page2 == 1
  339. $page.querySelector(".right").disabled = page2 == max
  340. }
  341. window.onCompanyDetail = function (name: string, company_id: string) {
  342. jumpCompanyDetail({
  343. name,
  344. company_id,
  345. })
  346. }
  347. })
  348. </script>
  349. <template>
  350. <div style="width: 100%; height: 100%; position: relative">
  351. <!-- <link rel="stylesheet" type="text/css" href="https://api.map.baidu.com/res/webgl/10/bmap.css"></link> -->
  352. <div class="map-container" id="map-container"></div>
  353. <div class="menu-container" id="menu-container">
  354. <div class="menu-box">
  355. <div class="menu" :class="showCompanyList ? 'active' : ''" @click="showCompanyList = !showCompanyList">
  356. 公司列表
  357. </div>
  358. </div>
  359. <div v-if="showCompanyList" class="company-list">
  360. <div class="close-btn" @click="showCompanyList = false"></div>
  361. <div class="input-group">
  362. <DySelectTree
  363. style="width: 48%"
  364. class="full-input"
  365. :url="'sys/dict/getOrgList?type=1'"
  366. v-model:value="org_id"
  367. :defaultExpandLevel="1"
  368. :option-map="{ id: 'value', label: 'label', children: 'children' }"
  369. placeholder="请选择区域..."
  370. @select="companyAreaChange"
  371. />
  372. <el-input
  373. @change="companyNameChange"
  374. style="width: 48%; height: 36px; border-radius: 5px"
  375. v-model="name"
  376. placeholder="输入企业名称"
  377. />
  378. </div>
  379. <div class="list-box" v-if="companyList.length > 0">
  380. <div class="clist_loading_box" v-if="clist_loading">
  381. <div class="spinner-border text-primary" role="status">
  382. <span class="visually-hidden">Loading...</span>
  383. </div>
  384. </div>
  385. <div class="company-item" v-for="(item, index) in companyList" :key="index">
  386. <img
  387. class="icon"
  388. :src="getAssetPath('media/screen/map/company.png')"
  389. alt=""
  390. @click="companyMarkOpen(item)"
  391. />
  392. <div class="text" @click="companyMarkOpen(item)">
  393. <span class="name">{{ item.name }}</span>
  394. <span class="address">{{ item.address }}</span>
  395. </div>
  396. <div class="btn">
  397. <el-button type="default" style="" class="lookDetal" @click="jumpCompanyDetail(item)">详情</el-button>
  398. </div>
  399. </div>
  400. <div v-if="companyTotal >= 0" style="float: right; margin: 10px 10px 5px 0">
  401. <el-pagination
  402. @size-change="(size:number) => refreshCompany(1, size)"
  403. background
  404. @current-change="refreshCompany"
  405. :current-page="pagination.curPage"
  406. :page-sizes="pagination.curPageSizes"
  407. :page-size="pagination.curPageSize"
  408. :pager-count="pagination.curPagerCount"
  409. layout="prev, pager, next"
  410. :total="companyTotal"
  411. ></el-pagination>
  412. </div>
  413. </div>
  414. <div class="list-box" v-if="companyList.length <= 0">
  415. <div style="color: #fff; font-size: 18px; width: 100%; text-align: center; padding: 10px">未查询到结果</div>
  416. </div>
  417. </div>
  418. </div>
  419. </div>
  420. </template>
  421. <style lang="scss" scoped>
  422. :deep(.el-pagination) {
  423. .el-pagination__sizes {
  424. display: none;
  425. }
  426. .el-pager > li.number,
  427. button {
  428. margin: 0 1px;
  429. width: 23px;
  430. min-width: 23px;
  431. height: 23px;
  432. }
  433. .el-pager > li.is-active {
  434. background-color: rgb(24, 28, 50);
  435. }
  436. }
  437. .clist_loading_box {
  438. width: 95%;
  439. height: 90%;
  440. position: absolute;
  441. display: flex;
  442. justify-content: center;
  443. align-items: center;
  444. background: rgba(159, 162, 184, 0.2);
  445. }
  446. </style>