MapOther.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. <template>
  2. <div class='map-view'>
  3. <van-nav-bar :title="`${floorName}平面图`" @click-left='backPage' @click-right="showLegend">
  4. <template #left>
  5. <van-icon name="arrow-left" size="18" color="#333333" />
  6. </template>
  7. <template #right v-if="legendList.length">
  8. <span :style="{color: show?'#1989fa':'#333333'}">图例</span>
  9. </template>
  10. </van-nav-bar>
  11. <transition name="van-slide-down">
  12. <div class="legendBox" v-show="show" @touchmove="show=false">
  13. <ul class="legend-list">
  14. <li class="legend-item" v-for="(item, index) in legendList" :key="`legend${index}`">
  15. <img :src="`/serve/topology-wanda/Picture/query/${item.Url}`" alt>
  16. {{`${item.Name}×${item.Num}`}}
  17. </li>
  18. </ul>
  19. <p class="legend-close" @click="show = false"></p>
  20. </div>
  21. </transition>
  22. <div id="bind-map-content">
  23. <canvas id="bind-canvas" ref="bind-canvas" tabindex="0"></canvas>
  24. <!-- 地图底部操作按钮 -->
  25. <div class='strip-bottom'>
  26. <canvasFun @fit='fit' @showText='showText' ref='canvasFun'></canvasFun>
  27. </div>
  28. <floor-list ref="fList" class="bind-floor-list" v-if='floorsArr.length>0' :floorsArr='floorsArr'
  29. @emitFloor='emitFloor'></floor-list>
  30. <div class="change-direction" @click='changeOri'>
  31. <img src='../../assets/images/screen.png' />
  32. <!-- <i class="iconfont wanda-hengshuping"></i> -->
  33. </div>
  34. </div>
  35. </div>
  36. </template>
  37. <script>
  38. /**
  39. * 平面图展示
  40. */
  41. import Vue from 'vue'
  42. import { mapGetters } from 'vuex'
  43. import { NavBar, Toast } from 'vant'
  44. import floorList from "@/components/floorMap/floorList.vue"
  45. import canvasFun from '@/components/floorMap/canvasFun'
  46. import { readGroup, queryStatis, graphQuery,appGraphElementQuery } from '@/api/public'
  47. import { queryShops } from '@/api/equipmentList.js'
  48. import { FloorView } from '@/lib/FloorView'
  49. import { FloorScene } from '@/lib/FloorScene'
  50. import { STopologyParser } from '@/lib/parsers/STopologyParser'
  51. import { TipelineItem } from '@/lib/items/TipelineItem'
  52. import { SImageLegendItem } from '@/lib/items/SImageLegendItem'
  53. import { SImageItem, SImageShowType, SGraphItem } from '@saga-web/graph/lib'
  54. import { ProjectRf } from '@saga-web/feng-map'
  55. import { SFloorParser, ItemOrder, ItemColor, SPolygonItem, SBoardItem } from '@saga-web/big'
  56. import { SColor } from '@saga-web/draw/lib'
  57. Vue.use(NavBar).use(Toast)
  58. export default {
  59. name: 'MapOther',
  60. props: {},
  61. components: { floorList, canvasFun },
  62. computed: {
  63. ...mapGetters(['plazaId', 'fmapID', 'haveFengMap', 'bunkObj', 'categoryId']),
  64. },
  65. data() {
  66. return {
  67. view: '',
  68. scene: '',
  69. floorsArr: [],
  70. mapServerURL: "http://mapapp.wanda.cn/editor",
  71. canvasLoading: false,
  72. floorid: '', //楼层id
  73. floorName: '', //楼层名
  74. count: 0, // 顶楼为多张图时计数器
  75. topologyParser: null, // 解析器数据
  76. fParser: null, // 底图解析器
  77. direction: '竖屏',
  78. show: false,
  79. legendList: [], // 图例列表
  80. }
  81. },
  82. props: {},
  83. beforeMount() { },
  84. mounted() {
  85. window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", () => {
  86. this.clearGraphy();
  87. setTimeout(() => {
  88. if (window.orientation === 0 || window.orientation === 180) {
  89. console.log("竖屏");
  90. }
  91. if (window.orientation === 90 || window.orientation === -90) {
  92. console.log("横屏");
  93. }
  94. document.getElementById("bind-canvas").width = document.getElementById("bind-map-content").offsetWidth;
  95. document.getElementById("bind-canvas").height = document.getElementById("bind-map-content").offsetHeight;
  96. this.init(this.floorid)
  97. }, 500)
  98. }, false);
  99. this.$nextTick(() => {
  100. document.getElementById("bind-canvas").width = document.getElementById("bind-map-content").offsetWidth;
  101. document.getElementById("bind-canvas").height = document.getElementById("bind-map-content").offsetHeight;
  102. })
  103. },
  104. methods: {
  105. backPage() {
  106. if (this.direction === '横屏') {
  107. this.roateY()
  108. this.direction = '竖屏'
  109. }
  110. this.$router.go(-1);
  111. },
  112. // 展示图例
  113. showLegend() {
  114. if(this.legendList.length) {
  115. this.show = !this.show;
  116. }
  117. },
  118. // 获取图例数据
  119. getLegendData(floorObj) {
  120. let params = {
  121. BuildingID: '1',
  122. CategoryID: this.categoryId,
  123. ProjectID: this.plazaId,
  124. Floors: [{FloorId: floorObj.gname, FloorName: floorObj.code}]
  125. }
  126. this.legendList = [];
  127. if (this.categoryId !== "SCPZ") {
  128. appGraphElementQuery(params).then(res => {
  129. if(res.Data[0] && res.Data[0].Statistics && res.Data[0].Statistics.length) {
  130. this.legendList = res.Data[0].Statistics.filter(item => {
  131. return item.Url && item.Type === "Image"
  132. });
  133. }
  134. })
  135. }
  136. },
  137. // 切换楼层
  138. emitFloor(floorObj) {
  139. if (floorObj) {
  140. this.getLegendData(floorObj);
  141. this.$nextTick(() => {
  142. this.floorid = floorObj.gname;
  143. this.floorName = floorObj.code;
  144. this.init(floorObj.gname);
  145. })
  146. }
  147. },
  148. init(floorid) {
  149. // this.canvasLoading = true
  150. Toast.loading({
  151. duration: 0, // 持续展示 toast
  152. message: '加载中...',
  153. forbidClick: true,
  154. });
  155. // this.floorid = floorid
  156. // this.$refs.canvasFun.isShow = false
  157. setTimeout(() => {
  158. this.clearGraphy()
  159. this.scene = new FloorScene()
  160. if (this.haveFengMap == 1) {
  161. this.scene.selectContainer.connect('listChange', this, this.listChange)
  162. this.getGraphDetail().then((res) => {
  163. if (res.Content.length == 1) {
  164. const data = res.Content[0]
  165. if (data.MaxY && data.MinX) {
  166. window.fengmapData.maxY = data.MaxY
  167. window.fengmapData.minX = data.MinX
  168. }
  169. }
  170. this.parserData(floorid)
  171. })
  172. // this.parserData(floorid);
  173. } else if (this.haveFengMap == 0) {
  174. this.view.scene = this.scene
  175. this.readGraph()
  176. } else {
  177. this.canvasLoading = false
  178. Toast.clear();
  179. }
  180. }, 100)
  181. },
  182. // 解析底图
  183. parserData(floor) {
  184. if (floor == 'g80') {
  185. // 屋顶
  186. if (window.fengmapData.frImg) {
  187. const pj = this.fmapID.split('_')[0]
  188. // 单张图片
  189. if (!ProjectRf[pj]) {
  190. let imgItem = new SImageItem(null, `${this.mapServerURL}/webtheme/${this.fmapID}/${window.fengmapData.frImg}`)
  191. imgItem.showType = SImageShowType.AutoFit
  192. imgItem.connect('imgLoadOver', this, () => {
  193. this.readGraph()
  194. })
  195. this.scene.addItem(imgItem)
  196. this.view.scene = this.scene
  197. // this.view.fitSceneToView()
  198. } else {
  199. // 多张图
  200. try {
  201. // 初始化0
  202. this.count = 0
  203. ProjectRf[pj].forEach((t) => {
  204. const item = new SImageItem(null, `${this.mapServerURL}/webtheme/${this.fmapID}/${t.name}`)
  205. item.width = t.width
  206. item.height = t.height
  207. item.moveTo(t.x, t.y)
  208. item.connect('imgLoadOver', this, () => {
  209. this.countRf(ProjectRf[pj].length)
  210. })
  211. this.scene.addItem(item)
  212. })
  213. this.view.scene = this.scene
  214. } catch (e) {
  215. console.log(e)
  216. }
  217. }
  218. } else {
  219. // 屋顶图不为图片
  220. this.readBaseMap(floor)
  221. }
  222. } else {
  223. if (window.fengmapData.gnameToGid[floor]) {
  224. this.readBaseMap(floor)
  225. } else {
  226. console.log('楼层不正确')
  227. }
  228. }
  229. },
  230. // 解析楼地板
  231. loadBoard(floor) {
  232. window.fengmapData.loadFloor(floor, (res) => {
  233. const zone = new SBoardItem(null, res)
  234. this.scene.addItem(zone)
  235. })
  236. },
  237. readBaseMap(floor) {
  238. this.loadBoard(window.fengmapData.gnameToGid[floor])
  239. window.fengmapData.parseData(window.fengmapData.gnameToGid[floor], (res) => {
  240. if (res.err) {
  241. console.log('errr', res.err)
  242. return
  243. }
  244. this.fParser = new SFloorParser(null)
  245. this.fParser.parseData(res)
  246. this.fParser.spaceList.forEach((t) => {
  247. this.scene.addItem(t)
  248. t.nameSize = 12
  249. t.nameColor = '#2a2a2a'
  250. if (t.data.Name && this.bunkObj[t.data.Name]) {
  251. t.name = this.bunkObj[t.data.Name].brandname
  252. } else {
  253. // t.name = t.data.Name
  254. t.name = ''
  255. }
  256. })
  257. this.fParser.wallList.forEach((t) => this.scene.addItem(t))
  258. this.fParser.virtualWallList.forEach((t) => this.scene.addItem(t))
  259. this.fParser.doorList.forEach((t) => this.scene.addItem(t))
  260. this.fParser.columnList.forEach((t) => this.scene.addItem(t))
  261. this.fParser.casementList.forEach((t) => this.scene.addItem(t))
  262. this.view.scene = this.scene
  263. // this.view.fitSceneToView()
  264. this.readGraph()
  265. })
  266. },
  267. readGraph() {
  268. this.readGroup()
  269. .then((data) => {
  270. if (data.Result == 'failure') {
  271. this.$store.commit('SETISMESSAGE', false)
  272. this.view.fitSceneToView()
  273. this.view.minScale = this.view.scale
  274. if (this.$refs.canvasFun) {
  275. this.$refs.canvasFun.everyScale = this.view.scale
  276. }
  277. Toast.clear();
  278. return
  279. } else {
  280. if (
  281. data.Data[0].Elements.Nodes.length === 0 &&
  282. data.Data[0].Elements.Markers.length === 0 &&
  283. data.Data[0].Elements.Relations.length === 0
  284. ) {
  285. this.$store.commit('SETISMESSAGE', false)
  286. } else {
  287. this.$store.commit('SETISMESSAGE', true)
  288. }
  289. }
  290. // 无返回Data处理
  291. if (!(data.Data && data.Data.length)) {
  292. this.view.fitSceneToView()
  293. this.view.minScale = this.view.scale
  294. if (this.$refs.canvasFun) {
  295. this.$refs.canvasFun.everyScale = this.view.scale
  296. }
  297. return false
  298. }
  299. // // 请求回来的备注
  300. // if (data.Data && data.Data[0].Note) {
  301. // let note = data.Data[0].Note
  302. // bus.$emit('queryRemarksMethods', note)
  303. // } else {
  304. // bus.$emit('queryRemarksMethods', '')
  305. // }
  306. // //土建装饰的图例展示
  307. // if (this.$cookie.get('categoryId') == 'SCPZ') {
  308. // let scpzTable = [],
  309. // arr = []
  310. // scpzTable = data.Data[0].Elements.Nodes || []
  311. // console.log(scpzTable)
  312. // if (scpzTable.length > 0) {
  313. // scpzTable.forEach((e) => {
  314. // if (e.Properties.ItemExplain) {
  315. // let obj = e
  316. // arr.push(obj)
  317. // }
  318. // })
  319. // }
  320. // console.log(arr)
  321. // this.$store.commit('SETSCPZTABLE', arr)
  322. // }
  323. // if (data.Data[0].Elements.Nodes.length > 0) {
  324. // this.$store.commit('SETTYPENUM', '')
  325. // let Lengd = data.Data[0].Elements.Nodes
  326. // Lengd.forEach((el) => {
  327. // if (el.Type == 'Image' && el.Num > 1) {
  328. // console.log(el.Num)
  329. // this.$store.commit('SETTYPENUM', el.Num)
  330. // }
  331. // })
  332. // }
  333. // 放到后边 $cookie graphId
  334. // this.$cookie.set('graphId', data.Data[0].ID, 3)
  335. // if (this.$cookie.get('graphId')) {
  336. // // 得到graphId 就请求图例
  337. // // 除土建装饰之外的图例展示 包括楼层功能
  338. // bus.$emit('queryViewMethods')
  339. // }
  340. this.topologyParser = new STopologyParser(null)
  341. this.topologyParser.parseData(data.Data[0].Elements)
  342. // 多边形
  343. this.topologyParser.zoneLegendList.forEach((t) => {
  344. this.scene.addItem(t)
  345. // t.connect('legendItemClick', t, this.handleClickLegendItem)
  346. })
  347. // 增加文字
  348. this.topologyParser.textMarkerList.forEach((t) => {
  349. this.scene.addItem(t)
  350. })
  351. // 增加图片
  352. this.topologyParser.imageMarkerList.forEach((t) => {
  353. this.scene.addItem(t)
  354. })
  355. // 增加直线
  356. this.topologyParser.lineMarkerList.forEach((t) => {
  357. this.scene.addItem(t)
  358. })
  359. // 增加图标类图例
  360. this.topologyParser.imageLegendList.forEach((t) => {
  361. this.scene.addItem(t)
  362. // t.connect('legendItemClick', t, this.handleClickLegendItem)
  363. })
  364. // 增加管线类
  365. // 增加图标类图例
  366. this.topologyParser.relationList.forEach((t) => {
  367. t.selectable = true
  368. this.scene.addItem(t)
  369. // t.connect('legendItemClick', t, this.handleClickLegendItem)
  370. })
  371. // this.view.fitSceneToView()
  372. // this.view.minScale = this.view.scale
  373. if (this.$refs.canvasFun) {
  374. this.$refs.canvasFun.everyScale = this.view.scale
  375. }
  376. this.view.fitSceneToView()
  377. this.view.minScale = this.view.scale
  378. this.canvasLoading = false
  379. Toast.clear();
  380. })
  381. .catch(() => {
  382. this.canvasLoading = false
  383. Toast.clear();
  384. })
  385. },
  386. // 顶楼为多张图时计数器
  387. countRf(len) {
  388. this.count++
  389. if (len == this.count) {
  390. this.readGraph()
  391. } else {
  392. console.log('所有图片未加载完成')
  393. }
  394. },
  395. clearGraphy() {
  396. if (this.view) {
  397. this.view.scene = null
  398. return
  399. }
  400. this.view = new FloorView("bind-canvas");
  401. },
  402. listChange(item, ev) {
  403. if (ev[0].length) {
  404. // 选中电井设置电井关联的商铺高亮
  405. this.setHightLight(ev[0])
  406. } else {
  407. this.clearHightLight()
  408. }
  409. },
  410. // 选中电井关联的商铺高亮
  411. setHightLight(arr) {
  412. this.clearHightLight()
  413. arr.forEach((item) => {
  414. let location = item.data.AttachObjectIds[0] ? item.data.AttachObjectIds[0].id : ''
  415. // 添加了位置类型并且选中的类型为电井类型
  416. if (
  417. (item.data.GraphElementId == '100050' ||
  418. item.data.GraphElementId == '100055' ||
  419. item.data.GraphElementId == '100056' ||
  420. item.data.GraphElementId == '100057') &&
  421. location
  422. ) {
  423. let getParams = {
  424. plazaId: this.plazaId,
  425. floor: this.floorid,
  426. keyword: `${location}:wellnum;`,
  427. }
  428. queryShops({ getParams }).then((res) => {
  429. let shopsnumList = []
  430. if (res.data && res.data.length) {
  431. for (let floor in res.data[0]) {
  432. if (res.data[0][floor].length) {
  433. res.data[0][floor].forEach((v) => {
  434. shopsnumList = shopsnumList.concat(v.shopsnumList.split(','))
  435. })
  436. }
  437. }
  438. }
  439. if (shopsnumList.length) {
  440. this.fParser.spaceList.forEach((item) => {
  441. if (shopsnumList.findIndex((name) => name == item.data.Name) != -1) {
  442. item.highLightFlag = true
  443. item.zOrder = 30
  444. }
  445. })
  446. }
  447. })
  448. }
  449. })
  450. },
  451. // 清除电井关联商铺的高亮状态
  452. clearHightLight() {
  453. ItemColor.spaceHighColor = new SColor('#FBF2CC')
  454. this.fParser.spaceList.forEach((item) => {
  455. item.highLightFlag = false
  456. item.zOrder = ItemOrder.spaceOrder
  457. })
  458. },
  459. // 适配底图到窗口
  460. fit() {
  461. this.view.fitSceneToView()
  462. },
  463. // 小眼睛控制显示铺位名称
  464. showText(val) {
  465. this.fParser.spaceList.forEach((t) => {
  466. t.showBaseName = val
  467. })
  468. },
  469. // 读取数据
  470. readGroup() {
  471. const data = {
  472. BuildingID: '1',
  473. FloorID: this.floorid,
  474. categoryId: this.categoryId,
  475. projectId: this.plazaId,
  476. Pub: true,
  477. }
  478. return readGroup(data)
  479. },
  480. // 获取图最大最小值
  481. getGraphDetail() {
  482. const categoryId = this.categoryId
  483. const data = {
  484. Filters: `categoryId='${categoryId}';projectId='${this.plazaId}';BuildingID='1';FloorID='${this.floorid}';isPub=true`,
  485. }
  486. return graphQuery(data)
  487. },
  488. changeOri() {
  489. if (this.direction === '竖屏') {
  490. this.roateX()
  491. this.direction = '横屏'
  492. } else if (this.direction === '横屏') {
  493. this.roateY()
  494. this.direction = '竖屏'
  495. }
  496. },
  497. roateX() {
  498. console.log('横屏')
  499. window.webkit &&
  500. webkit.messageHandlers.cordova_iab.postMessage(
  501. JSON.stringify({
  502. method: 'roateX',
  503. })
  504. )
  505. },
  506. // 竖屏
  507. roateY() {
  508. console.log('竖屏')
  509. window.webkit &&
  510. webkit.messageHandlers.cordova_iab.postMessage(
  511. JSON.stringify({
  512. method: 'roateY',
  513. })
  514. )
  515. },
  516. },
  517. watch: {
  518. '$route.params.floor': {
  519. handler(floor) {
  520. if (this.$route.params.floorsArr) {
  521. this.floorsArr = this.$route.params.floorsArr;
  522. }
  523. this.$nextTick(() => {
  524. this.floorid = floor.FloorId;
  525. this.floorName = floor.FloorName;
  526. let index = this.floorsArr.findIndex(item => {
  527. return item.gname === floor.FloorId
  528. })
  529. let item = {
  530. gname: floor.FloorId,
  531. code: floor.FloorName
  532. }
  533. this.$refs.fList.tabFloor(item ,index, true);
  534. // this.$refs.fList.currentFloorId = floor.FloorId;
  535. // this.init(floor.FloorId);
  536. })
  537. },
  538. immediate: true,
  539. deep: true
  540. }
  541. },
  542. }
  543. </script>
  544. <style lang='less' scoped>
  545. .map-view {
  546. width: 100%;
  547. height: 100%;
  548. overflow: hidden;
  549. display: flex;
  550. flex-direction: column;
  551. /deep/ .van-nav-bar {
  552. z-index: 999;
  553. }
  554. .legendBox {
  555. position: fixed;
  556. top: 46px;
  557. width: 100%;
  558. height: auto;
  559. padding: 16px 10px 0;
  560. z-index: 99;
  561. background: #FFFFFF;
  562. box-shadow: 0px 6px 15px 0px rgba(31, 36, 41, 0.08);
  563. .legend-list {
  564. display: flex;
  565. justify-content: space-between;
  566. flex-wrap: wrap;
  567. .legend-item {
  568. padding: 0 8px;
  569. height: 24px;
  570. font-size: 12px;
  571. color: #1F2429;
  572. line-height: 24px;
  573. background: #E4E6E7;
  574. border-radius: 12px;
  575. margin: 0 5px 12px;
  576. img {
  577. display: inline-block;
  578. max-width: 16px;
  579. max-height: 16px;
  580. vertical-align: text-bottom;
  581. }
  582. }
  583. .legend-item:last-child {
  584. margin-right: auto;
  585. }
  586. }
  587. .legend-close {
  588. margin: 10px auto 7px;
  589. width: 56px;
  590. height: 4px;
  591. border-radius: 5px;
  592. background: #D8D8D8;
  593. }
  594. }
  595. #bind-map-content {
  596. width: 100%;
  597. height: calc(100% - 50px);
  598. position: relative;
  599. overflow: hidden;
  600. .bind-floor-list {
  601. position: fixed;
  602. top: 65px;
  603. right: 16px;
  604. }
  605. .strip-bottom {
  606. position: fixed;
  607. bottom: 60px;
  608. right: 16px;
  609. }
  610. .change-direction {
  611. position: fixed;
  612. bottom: 60px;
  613. left: 16px;
  614. img {
  615. width: 28px;
  616. height: 28px;
  617. }
  618. }
  619. }
  620. }
  621. // 横屏
  622. @media screen and (orientation: landscape) {
  623. .map-view {
  624. /deep/ .van-nav-bar {
  625. height: 40px;
  626. }
  627. #bind-map-content {
  628. .bind-floor-list {
  629. position: fixed;
  630. top: 47px;
  631. right: 16px;
  632. }
  633. .strip-bottom {
  634. position: fixed;
  635. bottom: 15px;
  636. right: 60px;
  637. }
  638. .change-direction {
  639. position: fixed;
  640. bottom: 15px;
  641. left: 15px;
  642. img {
  643. width: 18px;
  644. height: 18px;
  645. }
  646. }
  647. }
  648. }
  649. }
  650. </style>