MapView.vue 18 KB

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