zhangyu преди 4 години
родител
ревизия
05cc9ade8f

+ 8 - 1
package.json

@@ -9,6 +9,11 @@
     "build_prod": "vue-cli-service build --mode production"
   },
   "dependencies": {
+    "@saga-web/base": "2.1.27",
+    "@saga-web/big": "1.0.113",
+    "@saga-web/draw": "2.1.107",
+    "@saga-web/feng-map": "1.0.47",
+    "@saga-web/graph": "2.1.126",
     "axios": "^0.20.0",
     "compression-webpack-plugin": "^5.0.2",
     "core-js": "^3.6.5",
@@ -35,6 +40,8 @@
     "terser-webpack-plugin": "^4.1.0",
     "typescript": "~3.9.3",
     "vue-template-compiler": "^2.6.11",
-    "webpack-bundle-analyzer": "^3.8.0"
+    "webpack-bundle-analyzer": "^3.8.0",
+    "fengmap": "^2.5.3",
+    "polybooljs": "^1.2.0"
   }
 }

+ 77 - 0
src/App.vue

@@ -1,6 +1,7 @@
 <template>
     <!-- ios头部padding适配 -->
     <div id='app' :class='isIOS?"ios-padding":""'>
+        <div id='fengMap' class='fengMap'></div>
         <!-- 顶部navbar -->
         <NarBar class='nav-bar' v-if='!$route.meta.hideNarBar' />
         <!-- <div class='container'> -->
@@ -20,11 +21,15 @@
 </template>
 <script>
 import Vue from 'vue'
+import { mapGetters, mapActions, mapMutations } from 'vuex'
+import { SFengParser } from '@saga-web/feng-map'
+import { setFloor } from '@/api/public.js'
 import { Tabbar, TabbarItem } from 'vant'
 Vue.use(Tabbar).use(TabbarItem)
 import store from './store/index'
 import NarBar from './components/Navbar'
 import { osInfo } from './utils/util'
