MapBox.vue 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362
  1. <template>
  2. <div id="map" style="width: 100%; height: 100%">
  3. <div class="space-main" id="spaceMain">
  4. <div
  5. class="space-box"
  6. v-for="(area, index) in mapData.spaceList"
  7. :style="{
  8. width: area.width + 'px',
  9. height: area.height + 'px',
  10. top: area.top + 'px',
  11. left: area.left + 'px',
  12. }"
  13. :key="'map' + index"
  14. >
  15. <div
  16. class="space"
  17. :id="'space' + area.id"
  18. :class="[
  19. area.canClick ? '' : 'click-disable',
  20. selectArea.spaceId === area.spaceId
  21. ? area.disabled
  22. ? 'select-disable'
  23. : 'select'
  24. : '',
  25. isSetSpace ? 'use-select' : '',
  26. area.disabled ? 'space-disable-box' : 'space-box-bg',
  27. ]"
  28. @click.stop="checkSpace(area)"
  29. :style="{
  30. backgroundColor: area.backgroundColor ? area.backgroundColor : '',
  31. }"
  32. >
  33. <div
  34. class="device"
  35. :class="selectArea.spaceId === area.spaceId ? 'select-device' : ''"
  36. v-show="
  37. area.width * displacement.scale > 24 &&
  38. area.height * displacement.scale > 24
  39. "
  40. >
  41. <img
  42. :src="area.icon"
  43. v-if="selectArea.spaceId !== area.spaceId && area.icon"
  44. />
  45. <img :src="area.selectIcon" v-else class="select-icon" alt="" />
  46. <template v-if="area.localName">
  47. <span
  48. v-if="
  49. (area.height > 80 &&
  50. area.localName.length * 12 < area.width) ||
  51. selectArea.spaceId === area.spaceId
  52. "
  53. style="font-size: 12px"
  54. >{{ area.localName }}</span
  55. >
  56. </template>
  57. </div>
  58. <!-- <div class="circle" v-else :style="{backgroundColor: area.circleColor?area.circleColor:''}"></div>-->
  59. </div>
  60. </div>
  61. </div>
  62. <!--地图右侧的操作按钮-->
  63. <div class="map-toolbar">
  64. <img
  65. :src="parseImgUrl('map-icon', 'icon-search-big.svg')"
  66. @click.stop="goSearch"
  67. class="icon-search"
  68. alt=""
  69. />
  70. <div class="toolbar-item" @click.stop="checkFloor">
  71. <span class="text-hidden">{{ floorItem.localName }}</span>
  72. </div>
  73. <div class="toolbar-item" @click.stop="checkBuilding">
  74. <span class="text-hidden">{{ buildingItem.localName }}</span>
  75. </div>
  76. <!-- <div class="toolbar-item">-->
  77. <!-- <img src="../../assets/images/map-icon/icon-floor-arrow.svg" alt="">-->
  78. <!-- </div>-->
  79. </div>
  80. <!-- 选择建筑 -->
  81. <van-popup
  82. v-model:show="showBuilding"
  83. teleport="body"
  84. class="buiding-box"
  85. style="width: 40%; height: 100%; padding: 20px"
  86. position="right"
  87. >
  88. <div
  89. class="buiding-item"
  90. :key="item.id"
  91. :class="buildingItem.buildingId === item.id ? 'active' : ''"
  92. @click.stop="comfirmBuilding(item)"
  93. v-for="item in buildingData"
  94. >
  95. {{ item.localName }}
  96. </div>
  97. </van-popup>
  98. <!-- 选择楼层 -->
  99. <van-popup
  100. v-model:show="showFloor"
  101. teleport="body"
  102. class="buiding-box"
  103. style="width: 40%; height: 100%; padding: 20px"
  104. position="right"
  105. >
  106. <div
  107. class="buiding-item"
  108. :key="item.id"
  109. :class="floorItem.id === item.id ? 'active' : ''"
  110. @click.stop="comfirmFloor(item)"
  111. v-for="item in floorData"
  112. >
  113. {{ item.localName }}
  114. </div>
  115. </van-popup>
  116. <!--搜索-->
  117. <van-popup
  118. v-model:show="showSearch"
  119. teleport="body"
  120. class="buiding-box"
  121. style="width: 100%; height: 100%"
  122. position="right"
  123. >
  124. <div style="width: 100%; height: 100%">
  125. <space-search @closeSearch="closeSearch"></space-search>
  126. </div>
  127. </van-popup>
  128. </div>
  129. </template>
  130. <script lang="ts">
  131. import {
  132. defineComponent,
  133. onMounted,
  134. nextTick,
  135. reactive,
  136. toRefs,
  137. watch,
  138. } from "vue";
  139. import {
  140. getLocalStorageFloor,
  141. getStorageSpaceId,
  142. localStorageFloor,
  143. localStorageSpaceId,
  144. parseImgUrl,
  145. setLocalNewSpaceInfo,
  146. } from "@/utils";
  147. import { Toast, Dialog } from "vant";
  148. import { getBuildingList, getFloorList, getMapInfo } from "@/apis/envmonitor";
  149. import SpaceSearch from "@/views/envmonitor/Search/SpaceSearch.vue";
  150. import { useRouter } from "vue-router";
  151. import { getSpaceType, mapIcon } from "@/utils/mapIcon";
  152. import any = jasmine.any;
  153. export default defineComponent({
  154. props: {
  155. projectId: {
  156. type: String,
  157. default: () => "",
  158. },
  159. spaceData: {
  160. type: Array,
  161. default: () => [],
  162. },
  163. spaceInfo: {
  164. type: Object,
  165. default: () => {},
  166. },
  167. isSetSpace: {
  168. type: Boolean,
  169. default: () => false,
  170. },
  171. floorId: {
  172. type: String,
  173. default: () => "",
  174. },
  175. buildingId: {
  176. type: String,
  177. default: () => "",
  178. },
  179. },
  180. components: {
  181. SpaceSearch,
  182. },
  183. setup(props, contx) {
  184. const router = useRouter();
  185. const mapData: any = {};
  186. const document: any = window.document;
  187. const screenInfo: any = {
  188. screenWidth: document.body.clientWidth,
  189. screenHeight: document.body.clientHeight,
  190. };
  191. const comMapScale: any = 0.8;
  192. const displacement: any = {
  193. scale: 1,
  194. pageX: 0,
  195. pageX2: 0,
  196. originScale: 0,
  197. moveable: false,
  198. };
  199. let buildingData: any = [];
  200. let floorData: any = [];
  201. let floorItem: any = {};
  202. let selectArea: any = {};
  203. let transformData: any = {};
  204. let spaceInfo: any = null;
  205. const proxyData = reactive({
  206. parseImgUrl: parseImgUrl,
  207. spaceInfo: spaceInfo,
  208. isSetSpace: props.isSetSpace, // isSetSpace:true 代表为设置常驻空间页面展示
  209. widthMapScale: 1,
  210. tempScale: 0.8,
  211. comMapScale: comMapScale,
  212. heightScale: 1,
  213. showSearch: false,
  214. isSetSearchSpace: false,
  215. showBuilding: false,
  216. showFloor: false,
  217. buildingItem: {
  218. buildingId: "",
  219. localName: "",
  220. },
  221. floorData: floorData,
  222. floorItem: floorItem,
  223. buildingData: buildingData,
  224. mapData: mapData,
  225. copyMapDaata: mapData,
  226. selectArea: selectArea,
  227. displacement: displacement,
  228. screenInfo: screenInfo,
  229. transformData: transformData,
  230. // 切换楼层的时候恢缩放和滚动的样式
  231. clearPreStyle() {
  232. let mapDom = document.querySelector("#map");
  233. mapDom.scrollLeft = 0;
  234. mapDom.scrollTop = 0;
  235. let matrix_box: any = document.querySelector("#spaceMain");
  236. // 记住使用的缩放值
  237. proxyData.displacement.scale = 1;
  238. if (matrix_box) {
  239. matrix_box.style.left = 0 + "px";
  240. matrix_box.style.top = 0 + "px";
  241. }
  242. },
  243. swipe(el: any, options: any) {
  244. //设置开关,监听move事件
  245. let isMove: any = false;
  246. // 设置手指触摸开始的坐标
  247. let startX: any = 0;
  248. let startY: any = 0;
  249. // 设置手指移动的坐标
  250. let moveX: any = 0;
  251. let moveY: any = 0;
  252. //设置指针距离元素的边框的距离
  253. let disX: any = 0;
  254. let disY: any = 0;
  255. // 如果用户未传入参数2,自己定义一个
  256. let fun: any = function () {};
  257. let data: any = {
  258. swipeLeft: fun,
  259. swipeRight: fun,
  260. swipeDown: fun,
  261. swipeUp: fun,
  262. drag: fun,
  263. };
  264. // 判断是否传入参数2,有的话覆盖默认值
  265. Object.assign(data, options);
  266. // 给元素绑定三个事件
  267. el.addEventListener(
  268. "touchstart",
  269. function (e: any) {
  270. console.log(e);
  271. //获取手指开始的坐标
  272. startX = e.touches[0].pageX;
  273. startY = e.touches[0].pageY;
  274. //计算指针距离元素边框的位置
  275. disX = startX - el.offsetLeft;
  276. disY = startY - el.offsetTop;
  277. console.log( el.offsetLeft)
  278. console.log(el.offsetTop)
  279. console.log(e.touches[0].pageX)
  280. },
  281. { passive: true }
  282. );
  283. el.addEventListener(
  284. "touchmove",
  285. function (e: any) {
  286. if (proxyData.displacement.moveable) {
  287. return;
  288. }
  289. console.log(e);
  290. //如果触发了move事件,打开开关
  291. isMove = true;
  292. // 获取移动时的坐标
  293. moveX = e.touches[0].pageX;
  294. moveY = e.touches[0].pageY;
  295. e.mation = {
  296. startX: startX,
  297. startY: startY,
  298. moveX: moveX,
  299. moveY: moveY,
  300. disX: disX,
  301. disY: disY,
  302. };
  303. data.drag.call(el, e);
  304. // 判断是否触发了move事件
  305. if (isMove) {
  306. // 计算水平边长
  307. let absX: any = Math.abs(moveX - startX);
  308. // 计算垂直边长
  309. let absY: any = Math.abs(moveY - startY);
  310. // 判断垂直还是水平滑动
  311. if (absX > absY) {
  312. // console.log('水平滑动');
  313. //再判断是左滑右滑
  314. if (moveX - startX > 0) {
  315. data.swipeRight.call(el, e);
  316. } else {
  317. data.swipeLeft.call(el, e);
  318. }
  319. } else {
  320. // console.log('垂直滑动');
  321. //判断是上滑还是下滑
  322. if (moveY - startX > 0) {
  323. // 下滑
  324. data.swipeDown.call(el, e);
  325. } else {
  326. data.swipeUp.call(el, e);
  327. }
  328. }
  329. }
  330. },
  331. { passive: true }
  332. );
  333. el.addEventListener("touchend", function (e: any) {
  334. isMove = false;
  335. });
  336. },
  337. /**
  338. * 地图滚动
  339. */
  340. mapScroll() {
  341. let matrix_box: any = document.querySelector("#spaceMain");
  342. let houseDesDom = document.querySelector("#houseDes");
  343. let houseHeight: any = houseDesDom ? houseDesDom.offsetHeight : 0;
  344. proxyData.swipe(matrix_box, {
  345. swipeLeft: function (e: any) {
  346. if (!proxyData.displacement.moveable) {
  347. if (matrix_box.offsetWidth < proxyData.screenInfo.screenWidth) {
  348. } else {
  349. let width: any =
  350. matrix_box.offsetWidth -
  351. Math.abs(e.touches[0].pageX - e.mation.disX);
  352. if (width < proxyData.screenInfo.screenWidth) {
  353. matrix_box.style.left =
  354. -(
  355. matrix_box.offsetWidth - proxyData.screenInfo.screenWidth
  356. ) + "px";
  357. } else {
  358. matrix_box.style.left =
  359. e.touches[0].pageX - e.mation.disX + "px";
  360. }
  361. }
  362. }
  363. },
  364. swipeRight: function (e: any) {
  365. if (!proxyData.displacement.moveable) {
  366. if (matrix_box.offsetWidth < proxyData.screenInfo.screenWidth) {
  367. return;
  368. }
  369. if (e.touches[0].pageX - e.mation.disX > 0) {
  370. matrix_box.style.left = 0 + "px";
  371. } else {
  372. matrix_box.style.left =
  373. e.touches[0].pageX - e.mation.disX + "px";
  374. }
  375. }
  376. },
  377. swipeDown: function (e: any) {
  378. if (!proxyData.displacement.moveable) {
  379. let height: any =
  380. proxyData.screenInfo.screenHeight - houseHeight - 20;
  381. let boxHeight: any = matrix_box.offsetHeight;
  382. if (boxHeight < height) {
  383. matrix_box.style.top = 0 + "px";
  384. } else {
  385. if (e.touches[0].pageY - e.mation.disY > 0) {
  386. matrix_box.style.top = 0 + "px";
  387. } else {
  388. matrix_box.style.top =
  389. e.touches[0].pageY - e.mation.disY + "px";
  390. }
  391. }
  392. }
  393. },
  394. swipeUp: function (e: any) {
  395. if (!proxyData.displacement.moveable) {
  396. let houseDesDom = document.querySelector("#houseDes");
  397. let houseHeight: any = houseDesDom ? houseDesDom.offsetHeight : 0;
  398. let height: any =
  399. proxyData.screenInfo.screenHeight - houseHeight - 20;
  400. let boxHeight: any = matrix_box.offsetHeight;
  401. let top: any = e.touches[0].pageY - e.mation.disY;
  402. if (boxHeight < height) {
  403. matrix_box.style.top = 0 + "px";
  404. } else {
  405. if (boxHeight - Math.abs(top) < height / 2) {
  406. matrix_box.style.top = -(boxHeight - height / 2) + "px";
  407. } else {
  408. matrix_box.style.top =
  409. e.touches[0].pageY - e.mation.disY + "px";
  410. }
  411. }
  412. }
  413. },
  414. drag: function (e: any) {},
  415. });
  416. },
  417. /**
  418. * 关闭搜索页面
  419. * @param item
  420. */
  421. closeSearch(item: any) {
  422. proxyData.showSearch = false;
  423. // 搜索页面过来的
  424. if (item) {
  425. proxyData.isSetSearchSpace = true;
  426. proxyData.loadingStart();
  427. let searchSpace: any = {
  428. buildingId: item.buildingId,
  429. buildingName: "",
  430. floorId: item.floorId,
  431. floorName: "",
  432. spaceId: item.id,
  433. };
  434. proxyData.init(searchSpace);
  435. } else {
  436. proxyData.isSetSearchSpace = false;
  437. }
  438. },
  439. /*
  440. 去搜索页面
  441. */
  442. goSearch() {
  443. proxyData.showSearch = true;
  444. // router.push({ path: '/search' })
  445. },
  446. /**
  447. * 设置选中的空间的位置,
  448. */
  449. setSelectSpacePosition(area: any) {
  450. setTimeout(() => {
  451. proxyData.setScrollLeft(area);
  452. proxyData.scrollTop(area);
  453. });
  454. },
  455. /**
  456. * 判断像左还是像右滚动
  457. */
  458. setScrollLeft(area: any) {
  459. let mapBoxEle = document.querySelector("#spaceMain");
  460. let left: any = 0;
  461. if (area.left + area.width >= proxyData.screenInfo.screenWidth / 2) {
  462. left =
  463. area.left - proxyData.screenInfo.screenWidth / 2 + area.width / 2;
  464. left = ~left;
  465. } else {
  466. left = 0;
  467. }
  468. if (left > 0) {
  469. left = 0;
  470. }
  471. if (
  472. Math.abs(left) >
  473. mapBoxEle.offsetWidth - proxyData.screenInfo.screenWidth
  474. ) {
  475. left = -(mapBoxEle.offsetWidth - proxyData.screenInfo.screenWidth);
  476. }
  477. mapBoxEle.style.left = left + "px";
  478. },
  479. /**
  480. * 获取竖着的方向
  481. */
  482. scrollTop(area: any) {
  483. let mapDom = document.querySelector("#map");
  484. let mapBoxEle = document.querySelector("#spaceMain");
  485. let houseDesDom = document.querySelector("#houseDes");
  486. let houseHeight: any = houseDesDom ? houseDesDom.offsetHeight : 0;
  487. let top: any = 0;
  488. if (
  489. area.top + area.width >
  490. (proxyData.screenInfo.screenHeight - houseHeight - 20) / 2
  491. ) {
  492. top =
  493. area.top -
  494. (proxyData.screenInfo.screenHeight - houseHeight) / 2 +
  495. area.height / 2;
  496. } else {
  497. top = 0;
  498. }
  499. top = ~top;
  500. if (top > 0) {
  501. top = 0;
  502. }
  503. mapBoxEle.style.top = top + "px";
  504. },
  505. /**
  506. * 切换空间
  507. */
  508. checkSpace(area: any) {
  509. if (area.disabled) {
  510. // 如果不在
  511. Toast("该空间和平板没绑定,暂不支持查看");
  512. return;
  513. }
  514. proxyData.isSetSearchSpace = false;
  515. if (area && area.canClick) {
  516. proxyData.setSelectSpacePosition(area);
  517. proxyData.selectArea = area;
  518. proxyData.selectArea.buildingId = proxyData.buildingItem.buildingId;
  519. proxyData.setLocalSpaceInfo();
  520. contx.emit("changeSpace", proxyData.selectArea);
  521. } else {
  522. Toast("不可选区域");
  523. }
  524. },
  525. /**
  526. * 确认设置为常驻空间
  527. */
  528. comfirSetSpace(item: any) {
  529. if (item.spaceId === props.spaceInfo.spaceId) {
  530. Dialog.confirm({
  531. title: "取消常驻空间",
  532. confirmButtonColor: "#000000",
  533. cancelButtonColor: "#4D5262",
  534. message: `
  535. 是否取消常驻空间设置 ? `,
  536. })
  537. .then(() => {
  538. contx.emit("delPermanentSpace");
  539. })
  540. .catch(() => {});
  541. } else {
  542. Dialog.confirm({
  543. title: "设置常驻空间",
  544. confirmButtonColor: "#000000",
  545. cancelButtonColor: "#4D5262",
  546. message: `是否将常驻空间设置为${item.localName}?`,
  547. })
  548. .then(() => {
  549. proxyData.selectArea = item;
  550. contx.emit("changeSpaceId", proxyData.selectArea.spaceId);
  551. })
  552. .catch(() => {});
  553. }
  554. },
  555. /**
  556. * 本地缓存最新的空间建筑信息,提供给首次进入页面使用
  557. */
  558. setLocalSpaceInfo() {
  559. localStorageSpaceId(
  560. proxyData.buildingItem.buildingId,
  561. proxyData.floorItem.id,
  562. proxyData.selectArea.spaceId
  563. );
  564. let spaceInfo: any = {
  565. buildingId: proxyData.buildingItem.buildingId,
  566. buildingName: proxyData.buildingItem.localName,
  567. floorId: proxyData.floorItem.id,
  568. floorName: proxyData.floorItem.localName,
  569. spaceId: proxyData.selectArea.spaceId, // 上格云3
  570. };
  571. setLocalNewSpaceInfo(spaceInfo);
  572. },
  573. /**
  574. * 地图放大的距离
  575. * @param start
  576. * @param stop
  577. */
  578. getDistance(start: any, stop: any) {
  579. return Math.hypot(stop.x - start.x, stop.y - start.y);
  580. },
  581. /**
  582. * 格式化地图数据
  583. */
  584. formateMapData() {
  585. let spaceData: any = props.spaceData;
  586. let data: any = proxyData.mapData;
  587. if (data) {
  588. proxyData.setSpaceScale();
  589. proxyData.setTempScale();
  590. if (data.width < 3000) {
  591. proxyData.comMapScale = 0.8;
  592. }
  593. data.width = data.width * proxyData.comMapScale;
  594. data.height = data.height * proxyData.comMapScale;
  595. let spaceList: any = data?.spaceList ?? [];
  596. for (let i = 0; i < spaceList.length; i++) {
  597. let item = spaceList[i];
  598. item.width = item.width * proxyData.comMapScale;
  599. item.height = item.height * proxyData.comMapScale;
  600. item.top = item.top * proxyData.comMapScale;
  601. item.left = item.left * proxyData.comMapScale;
  602. let flag: any = true;
  603. for (let j = 0; j < spaceData.length; j++) {
  604. if (item.spaceId === spaceData[j].spaceId) {
  605. flag = false;
  606. break;
  607. }
  608. }
  609. if (flag) {
  610. item.disabled = true;
  611. }
  612. // item.canClick = !item.canClick
  613. proxyData.setSpaceIcon(item);
  614. }
  615. // console.log(" proxyData.mapData proxyData.mapData");
  616. // console.log(proxyData.mapData);
  617. // 备份数据
  618. proxyData.copyMapDaata = JSON.parse(JSON.stringify(data));
  619. }
  620. },
  621. // 获取空间最小宽
  622. setSpaceScale() {
  623. let data: any = proxyData.mapData;
  624. if (data) {
  625. let spaceList: any = data?.spaceList ?? [];
  626. let minHeight: any = Math.min.apply(
  627. null,
  628. spaceList.map((item: any) => item.height)
  629. );
  630. let minWidth: any = Math.min.apply(
  631. null,
  632. spaceList.map((item: any) => item.width)
  633. );
  634. let min: any = minHeight < minWidth ? minHeight : minWidth;
  635. min = min ? min : 30;
  636. proxyData.comMapScale = 30 / min;
  637. }
  638. },
  639. // 缩放的临界值修改
  640. setTempScale() {
  641. proxyData.tempScale = 0.4;
  642. let data: any = proxyData.mapData;
  643. if (data) {
  644. let width: any = proxyData.mapData.width;
  645. let height: any = proxyData.mapData.height;
  646. if (width > height) {
  647. let num: any = Math.ceil(width / proxyData.screenInfo.screenWidth);
  648. if (num < 10) {
  649. proxyData.tempScale = 0.4;
  650. } else if (num < 20) {
  651. proxyData.tempScale = 0.3;
  652. } else {
  653. proxyData.tempScale = 0.25;
  654. }
  655. } else {
  656. let num: any = Math.ceil(
  657. height / proxyData.screenInfo.screenHeight
  658. );
  659. if (num < 10) {
  660. proxyData.tempScale = 0.4;
  661. } else if (num < 20) {
  662. proxyData.tempScale = 0.3;
  663. } else {
  664. proxyData.tempScale = 0.25;
  665. }
  666. }
  667. }
  668. },
  669. /**
  670. * 设置地图最外框宽和高
  671. */
  672. setMapBoxStyle() {
  673. let mapBoxEle = document.querySelector("#spaceMain");
  674. if (proxyData.mapData && proxyData.mapData.width) {
  675. mapBoxEle.style.width = proxyData.mapData.width + "px";
  676. mapBoxEle.style.height = proxyData.mapData.height + "px";
  677. }
  678. },
  679. /**
  680. * 设置空间的图标
  681. *
  682. */
  683. setSpaceIcon(item: any) {
  684. // if(item.can)
  685. if (item.canClick) {
  686. let typeName: any = getSpaceType(item.roomFuncType);
  687. item.icon = mapIcon[typeName].icon;
  688. item.selectIcon = mapIcon[typeName].selectIcon;
  689. item.backgroundColor = mapIcon[typeName].backgroundColor;
  690. item.bg = mapIcon[typeName].bg;
  691. item.icon = parseImgUrl("map-new-icon", item.icon);
  692. item.selectIcon = parseImgUrl("map-new-icon", item.selectIcon);
  693. } else {
  694. item.icon = "";
  695. }
  696. },
  697. midpoint(x1: any, y1: any, x2: any, y2: any) {
  698. return [x1 + (x2 - x1) / 2, y1 + (y2 - y1) / 2];
  699. // return [x1 + x2 / 2, y1 + (y2 - y1)]
  700. },
  701. /**
  702. * 更新地图的宽高
  703. */
  704. updateMapStyle() {
  705. let data: any = JSON.parse(JSON.stringify(proxyData.copyMapDaata));
  706. if (data) {
  707. data.width = data.width * proxyData.displacement.scale;
  708. data.height = data.height * proxyData.displacement.scale;
  709. let spaceList: any = data?.spaceList ?? [];
  710. for (let i = 0; i < spaceList.length; i++) {
  711. let item = spaceList[i];
  712. item.width = item.width * proxyData.displacement.scale;
  713. item.height = item.height * proxyData.displacement.scale;
  714. item.top = item.top * proxyData.displacement.scale;
  715. item.left = item.left * proxyData.displacement.scale;
  716. }
  717. proxyData.mapData = data;
  718. proxyData.setMapBoxStyle();
  719. }
  720. },
  721. /**
  722. * 更新地图的位置
  723. */
  724. updateMapPositon(temp: any, matrix_box: any) {
  725. // let left: any = (proxyData.displacement.oldSize[0] - proxyData.displacement.oldSize[0] * proxyData.displacement.scale) * proxyData.displacement.scaleTranslateProportion[0]
  726. // let top: any = (proxyData.displacement.oldSize[1] - proxyData.displacement.oldSize[1] * proxyData.displacement.scale) * proxyData.displacement.scaleTranslateProportion[1]
  727. let left: any =
  728. proxyData.displacement.scaleCenter[0] -
  729. proxyData.displacement.scaleCenter[0] * proxyData.displacement.scale;
  730. let top: any =
  731. proxyData.displacement.scaleCenter[1] -
  732. proxyData.displacement.scaleCenter[1] * proxyData.displacement.scale;
  733. if (temp > 0 && proxyData.displacement.scale < 1) {
  734. if (left > 0) {
  735. left = ~left;
  736. }
  737. if (top > 0) {
  738. top = ~top;
  739. // top = 0
  740. }
  741. }
  742. let newTop: any =
  743. proxyData.displacement.top * proxyData.displacement.scale + top;
  744. let newLeft: any =
  745. proxyData.displacement.left * proxyData.displacement.scale + left;
  746. if (matrix_box.offsetWidth < proxyData.screenInfo.screenWidth) {
  747. newLeft = 0;
  748. }
  749. if (newLeft > 0) {
  750. matrix_box.style.left = 0 + "px";
  751. } else {
  752. matrix_box.style.left = newLeft + "px";
  753. }
  754. if (matrix_box.offsetHeight < proxyData.screenInfo.screenHeight) {
  755. matrix_box.style.top = 0;
  756. } else {
  757. if (newTop > 0) {
  758. matrix_box.style.top = 0;
  759. } else {
  760. matrix_box.style.top = newTop + "px";
  761. }
  762. }
  763. },
  764. /**
  765. * 地图缩放功能
  766. */
  767. mapScale() {
  768. let matrix_box: any = document.querySelector("#spaceMain");
  769. matrix_box.addEventListener(
  770. "touchstart",
  771. function (event: any) {
  772. let touches: any = event.touches;
  773. let events: any = touches[0];
  774. let events2: any = touches[1];
  775. // 第一个触摸点的坐标
  776. proxyData.displacement.pageX = events.pageX;
  777. proxyData.displacement.pageY = events.pageY;
  778. proxyData.displacement.moveable = true;
  779. proxyData.displacement.originScale =
  780. proxyData.displacement.scale || 1;
  781. if (events2) {
  782. proxyData.displacement.pageX2 = events2.pageX;
  783. proxyData.displacement.pageY2 = events2.pageY;
  784. let left: any = isNaN(parseInt(matrix_box.style.left))
  785. ? 0
  786. : parseInt(matrix_box.style.left);
  787. let top: any = isNaN(parseInt(matrix_box.style.top))
  788. ? 0
  789. : parseInt(matrix_box.style.top);
  790. proxyData.displacement.center = proxyData.midpoint(
  791. events.pageX,
  792. events.pageY,
  793. events2.pageX,
  794. events2.pageY
  795. );
  796. proxyData.displacement.left = left / proxyData.displacement.scale;
  797. proxyData.displacement.top = top / proxyData.displacement.scale;
  798. proxyData.displacement.scaleCenter = [
  799. proxyData.displacement.center[0] / proxyData.displacement.scale,
  800. proxyData.displacement.center[1] / proxyData.displacement.scale,
  801. ];
  802. proxyData.displacement.scaleTranslateProportion = [
  803. proxyData.displacement.scaleCenter[0] /
  804. (matrix_box.offsetWidth / proxyData.displacement.scale),
  805. proxyData.displacement.scaleCenter[1] /
  806. (matrix_box.offsetHeight / proxyData.displacement.scale),
  807. ];
  808. proxyData.displacement.oldSize = [
  809. matrix_box.offsetWidth / proxyData.displacement.scale,
  810. matrix_box.offsetHeight / proxyData.displacement.scale,
  811. ];
  812. } else {
  813. proxyData.displacement.moveable = false;
  814. }
  815. },
  816. { passive: true }
  817. );
  818. matrix_box.addEventListener(
  819. "touchmove",
  820. function (event: any) {
  821. if (!proxyData.displacement.moveable) {
  822. return;
  823. }
  824. // event.preventDefault();
  825. let touches: any = event.touches;
  826. let events: any = touches[0];
  827. let events2: any = touches[1];
  828. // 双指移动
  829. if (events2) {
  830. // 第2个指头坐标在touchmove时候获取
  831. if (!proxyData.displacement.pageX2) {
  832. proxyData.displacement.pageX2 = events2.pageX;
  833. }
  834. if (!proxyData.displacement.pageY2) {
  835. proxyData.displacement.pageY2 = events2.pageY;
  836. }
  837. // 双指缩放比例计算
  838. let zoom: any =
  839. proxyData.getDistance(
  840. {
  841. x: events.pageX,
  842. y: events.pageY,
  843. },
  844. {
  845. x: events2.pageX,
  846. y: events2.pageY,
  847. }
  848. ) /
  849. proxyData.getDistance(
  850. {
  851. x: proxyData.displacement.pageX,
  852. y: proxyData.displacement.pageY,
  853. },
  854. {
  855. x: proxyData.displacement.pageX2,
  856. y: proxyData.displacement.pageY2,
  857. }
  858. );
  859. // 应用在元素上的缩放比例
  860. let newScale: any = proxyData.displacement.originScale * zoom;
  861. if (newScale < proxyData.tempScale) {
  862. newScale = proxyData.tempScale;
  863. }
  864. // 最大缩放比例限制
  865. if (newScale > 1.5) {
  866. newScale = 1.5;
  867. }
  868. let temp: any = newScale - proxyData.displacement.scale;
  869. proxyData.displacement.scale = newScale;
  870. if (temp !== 0) {
  871. proxyData.updateMapPositon(temp, matrix_box);
  872. proxyData.updateMapStyle();
  873. }
  874. }
  875. },
  876. { passive: true }
  877. );
  878. matrix_box.addEventListener("touchend", function () {
  879. proxyData.displacement.moveable = true;
  880. });
  881. },
  882. /**
  883. * 获取建筑信息
  884. */
  885. getBuildingList() {
  886. let params: any = {
  887. criteria: {
  888. projectId: props.projectId,
  889. },
  890. orders: [
  891. {
  892. asc: true,
  893. column: "localId",
  894. },
  895. ],
  896. };
  897. getBuildingList(params).then((res) => {
  898. let resData: any = res;
  899. if (resData.result === "success") {
  900. let content: any = resData?.content ?? [];
  901. proxyData.buildingData = content;
  902. // 设置展示的建筑名称
  903. proxyData.setBuildingName();
  904. }
  905. });
  906. },
  907. /**
  908. *
  909. * 选择建筑
  910. */
  911. checkBuilding() {
  912. proxyData.showBuilding = true;
  913. },
  914. /**
  915. * 选择楼层
  916. */
  917. checkFloor() {
  918. proxyData.showFloor = true;
  919. },
  920. /**
  921. * 确定选择的楼层信息
  922. */
  923. comfirmFloor(item: any, flag: boolean = true) {
  924. proxyData.floorItem = item;
  925. proxyData.showFloor = false;
  926. // 获取地图数据
  927. proxyData.loadingStart();
  928. proxyData.getMapInfo(flag);
  929. /**
  930. *缓存建筑对应的楼层
  931. */
  932. localStorageFloor(
  933. proxyData.buildingItem.buildingId,
  934. proxyData.floorItem.id
  935. );
  936. },
  937. /**
  938. * 确定建筑
  939. */
  940. comfirmBuilding(item: any) {
  941. proxyData.showBuilding = false;
  942. proxyData.buildingItem.buildingId = item.id;
  943. proxyData.buildingItem.localName = item.localName;
  944. proxyData.loadingStart();
  945. proxyData.getFloorList();
  946. },
  947. /**
  948. * 加载loading
  949. */
  950. loadingStart() {
  951. Toast.loading({
  952. duration: 0, // 持续展示 toast
  953. forbidClick: true,
  954. message: "加载中...",
  955. });
  956. },
  957. /**
  958. * 结束
  959. */
  960. loadinngEnd() {
  961. Toast.clear();
  962. },
  963. /**
  964. * 查询楼层信息
  965. */
  966. getFloorList(flag: boolean = true) {
  967. if (proxyData.buildingItem.buildingId) {
  968. let params: any = {
  969. criteria: {
  970. projectId: props.projectId,
  971. buildingId: proxyData.buildingItem.buildingId,
  972. },
  973. orders: [
  974. {
  975. asc: true,
  976. column: "localId",
  977. },
  978. ],
  979. };
  980. getFloorList(params)
  981. .then((res) => {
  982. let resData: any = res;
  983. if (res.result === "success") {
  984. proxyData.floorData = resData?.content ?? [];
  985. // 设置楼层的名称
  986. proxyData.setFloorName();
  987. } else {
  988. proxyData.floorData = [];
  989. }
  990. if (flag && proxyData.floorData.length) {
  991. proxyData.getHistorySelectFloor();
  992. proxyData.getMapInfo();
  993. }
  994. proxyData.loadinngEnd();
  995. })
  996. .catch(() => {
  997. proxyData.loadinngEnd();
  998. });
  999. }
  1000. },
  1001. /**
  1002. * 获取地图信息
  1003. */
  1004. getMapInfo(flag: boolean = true, searchItem: any = null) {
  1005. let params: any = {
  1006. projectId: props.projectId,
  1007. floorId: proxyData.floorItem.id,
  1008. };
  1009. getMapInfo(params)
  1010. .then((res) => {
  1011. let resData: any = res;
  1012. // debugger;
  1013. if (resData.result === "success") {
  1014. proxyData.mapData = resData?.data ?? null;
  1015. // 切换数据的时候清楚默认样式
  1016. proxyData.clearPreStyle();
  1017. proxyData.formateMapData();
  1018. // 首次进入页面的时候展示空间来源于父div
  1019. if (searchItem) {
  1020. let area = proxyData.getFirstSelectSpace(searchItem);
  1021. // debugger
  1022. if (area) {
  1023. proxyData.selectArea = area;
  1024. }
  1025. }
  1026. proxyData.setSelectSpacePosition(proxyData.selectArea);
  1027. // 接口返回后设置地图缩放和滚动
  1028. nextTick(() => {
  1029. // 地图双指缩放
  1030. proxyData.setMapBoxStyle();
  1031. proxyData.mapScale();
  1032. proxyData.mapScroll();
  1033. });
  1034. }
  1035. // setTimeout(() => {
  1036. // proxyData.loadinngEnd()
  1037. // }, 1000)
  1038. })
  1039. .catch(() => {
  1040. proxyData.loadinngEnd();
  1041. });
  1042. },
  1043. /**
  1044. * 获取缓存的楼层
  1045. */
  1046. getHistorySelectFloor() {
  1047. let historyFloor: any = getLocalStorageFloor();
  1048. let flag: any = false;
  1049. let floorId: any = historyFloor[proxyData.buildingItem.buildingId];
  1050. proxyData.floorData.map((floor: any) => {
  1051. if (floor.id === floorId) {
  1052. flag = true;
  1053. proxyData.floorItem = floor;
  1054. }
  1055. });
  1056. if (!flag) {
  1057. proxyData.floorItem = proxyData.floorData[0];
  1058. }
  1059. },
  1060. /**
  1061. * 获取选中的选中空间
  1062. */
  1063. getHistorySpace() {
  1064. let data: any = proxyData.mapData;
  1065. let historySpace: any = getStorageSpaceId();
  1066. if (data) {
  1067. let flag: boolean = false;
  1068. let spaceList = data?.spaceList ?? [];
  1069. let key: any = `${proxyData.buildingItem.buildingId},${proxyData.floorItem.id}`;
  1070. let spaceId: any = historySpace[key];
  1071. if (spaceId) {
  1072. spaceList.map((space: any) => {
  1073. if (spaceId === space.spaceId) {
  1074. proxyData.selectArea = space;
  1075. flag = true;
  1076. }
  1077. });
  1078. }
  1079. if (!flag) {
  1080. for (let i: any = 0; i < spaceList.length; i++) {
  1081. if (spaceList[i].canClick) {
  1082. proxyData.selectArea = spaceList[i];
  1083. break;
  1084. }
  1085. }
  1086. }
  1087. }
  1088. },
  1089. /**
  1090. * 首次进入页面设置选中的空间
  1091. */
  1092. getFirstSelectSpace(item: any) {
  1093. let area: any = null;
  1094. let data: any = proxyData.mapData;
  1095. // debugger;
  1096. if (data && item) {
  1097. let spaceList = data?.spaceList ?? [];
  1098. for (let i = 0; i < spaceList.length; i++) {
  1099. if (spaceList[i].spaceId === item.spaceId) {
  1100. // proxyData.selectArea = spaceList[i]
  1101. area = spaceList[i];
  1102. break;
  1103. }
  1104. }
  1105. }
  1106. return area;
  1107. },
  1108. setDefaultSpace(item: any) {
  1109. if (item) {
  1110. proxyData.buildingItem.buildingId = item.buildingId;
  1111. proxyData.buildingItem.localName = item.buildingName
  1112. ? item.buildingName
  1113. : "";
  1114. proxyData.floorItem = {
  1115. id: item.floorId,
  1116. localName: item.floorName ? item.floorName : "",
  1117. };
  1118. }
  1119. },
  1120. // 设备模块初始化地图
  1121. init(item: any) {
  1122. if (item) {
  1123. proxyData.setDefaultSpace(item);
  1124. }
  1125. proxyData.getBuildingList();
  1126. proxyData.getFloorList(false);
  1127. proxyData.getMapInfo(false, item);
  1128. },
  1129. /**
  1130. *搜索后设置建筑的localName
  1131. */
  1132. setBuildingName() {
  1133. if (proxyData.buildingItem.buildingId) {
  1134. proxyData.buildingData.map((item: any) => {
  1135. if (item.id === proxyData.buildingItem.buildingId) {
  1136. proxyData.buildingItem.localName = item.localName;
  1137. }
  1138. });
  1139. } else {
  1140. // 设置常驻空间的时候使用
  1141. proxyData.buildingItem = {
  1142. buildingId: proxyData.buildingData[0].id,
  1143. localName: proxyData.buildingData[0].localName,
  1144. };
  1145. }
  1146. },
  1147. /**
  1148. * 搜索页面回来根据id设置楼层的localName
  1149. */
  1150. setFloorName() {
  1151. if (proxyData.floorItem.id) {
  1152. proxyData.floorData.map((item: any) => {
  1153. if (item.id === proxyData.floorItem.id) {
  1154. proxyData.floorItem.localName = item.localName;
  1155. }
  1156. });
  1157. } else {
  1158. // 设置常驻空间的时候使用
  1159. proxyData.floorItem = proxyData.floorData[0];
  1160. }
  1161. },
  1162. });
  1163. watch(props, (newProps: any) => {}, {
  1164. deep: false,
  1165. immediate: true,
  1166. });
  1167. onMounted(() => {
  1168. proxyData.spaceInfo = props.spaceInfo;
  1169. proxyData.buildingItem.buildingId = props.buildingId;
  1170. proxyData.floorItem.id = props.floorId;
  1171. proxyData.spaceInfo.buildingId = props.buildingId;
  1172. proxyData.spaceInfo.floorId = props.floorId;
  1173. proxyData.selectArea.spaceId = props.spaceInfo.spaceId;
  1174. proxyData.init(proxyData.spaceInfo);
  1175. });
  1176. return {
  1177. ...toRefs(proxyData),
  1178. };
  1179. },
  1180. });
  1181. </script>
  1182. <style lang="scss" scoped>
  1183. .space-main {
  1184. width: 100%;
  1185. height: 100%;
  1186. position: relative;
  1187. background: #f7f8fa;
  1188. transform-origin: 0 0;
  1189. transition: transform 0.3s;
  1190. transform: scale(1);
  1191. //transform: translateX(-100px) !important;
  1192. padding: 0 5px;
  1193. overflow: hidden;
  1194. .space-box {
  1195. position: absolute;
  1196. padding: 5px;
  1197. }
  1198. .space-disable-box {
  1199. // opacity: 0.4;
  1200. }
  1201. .space-box-bg {
  1202. // background: #5e8bcf;
  1203. background: rgba(94, 139, 207, 0.4) !important;
  1204. border: 2px solid rgba(94, 139, 207, 0.8);
  1205. border-radius: 5px;
  1206. // color: #fff;
  1207. .select-device {
  1208. span {
  1209. color: #fff !important;
  1210. }
  1211. }
  1212. .device span {
  1213. color: #fff !important;
  1214. font-size:16px;
  1215. }
  1216. }
  1217. .space {
  1218. position: relative;
  1219. width: 100%;
  1220. height: 100%;
  1221. box-shadow: 0px 1px 4px rgba(1, 1, 51, 0.01),
  1222. 0px 16px 40px rgba(1, 1, 51, 0.03);
  1223. border-radius: 4px;
  1224. box-sizing: border-box;
  1225. .device {
  1226. position: absolute;
  1227. left: 50%;
  1228. top: 50%;
  1229. transform: translate(-50%, -50%);
  1230. text-align: center;
  1231. z-index: 666;
  1232. img {
  1233. //margin-bottom: 6px;
  1234. }
  1235. span {
  1236. display: block;
  1237. word-break: keep-all;
  1238. white-space: nowrap;
  1239. //font-size: 12px;
  1240. color: #8995ba;
  1241. font-weight: 600;
  1242. }
  1243. }
  1244. .select-device {
  1245. transform: translate(-50%, -70%);
  1246. img {
  1247. margin-bottom: 6px;
  1248. }
  1249. }
  1250. .circle {
  1251. width: 4px;
  1252. height: 4px;
  1253. border-radius: 50%;
  1254. position: absolute;
  1255. top: 50%;
  1256. left: 50%;
  1257. transform: translateX(-50%) translateY(-50%);
  1258. }
  1259. }
  1260. .select {
  1261. border: 2px solid rgba(77, 148, 255, 0.8);
  1262. }
  1263. .select-disable {
  1264. border: 2px solid rgba(77, 148, 255, 0.2);
  1265. }
  1266. .use-select {
  1267. border: 5px solid #ffe823;
  1268. }
  1269. &::-webkit-scrollbar {
  1270. display: none;
  1271. }
  1272. }
  1273. .map-toolbar {
  1274. position: fixed;
  1275. width: 44px;
  1276. right: 20px;
  1277. z-index: 999;
  1278. top: 50%;
  1279. transform: translateY(-50%);
  1280. .icon-search {
  1281. width: 44px;
  1282. height: 44px;
  1283. border-radius: 5px;
  1284. background: #fff;
  1285. }
  1286. .toolbar-item {
  1287. width: 44px;
  1288. height: 44px;
  1289. background: #ffffff;
  1290. box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.1), 0px 4px 8px rgba(0, 0, 0, 0.1);
  1291. border-radius: 4px;
  1292. margin-top: 10px;
  1293. text-align: center;
  1294. .toolbar-menu {
  1295. width: 44px;
  1296. }
  1297. img {
  1298. width: 12px;
  1299. height: 14px;
  1300. margin-top: 15px;
  1301. }
  1302. }
  1303. .text-hidden {
  1304. //font-family: Montserrat;
  1305. display: block;
  1306. font-style: normal;
  1307. width: 44px;
  1308. line-height: 44px;
  1309. font-weight: 500;
  1310. font-size: 16px;
  1311. text-align: center;
  1312. color: #4d5262;
  1313. overflow: hidden;
  1314. text-overflow: ellipsis;
  1315. white-space: nowrap;
  1316. }
  1317. }
  1318. .buiding-item {
  1319. //font-family: 'Montserrat';
  1320. width: 100%;
  1321. padding: 10px;
  1322. font-style: normal;
  1323. font-weight: 500;
  1324. font-size: 14px;
  1325. text-align: left;
  1326. color: rgba(13, 13, 61, 0.86);
  1327. border-bottom: 1px solid rgba(2, 2, 82, 0.03);
  1328. }
  1329. .active {
  1330. color: rgba(77, 148, 255, 0.8);
  1331. }
  1332. </style>