MapBox.vue 41 KB

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