+window.fengmapData = null
 export default {
     name: 'App',
     props: {},
@@ -47,12 +52,17 @@ export default {
                 3: '其他事项',
             },
             isIOS: false, //是否是IOS
+            key: '23f30a832a862c58637a4aadbf50a566',
+            appName: '万达可视化系统',
+            mapServerURL: `http://map.wanda.cn/editor`,
+            mapthemeUrl: `http://map.wanda.cn/editor/webtheme`,
         }
     },
     beforeMount() {},
     created() {
         store.commit('SETSSOTOKEN', 'admin:liujiandong')
         console.log(window.location.href)
+        this.SETHAVEFENGMAP(false)
         const { os } = osInfo()
         if (os === 'iOS') {
             this.isIOS = true
@@ -62,8 +72,55 @@ export default {
     },
     mounted() {
         console.log('环境变量', process.env.VUE_APP_RealEnv)
+        if (this.plazaId) {
+            this.getFengMap()
+        } else {
+            window.fengmapData = null
+        }
+    },
+    computed: {
+        ...mapGetters(['plazaId', 'fmapID']),
     },
     methods: {
+        ...mapActions(['getfmapID']),
+        ...mapMutations(['SETHAVEFENGMAP']),
+        getFengMap() {
+            this.getfmapID().then(() => {
+                this.getMap()
+            })
+        },
+        getMap() {
+            window.fengmapData = new SFengParser(
+                'fengMap',
+                `${this.mapServerURL}/fmap/${this.fmapID}`,
+                this.key,
+                this.appName,
+                null,
+                this.mapthemeUrl
+            )
+            if (this.fmapID.includes('null')) {
+                this.SETHAVEFENGMAP(0)
+            }
+            window.fengmapData.loadMap(this.fmapID, (a, b) => {
+                const dataArr = b.map((item) => {
+                    return item.gname
+                })
+                // 获取主题数据
+                window.fengmapData.loadTheme(`${this.mapServerURL}/webtheme/${this.fmapID}/${this.fmapID}.theme`).then((res) => {
+                    this.SETHAVEFENGMAP(1)
+                })
+                // 缓存楼层数据
+                if (dataArr.length) {
+                    setFloor({ plazaId: this.plazaId }, dataArr)
+                        .then((res) => {
+                            console.log('缓存楼层', res)
+                        })
+                        .catch((error) => {
+                            console.log('缓存楼层', error)
+                        })
+                }
+            })
+        },
         // 路由更改
         changeTabbar(active) {
             console.log(active)
@@ -71,6 +128,19 @@ export default {
             store.commit('SETAPPTITLE', this.titleDict[active])
         },
     },
+    watch: {
+        plazaId(plazaId) {
+            console.log('项目id', plazaId)
+            window.fengmapData = null
+            // 当获取到到项目id,请求底图
+            if (plazaId) {
+                // 请求该项目下的楼层数据
+                this.getFengMap()
+            } else {
+                window.fengmapData = null
+            }
+        },
+    },
 }
 </script>
 <style lang="less">
@@ -84,6 +154,13 @@ export default {
     width: 100%;
     height: 50px;
 }
+.fengMap {
+    position: fixed;
+    width: 100px;
+    height: 100px;
+    z-index: -1;
+    opacity: 0;
+}
 // .container {
 //     height: calc(100% - 105px);
 //     background-color: #aaa;

BIN
src/assets/images/iconBlackBottom.png


BIN
src/assets/images/iconBlackTop.png


BIN
src/assets/images/iconLightBottom.png


BIN
src/assets/images/iconLightTop.png


+ 177 - 0
src/components/floorMap/canvasFun.vue

@@ -0,0 +1,177 @@
+<template>
+    <div>
+        <div class='action-box'>
+            <div class='small-block'>
+                <el-dropdown size='mini' placement='top-start' @command='handleCommand'>
+                    <i>
+                        <img src='../../assets/imgs/dl.png' alt />
+                    </i>
+                    <el-dropdown-menu slot='dropdown'>
+                        <el-dropdown-item command='savePng'>保存为png</el-dropdown-item>
+                        <!-- <el-dropdown-item command='saveSvg'>保存为svg</el-dropdown-item> -->
+                    </el-dropdown-menu>
+                </el-dropdown>
+            </div>
+            <div class='small-block' @click='showText'>
+                <i>
+                    <el-tooltip v-if='isShow' effect='dark' content='隐藏店铺名称' placement='top'>
+                        <img src='../../assets/imgs/yl.png' alt />
+                    </el-tooltip>
+                    <el-tooltip v-else effect='dark' content='显示店铺名称' placement='top'>
+                        <img src='../../assets/imgs/er.png' alt />
+                    </el-tooltip>
+                </i>
+            </div>
+            <div class='small-block' @click='fitToWindow'>
+                <i>
+                    <img src='../../assets/imgs/eye2.jpg' alt />
+                </i>
+            </div>
+            <div class='small-size' @click='reduce'>
+                <i>-</i>
+            </div>
+            <div class='small-slide'>
+                <el-slider tooltip-class='tooltip-class' :min='min' v-model='sliderVal' :show-tooltip='false' @input='scale' :max='max'></el-slider>
+            </div>
+            <div class='small-size' @click='plus'>
+                <i>+</i>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            sliderVal: 1, // 滑块值
+            active: '',
+            min: 1,
+            max: 200,
+            everyScale: 1, // 每份的放大倍数
+            isSwitch: false, // 是否开启吸附
+            isShow: false
+        }
+    },
+
+    methods: {
+        // 适配大小
+        fitToWindow() {
+            this.$emit('fit')
+        },
+        // 下拉菜单
+        handleCommand(command) {
+            this.$emit(command)
+        },
+        // 是否开启吸附
+        handleDivideCommand(commond) {
+            this.$emit('changeAbsorb', this.isSwitch)
+        },
+        // 切割编辑
+        divide() {
+            this.active = 'divide'
+            this.$emit('divide')
+        },
+        // 清除编辑
+        clearDivide() {
+            this.active = ''
+            this.$emit('clearDivide')
+        },
+        // 减
+        reduce() {
+            this.sliderVal /= 1.1
+            if (this.sliderVal < this.min) {
+                this.sliderVal = this.min
+            }
+            this.scale(this.sliderVal)
+        },
+        // 缩放
+        scale(val) {
+            // 换算
+            let scale = (val * this.everyScale) / 10
+            this.$emit('scale', scale)
+        },
+        // 加
+        plus() {
+            this.sliderVal *= 1.1
+            if (this.sliderVal > this.maxScale) {
+                this.sliderVal = this.maxScale
+            }
+            this.scale(this.sliderVal)
+        },
+        showText() {
+            this.isShow = !this.isShow
+            this.$emit('showText', this.isShow)
+        }
+    },
+    mounted() {}
+}
+</script>
+<style lang="less" scoped>
+.action-box {
+    width: 400px;
+    height: 40px;
+    background: rgba(255, 255, 255, 1);
+    box-shadow: 0px 2px 15px 0px rgba(31, 36, 41, 0.08);
+    border-radius: 2px;
+    margin: 0 auto;
+    display: flex;
+    align-items: center;
+    overflow: hidden;
+    .small-block {
+        border-right: 1px solid #e4e5e7;
+        padding: 12px;
+        cursor: pointer;
+        i {
+            width: 16px;
+            height: 16px;
+            display: inline-block;
+            img {
+                width: 100%;
+                height: 100%;
+            }
+        }
+    }
+    .small-size {
+        cursor: pointer;
+        padding: 12px;
+        font-size: 28px;
+    }
+    .small-slide {
+        flex: 1;
+        height: 100%;
+        padding: 0 8px;
+        margin-top: 10px;
+        border-left: 1px solid #e4e5e7;
+        border-right: 1px solid #e4e5e7;
+        z-index: 1;
+    }
+}
+</style>
+<style lang="less">
+.action-box {
+    .el-slider__button {
+        width: 13px;
+        height: 13px;
+        border: 2px solid #025baa;
+    }
+    .el-slider__runway {
+        height: 3px;
+        background-color: #e4e7ed;
+        background: rgba(0, 0, 0, 0.45);
+        border-radius: 1px;
+    }
+    .el-slider__button-wrapper {
+        top: -17px;
+    }
+    .el-slider__bar {
+        height: 3px;
+        background-color: #025baa;
+        border-top-left-radius: 1px;
+        border-bottom-left-radius: 1px;
+    }
+    .action-box .el-slider__runway {
+        background-color: #e8e8e8 !important;
+        background: #e8e8e8 !important;
+    }
+}
+</style>

src/components/floorList.vue → src/components/floorMap/floorList.vue


+ 23 - 0
src/components/mapClass/until.js

@@ -0,0 +1,23 @@
+//rgba转成16进制
+export function hexify(color) {
+    var values = color
+        .replace(/rgba?\(/, '')
+        .replace(/\)/, '')
+        .replace(/[\s+]/g, '')
+        .split(',');
+    var a = parseFloat(values[3] || 1), r = Math.floor(a * parseInt(values[0]) + (1 - a) * 255), g = Math.floor(a * parseInt(values[1]) + (1 - a) * 255), b = Math.floor(a * parseInt(values[2]) + (1 - a) * 255);
+    return '#' + ('0' + r.toString(16)).slice(-2) + ('0' + g.toString(16)).slice(-2) + ('0' + b.toString(16)).slice(-2);
+}
+//  生成uuid
+export function uuid() {
+    var s = [];
+    var hexDigits = "0123456789abcdef";
+    for (var i = 0; i < 36; i++) {
+        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
+    }
+    s[14] = "4";
+    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
+    s[8] = s[13] = s[18] = s[23] = "-";
+    var uuid = s.join("");
+    return uuid;
+}

+ 25 - 1
src/store/index.ts

@@ -1,5 +1,6 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
+import { queryfmapID } from '@/api/login.js'
 
 Vue.use(Vuex)
 
@@ -8,10 +9,16 @@ export default new Vuex.Store({
         ssoToken: 'admin:liujiandong',
         appTitle: '管理说明书', //顶部标题
         // ssoToken: null,
+        plazaId: '1000423', //项目Id
+        fmapID: '',
+        haveFengMap: -1, //是否有蜂鸟地图的数据 -1为等待 0 为失败 1 为成功
     },
     getters: {
         ssoToken: (state) => state.ssoToken,
         appTitle: (state) => state.appTitle,
+        plazaId: (state) => state.plazaId,
+        fmapID: (state) => state.fmapID,
+        haveFengMap: (state) => state.haveFengMap,
     },
     mutations: {
         SETSSOTOKEN(state, data) {
@@ -20,7 +27,24 @@ export default new Vuex.Store({
         SETAPPTITLE(state, data) {
             state.appTitle = data
         },
+        SETPLAZAID(state, data) {
+            state.plazaId = data
+        },
+        SETMAPID(state, data) {
+            state.fmapID = data
+        },
+        SETHAVEFENGMAP(state, data) {
+            state.haveFengMap = data
+        },
+    },
+    actions: {
+        async getfmapID(context) {
+            await queryfmapID({
+                mapId: context.state.plazaId,
+            }).then((res) => {
+                context.commit('SETMAPID', `${context.state.plazaId}_${res.mapVersion}`)
+            })
+        },
     },
-    actions: {},
     modules: {},
 })

+ 54 - 2
src/views/overview/MapView.vue

@@ -7,6 +7,10 @@
         </van-nav-bar>
         <div id="bind-map-content" v-loading="canvasLoading">
           <canvas id="bind-canvas" ref="bind-canvas" tabindex="0"></canvas>
+          <!-- 地图底部操作按钮 -->
+          <div class='strip-bottom'>
+            <!-- <canvasFun @fit='fit' @savePng='savePng' @saveSvg='saveSvg' @saveJson='saveJson' @scale='scale' @showText='showText' ref='canvasFun'></canvasFun> -->
+          </div>
           <floor-list v-if='floorsArr.length>0' :floorsArr='floorsArr' @emitFloor='emitFloor' id='system'></floor-list>
         </div>
     </div>
@@ -17,15 +21,29 @@
  */
 import Vue from 'vue'
 import { NavBar } from 'vant'
-import floorList from "@/components/floorList.vue"
+import floorList from "@/components/floorMap/floorList.vue"
+import canvasFun from '@/components/floorMap/canvasFun'
+import { FloorView } from '@/lib/FloorView'
+import { FloorScene } from '@/lib/FloorScene'
+import { STopologyParser } from '@/lib/parsers/STopologyParser'
+
+import { TipelineItem } from '@/lib/items/TipelineItem'
+import { SImageLegendItem } from '@/lib/items/SImageLegendItem'
+
+import { SImageItem, SImageShowType, SGraphItem } from '@saga-web/graph/lib'
+import { SColor } from '@saga-web/draw/lib'
 Vue.use(NavBar)
 export default {
     name: 'MapView',
     props: {},
-    components: {},
+    components: { floorList, canvasFun },
     data() {
         return {
             floorsArr: [],
+            view: '',
+            scene: '',
+            mapServerURL: "http://map.wanda.cn/editor",
+            activeFloor: null,
             canvasLoading: false
         }
     },
@@ -41,6 +59,33 @@ export default {
         backPage() {
             this.$router.go(-1)
         },
+        init(floorid) {
+            this.canvasLoading = true
+            this.floorid = floorid
+            this.$refs.canvasFun.isShow = false
+            setTimeout(() => {
+                this.clearGraphy()
+                this.scene = new FloorScene()
+                if (this.haveFengMap == 1) {
+                    this.getGraphDetail().then((res) => {
+                        if (res.Content.length == 1) {
+                            const data = res.Content[0]
+                            if (data.MaxY && data.MinX) {
+                                window.fengmapData.maxY = data.MaxY
+                                window.fengmapData.minX = data.MinX
+                            }
+                        }
+                        this.parserData(floorid)
+                    })
+                    // this.parserData(floorid);
+                } else if (this.haveFengMap == 0) {
+                    this.view.scene = this.scene
+                    this.readGraph()
+                } else {
+                    this.canvasLoading = false
+                }
+            }, 100)
+        },
         // 切换楼层
         emitFloor(floorObj) {
           // if (floorObj) {
@@ -51,6 +96,13 @@ export default {
           //   })
           // }
         },
+        clearGraphy() {
+          if (this.view) {
+            this.view.scene = null
+            return
+          }
+          this.view = new FloorView("bind-canvas");
+        },
     },
 }
 </script>

+ 1 - 1
tsconfig.json

@@ -31,7 +31,7 @@
     "src/**/*.tsx",
     "src/**/*.vue",
     "tests/**/*.ts",
-    "tests/**/*.tsx"
+    "tests/**/*.tsx", "src/store/index.js"
   ],
   "exclude": [
     "node_modules"